LLM出力のばらつき:1回のターゲットを絞ったリトライが効果的な場合
同一の入力に対し、LLMの出力の45%が変化しました。ここでは、そのばらつきを、リトライ予算を浪費することなく品質を回復させる1回限りのリトライへと転換する方法を紹介します。
有効な回答をすでに返したLLM呼び出しを再試行するのは、無駄に聞こえます。ほとんどの場合、その通りです。しかし、私たちは本番の翻訳パイプラインで、考えを改めることになるある測定を行いました。同じモデル、同じプロンプト、同じ入力で55件の承認済み出力を再生成したところ、そのうち25件が異なる結果で返ってきたのです。これは、確定したはずの回答に対して45%のばらつき率があるということです。この記事では、そのばらつきがリソースとなる限定的なケース、すなわち、真の品質を回復する1回限りの条件付き再試行と、それを有効にする前に回避する設計が必要な2つの失敗モード(結果の上書きと予算の枯渇)について説明します。
測定:同一入力に対して45%の出力が変化
問題のパイプラインは、多言語の用語集を構築するものです。バッチジェネレーターが2つのLLMに医療美容用語の翻訳を依頼し、コンセンサスステップでそれらを比較し、逆翻訳チェックで意味を検証します。すべてのゲートを通過した出力は、確定済みエントリとして保存されます。
監査中に、55件の確定済み中国語エントリを削除し、まったく同じ生成を再度実行しました。プロンプトの変更、モデルの変更、temperatureの変更はありませんでした。2回目の実行は、最初の実行と30件のエントリしか一致しませんでした。残りの25件は、異なる表層形で返されました。
その違いはランダムなノイズではありませんでした。それらは3つのグループに分かれました。
- 書式設定の揺れ:あらゆる正規化処理において同一と見なされるような、
capitalization、スペース、シノニムレベルの置き換え。 - 実質的な改善:1回目の実行では英語のブランド名がそのまま残されていたデバイスに対し、2回目の実行では確立された現地市場での名称が生成された。
- 実質的な悪化:2回目の実行では、正しい現地名が失われ、英語のブランド名にフォールバックした。
興味深いのは2番目と3番目のグループです。これらは、反対方向を指す同じ現象です。モデルは、ロングテールのブランド用語に対する現地市場での名称を確実には知りません。それを生成することもあればしないこともあり、どちらの側にも有意な確率が存在します。その分布から得られる単一のサンプルは、モデルの最善の回答ではありません。それは単なる1回の抽出(draw)にすぎません。
生成を分布からの抽出(draw)と見なすと、再試行に関する問いの形が変わります。問いはもはや「モデルを信頼すべきか」ではなく、「どの出力に対して2回目の抽出が1回目を上回る可能性が高く、そしてどうすればそれらを低コストで見分けられるか?」となります。
チェック可能なプロパティ違反の場合にのみ再試行する
すべてを再試行すると、ほぼゼロの利益のためにコストが倍増します。30の安定したエントリに対しては、2回目のドローは同じものを返しますし、変動するエントリに対しては、どちらのドローが良かったかを知る方法がありません。やみくもな再試行は、分散をチャーンに変えてしまいます。
回避策は、以下の特性を持つプロパティを見つけることです。
- 別のLLM呼び出しなしで、決定論的にチェック可能であること。
- 「2回目のドローの方が良い可能性が高い」ことと強く相関していること。
- すべての出力でテストするのに十分安価であること。
我々のケースでは、そのプロパティは書記体系の不一致でした。中国語の用語集エントリは、通常は漢字を含むべきです。中国の美容市場では、輸入ブランドのデバイスにさえ現地の名前が付けられるため、中国語のスロットにラテン文字のみの文字列が含まれている場合、それは通常「モデルがこのドローで現地の名前を取得できなかった」ことを意味し、「現地の名前が存在しない」ということではありません。純粋関数でこれをテストできます。コードポイントを反復処理し、漢字とラテン文字の数を数えるだけで、ネットワークは関与しません。
そのため、再試行のゲートは次のようになりました。完全な検証チェーンを通過した後、中国語スロットに対して受け入れられた出力がラテン文字のみの場合、そのスロットを一度だけ再生成します。その際、「確立された現地市場の漢字名があればそれを優先し、ないブランドについては元の名前を維持する」という指示を1つ追加します。
ここでは2つの詳細が重要です。第一に、再試行は元の試行と同じ生成、コンセンサス、検証のパイプラインを再利用します。検証をスキップする再試行は、再試行ではなく、バイパスです。第二に、追加された指示はベースプロンプトを置き換えるのではなく追記されるため、再試行は最初のドローとは正確に1つの点でのみ異なります。差分が何に起因するかを特定できるようにしたいのです。
ライブデータでの結果です。フィラーブランドのスロットで、最初は生の英語のブランド名として返ってきたものが、再試行で正しい漢字の市場名で返ってきました。再試行後もラテン文字のままだったスロットは、確立された現地名が存在しないマイナーなブランドが圧倒的であり、これはまさに残ってほしい母集団です。実行後、新たに埋められた中国語スロットの約11%がラテン文字のみのままであり、それらは黙って通過する代わりにレビューフラグが付けられます。
合格した結果を失敗で上書きしない
あらゆるリトライ設計における最初の失敗モードは、上書きです。元の出力はすべてのゲートを通過しました。リトライは通過しないかもしれません。リトライの結果を無条件に書き込むと、合格したエントリーが拒否に置き換えられ、埋まっていたスロットが空になる可能性があります。それは、リトライしないことよりも厳密に悪い状態です。
最終的に採用した仕様は次のとおりです:
snapshot = copy(result) // everything the pipeline may mutate
reset(result) // back to undecided state
regenerate with reinforced prompt
run consensus + verification // same gates as the original
adopt only if:
verdict == pass
AND output now satisfies the property (contains Han)
AND output does not collide with an existing confirmed entry
otherwise:
restore(snapshot) // the passing original wins
各条件には、それぞれに存在する理由があります。パスチェックは、検証の権限を本来あるべき場所に保持します。プロパティチェックは、再度ラテン文字を返した再試行を拒否します。なぜなら、それを採用すると何も修正されないまま予算を消費してしまうからです。衝突チェックが重要なのは、新しい漢字名が別の概念の確定した翻訳と重複する可能性があるためです。それを採用すると、後でパイプラインの重複ゲートに引っかかり、スロット全体を道連れにしてしまいます。採用前にチェックすることで、衝突した再試行は有効なエントリを破壊するのではなく、静かにオリジナルを復元します。
スナップショットは、出力テキストだけでなく、パイプラインが変更するすべてのフィールドをカバーする必要があります。我々のスナップショットは、判定、逆翻訳、類似度距離を含む7つのフィールドを保持します。1つでも欠けていると、復元されたエントリは2つの実行のキメラになってしまいます。
隠れたコスト:再試行バジェットと永続的な枯渇
2つ目の障害モードはより巧妙で、私たちの最初の実装で危うく出荷されるところでした。バッチパイプラインは通常、スロットごとの試行回数に上限を設けています。私たちのシステムでは3回まで許可しています。3回の判定失敗後、スロットは母集団から永続的に除外されます。これにより、不正な入力が毎晩LLMの費用を消費し続けることを防ぎます。
試行回数カウンターは、監査ログの行から導出されます。私たちの最初の設計では、再試行をそれ自体の行としてログに記録していました。これは、1晩に1回余分な試行として読み取られます。毎晩再試行されるスロットは、2晩で3回の試行上限に達し、補充用の母集団から永久に脱落してしまいます。より多くのスロットを補充するための機能が、静かにそれらを削除していたことになります。
修正策は、再試行をバジェットから見えないようにすることでした。再試行では、独立した監査行を書き込みません。その代わり、最終行の summary フィールドにマーカーを追加し、元の出力を一緒に記録します。その1つのマーカーが2つの役割を果たします。
- バジェットへの中立性:試行回数のカウントでは、以前と同様に1晩に1行しか見えません。
- 1回限りの実行強制:再試行する前に、パイプラインはそのスロットの最新行を読み取ります。マーカーが存在する場合、このスロットは現在の判定サイクルで既に再試行済みであることを意味するため、スキップします。
私たちは、1回限りの実行を永続的ではなく、判定サイクルに限定しました。後にレビュー担当者がそのエントリーを却下し、スロットが母集団に再投入された場合、新たな試行回数と共に新たな再試行の機会を得ます。永続的な1回限りの実行は、何年も前に判定されたスロットが二度と恩恵を受けられないことを意味し、誰のためにもなりません。
このセクションから1つ教訓を得るとすれば、バッチシステムに再試行を追加する前に、試行回数やコスト計算のすべてのコンシューマーを見つけ出し、それぞれにとってあなたの再試行がどのように見えるかを確認することです。再試行は、バジェット、dedupチェック、枯渇述語、モニタリングと相互作用します。あなたが明示的にそうしない限り、それらのコンシューマーは、あなたの追加の呼び出しが「単なる再試行」であったことを知りません。
このパターンが適用される場合と、されない場合
このパターンは、安価で決定的なプロパティチェックを持つあらゆる生成タスクに一般化できます。
- パースが必要な構造化出力 (JSON スキーマ、日付形式): パースの失敗がプロパティです。
- ターゲットのスクリプトである必要がある翻訳: ここでのように、書記体系のチェック。
- コンパイルが必要なコード生成: コンパイラがプロパティチェックです。
- 制約付きリライティング (長さ制限、禁止用語): スキャナがプロパティチェックです。
品質が程度の問題であり、決定的なテストがない場合には適用されません。純粋関数で「違反しているか否か」を判断できない場合、それは LLM-judges-LLM に戻ることになり、これは異なるコストを持つ異なるツールです。また、分散が低い場合にも価値を失います。ロングテールの専門用語では 45% を確認しましたが、よく知られた用語では同じパイプラインがほぼ決定的であり、そこでのリトライは純粋な無駄です。リトライによって何か新しいものが見つかると想定する前に、削除して再生成したサンプルで分散を測定してください。
もう一つの正直な限界: 1 回のリトライは分布を 2 回サンプリングします。私たちのワークロードでは、回復可能なケースのほとんどが回復しました。なぜなら、プロパティチェックが、どのスロットが 2 回目の試行の価値があるかを正確に教えてくれたからです。もし回復可能なセットが 5 回の試行を必要とする場合、経済性が変わり、よりハードにサンプリングするのではなく、プロンプトを修正すべきでしょう。
よくある質問
リトライの際に、temperatureを上げたり、別のモデルを使用したりしないのはなぜですか? 一度に2つの変数を変更すると、結果の原因を特定できなくなります。私たちのリトライでは、既知の失敗を対象とする指示を追加するという、ただ1つのことだけを変更します。これにより、改善が見られた場合にその効果を正しく評価し、維持することができます。また、モデルを交換すると、リトライの出力が元の出力と同じ検証を受けるという保証がなくなります。
プロパティが満たされるまで繰り返すのではなく、なぜ一度しかリトライしないのですか? 「確立された現地の名称は存在しない」というのが正当な最終状態である場合があるためです。マイナーなブランドの場合、ラテン文字の名称が正解であるため、ループさせると無限に処理が続くか、あるいは「一度だけ試して、レビュー用にフラグを立てる」という方法よりも妥当性を考えるのが難しい、別の停止条件が必要になってしまいます。
LLMにおいて45%のばらつきは正常ですか? それは、タスクがモデルの知識の限界にどれだけ近いかに大きく依存します。私たちが使用した、よく知られている用語は実行ごとに安定していましたが、ばらつきはモデルが純粋に確信が持てないロングテールの項目に集中していました。ターゲットを絞ったリトライが機能するのは、まさにこの集中のおかげです。プロパティチェックによって、不確かな箇所が発見されるのです。
これは人によるレビューの代替となるものですか? いいえ。これはレビューキューを縮小するものです。リトライ後も違反状態のままの出力にはフラグが立てられ、そのフラグには元の出力も含まれるため、レビュー担当者は両方の試行結果を確認できます。このパターンは、「すべてをレビューする」ことから、「機械がもう一度試行しても修正できなかったものをレビューする」ことへと、労力を移行させます。