モデルの合意(コンセンサス)を用いてLLMの数値判断を安全にする方法
単一のモデルは、一見正しく見えるが間違っている数値を生成することがあります。信頼する前に、2つの独立したモデルを相互にチェックし、コードで結果を再計算してください。
段落を要約する言語モデルは、多少間違っていても役に立つ場合があります。しきい値を計算したり、金額を検証したり、2つの数値が一致するかをチェックしたりするモデルには、その猶予はありません。数値は正しいかそうでないかのどちらかであり、もっともらしい間違った数値はレビューを通過してしまうため、明らかに間違った数値よりも悪質です。この投稿では、モデルの数値出力を真実の源としてではなく、チェックすべき主張として扱うパターンについて説明します。すなわち、同じ判断を2つの独立したモデルで実行し、それらが完全に一致した場合にのみ数値を受け入れ、それが重要な何かに到達する前にプレーンなコードで結果を再計算するというものです。
言語は寛容だが、数字はそうではない
LLMが得意とすることのほとんどは、寛容な空間に存在します。要約でニュアンスが抜け落ちたり、リライトで少し奇妙な単語が選ばれたりしても、読者は意味を理解でき、下流のプロセスで何も壊れることはありません。自然言語には冗長性が組み込まれているため、小さなエラーは洗い流されます。
数値的な判断には、そのような余裕は一切ありません。モデルが1,050,000の送金が1,000,000の制限内であると判断したり、割引価格がある値に丸められるべきところを別の値に丸めたりした場合、部分点はありません。出力はゲート、台帳、または制御フローの分岐に入力され、1つの間違った桁が結果を完全に変えてしまいます。
これを危険なものにする失敗モードは、具体的で再現性があります。
- 幻覚による自信。モデルは、数値を正しく導き出したか、捏造したかにかかわらず、同じ流暢な確信をもって述べます。その口調からは、どちらが起こったのかを知ることはできません。
- 桁と大きさの誤差。モデルは、ゼロを1つ脱落させたり、2つの数字を入れ替えたり、答えの桁を1つ間違えたりすることがありますが、その周りの文章は完璧に読めます。
- 単位と通貨の混同。パーセンテージを分数として、分を秒として読み取ったり、ある通貨を別の通貨として扱ったりします。計算は内部的に一貫していても、単位が間違っているため、結果はやはり間違いです。
- 境界値の誤り。しきい値でのoff-by-oneエラーや、上限値を含むべきところを含まないものとして扱うことで、拒否されるべき値がすり抜けてしまいます。
これらはまさに、流暢な単一の回答が最も隠しやすい種類のエラーです。文章の構成は正しく、論理も正しそうに聞こえますが、数字が間違っているのです。
モデルの出力を答えではなく、主張として扱う
核となる転換は、モデルに答えを求めるのをやめ、後で検証する主張を求めるようにすることです。4つのルールが、確率的なジェネレーターを安全なゲートに変えます。
- 2つの独立したモデルをクロスチェックし、それらが一致した場合にのみ受け入れる。
- 決定論的なコードでその数値を再計算し、不一致があれば拒否する。
- 答えを正確に比較できるように、構造化された出力を強制する。
- ツールも外部の状態も使わせず、モデルの役割を純粋な判断のみに限定する。
これらのどれも、モデル単体を信頼するものではありません。それぞれが出力が間違っている可能性を想定し、その想定に基づいてチェックを構築します。この記事の残りの部分では、これらを1つずつ取り上げます。
コンセンサスゲート:合意または停止
最初のルールは、投票ではなく、全員一致のゲートです。同一の判定を、コンテキストを共有しない2つの独立したモデルに送り、その回答を比較します。両方が同じ数値と同じ単位を生成した場合、それを暫定的な承認として扱います。少しでも不一致があれば、処理を停止し、人間またはフォールバックパスのためにそのケースを保留します。
全員一致という言葉が重要です。これは、最も一般的な回答が勝つ多数決ではありません。数値の安全性においては、不一致こそがプロセス全体で最も価値のある出力です。これは、少なくとも1つのモデルがここで間違っていることを意味し、どちらが間違っているかはまだ判断できません。多数派を支持してその不一致を解決することは、コストをかけて得た正確なシグナルを捨てることになります。ゲートはフェイルクローズすべきです。つまり、疑わしい場合は、その数値を通過させてはなりません。
独立性こそが、このゲートに力を与えるものです。同じファミリーの2つのモデルや、同じモデルに2回クエリを実行した場合、同じ場所で同じ間違いを犯す傾向があるため、それらの間での合意はほとんど何も証明しません。異なるデータでトレーニングされた、真に異なる2つのモデルは、異なる死角を持っています。そのため、両方が偶然に同一の間違った数値を生成する可能性ははるかに低くなります。これは投票を数えているのではなく、2つの別々の推定器が同じ点に着地するかどうかを確認しているのです。
def consensus_gate(task, model_a, model_b):
a = model_a.judge(task) # structured: {"value": ..., "unit": ...}
b = model_b.judge(task) # same task, no shared context
if a is None or b is None:
return HOLD # a model failed to answer, fail closed
if a.value != b.value or a.unit != b.unit:
return HOLD # disagreement is a risk signal, escalate
return Accept(a.value, a.unit) # both agree, provisional accept
ここでの合意はあくまで仮の承認であり、最終的なものではないことに注意してください。2つのモデルが共通の死角を持ち、一緒に間違う可能性があります。ゲートはその確率を下げますが、なくすわけではありません。これが、次のルールが存在する理由です。
決定論的なコードで数値を再計算する
コンセンサスはほとんどの単一モデルのエラーを除去しますが、それでもモデルが生成した数値を信頼することになります。2番目のルールはその信頼を取り除きます。答えが通常の計算で導出できる場合は常にそれを導出し、真に判断が必要な部分にのみモデルを使用します。
これについて考えるのに役立つ方法は分業です。モデルは問題の曖昧な部分、つまり乱雑な入力の読み取り、関連する行の決定、曖昧なフィールドの分類が得意です。合計が正確であることを保証するのは苦手です。したがって、モデルに読み取りと選択を行わせ、次に自分で算術計算を行い、モデルの主張を自分の結果と照合します。
決定論的なレイヤーは3種類のチェックを実施すべきです。値を正確な型にパースし、金額には決してfloat型を使用しません。既知の境界に対して範囲チェックを行います。そして、どのモデルが何を言ったかに関係なく成立しなければならない不変条件(例えば、部分の合計が全体になるなど)をアサートします。
from decimal import Decimal
def verify(value, unit, source_rows):
# 1. parse into an exact type, never a float for money
amount = Decimal(value)
# 2. range check against known bounds
if not (MIN_AMOUNT <= amount <= MAX_AMOUNT):
raise Reject("value is outside the allowed range")
# 3. invariant: the parts must sum to the whole
computed = sum(Decimal(r.amount) for r in source_rows)
if amount != computed:
raise Reject(f"sum mismatch: model said {amount}, code computed {computed}")
# 4. unit must match what the pipeline expects
if unit != EXPECTED_UNIT:
raise Reject(f"unexpected unit {unit}")
return amount
不一致の場合の分岐が重要です。再計算された合計がモデルの数値と一致しない場合、コードはそれらを平均化したり、どちらか一方を優先したりはせず、拒否します。不一致は、モデルが間違っているか、モデルが読み取った入力がコードが読み取った入力と異なるかのいずれかを意味し、どちらの場合も、何らかの数値を提出する前に人間の介入が必要です。これは、両方のモデルが偶然に共有してしまった桁違いのエラーを検出する層です。
数値を比較できるように構造化出力を強制する
モデルが文章の中に数値を埋め込んでしまうと、2つの回答を比較したり、一方を再計算したりすることはできません。3番目のルールは、固定スキーマを持つ構造化出力を要求し、値を保持するフィールドで自由な散文を禁止することです。
スキーマは一度に3つのことを行います。コンセンサスゲートでの比較を、脆弱な英語の解析ではなく、型付けされたフィールドでの完全一致にします。解釈が必要なフレーズの代わりに、決定論的レイヤーにチェックするためのクリーンな値を与えます。そして、モデルが創造性を発揮できる表面を狭めますが、これはまさに数値のドリフトが忍び込む場所です。
このような形式の出力を要求し、適合しないものはすべて拒否してください:
{
"value": "1050000",
"unit": "KRW",
"basis": "sum_of_line_items",
"confidence": "high"
}
転送中は数値を文字列として保持し、到着時にそれを正確な10進数型にパースして、モデルとチェックの間に浮動小数点数の丸め誤差が紛れ込まないようにしてください。フィールドが欠落している、コメントが追加されている、または数値が説明で囲まれているレスポンスは、不一致の場合と同様に、失敗したレスポンスとして扱ってください。要求された形式で応答しないモデルは、応答しなかったことになります。
モデルをツールと状態から隔離する
最後のルールは、モデルが何にアクセスすることを許可されるかに関するものです。数値的な判断のためには、入力と質問以外は何も与えません。ツールも、他のシステムを呼び出す機能も、他のレビュー担当者との共有メモリも、何ものへの書き込みアクセス権もありません。
隔離は2つの利点をもたらします。それにより、2つのモデルは真に独立した状態に保たれます。どちらも他方の推論を見たり、共有された中間結果にアンカーしたりすることができないため、両者の合意が意味のあるものになるのです。そして、影響範囲をゼロに保ちます。構造化された主張を返すことしかできないモデルは、間違った数値に基づいて行動することはできず、提案することしかできません。そして、何かが起こる前に、すべての提案はゲートと再チェックを通過します。モデルはセンサーであり、アクチュエーターではありません。それは測定値を報告し、コードがそれを使って何をするかを決定します。
単一モデル対コンセンサスゲート
このパターンは構成要素が増えるため、単一の呼び出しと比較して、それらの構成要素にどのような利点があるかをはっきりと確認することが役立ちます。
| 観点 | 単一モデル | 2モデルのコンセンサスゲート |
|---|---|---|
| 検知されない誤った数値 | 下流工程に渡されます | 両方が一致して再チェックに合格しない限り、ブロックされる |
| 確信度の高いハルシネーション | しばしば受け入れられる | 両方が全く同じエラーを共有しない限り、捕捉される |
| 判断あたりのコスト | 1回のモデル呼び出し | 2回以上のモデル呼び出し |
| レイテンシー | 1モデル分 | 2つのうち、より遅い方 |
| 不一致の場合 | 検知されない | 人間による確認のためにフラグが立てられ、保留される |
| 最適な用途 | 可逆的で、重要度の低いテキスト | 金銭、しきい値、照合 |
単一モデルのアプローチは、すべてのジョブにとって誤りというわけではありません。もっともらしい誤った数値が実害をもたらすようなジョブにとっては、誤りとなります。
コストと、それを省略すべき場合
ゲートは無料ではありません。1回の判断につき1回ではなく2回以上のモデル呼び出しの料金を支払い、それらは並列で実行されるものの最後に完了したものがペースを決めるため、最も遅いものを待つことになります。エンジニアリングコストもかかります。維持すべきスキーマ、作成すべき決定論的チェッカー、そして人間やフォールバックが処理しなければならない不一致のための保留パスです。大量かつ低価値な判断のストリームに対しては、そのオーバーヘッドが利益を上回る可能性があります。
ですから、リスクの大きさに合わせてパターンを適用しましょう。間違った数値がもたらす代償が大きく、後戻りが困難な場合、完全なゲートはそのコストに見合う価値を発揮します。
- 金銭に関わるパス。金額、限度額、返金など、価値を移動させたり、取引をゲートしたりするあらゆるもの。
- 閾値と制御。何かが許可されるかどうかを決定する、計算されたカットオフ値。
- 照合。2つの独立した数値が一致することを確認すること。誤った合格が実際の不一致を隠してしまうような場合。
- 一方通行の出力。台帳に書き込まれたり、パートナーに送信されたりして、後から密かに修正することができない数値。
逆のケースでは、それをスキップしてください。人間がざっと目を通すための大まかな見積もりを提案するモデル、レポートの要約、いずれにせよ人が編集する下書き、これらのいずれも2つのモデルと10進数チェッカーを必要としません。使い捨ての見積もりに対して完全なゲートを実行することは、レイテンシと費用の無駄です。
紛れもない限界は、共通の死角です。コンセンサスは間違った数値になる可能性を低減させますが、それをゼロにすることはありません。なぜなら、2つのモデルが同じ欠陥のあるパターンで訓練され、それを一緒に繰り返す可能性があるからです。それが、決定論的な再チェックがゲートの背後に置かれ、人間が不一致パスに留まる理由です。モデルは候補を生成することには長けていますが、それが正確であることを保証することには弱いです。コンセンサス、決定論的な再計算、そしてフェイルクローズドな処理は、その弱い保証を、正確でなければならない数値の前に置くことができるゲートへと変えるのです。