LLMではできない「推論の再現性検証」をCLIで実現した話
はじめに
ChatGPTやClaudeなどのLLMはとても便利ですが、使っていてこんな疑問を持ったことはないでしょうか。
- 同じ入力をしても、結果が微妙に変わる
- なぜその結論になったのか、追いかけることができない
つまり、
「出力を信じることはできても、検証することはできない」
という構造的な問題が、LLMにはあります。
前提:何を検証しているのか
今回検証しているのはLLMそのものではなく、
自分が開発しているソフトウェア設計開発支援の推論モデル(DBM: Design Brain Model)
です。
DBMはざっくり言うと、こんな設計思想で作っています。
- 推論を確率的な生成ではなく、明示的な状態遷移として扱う
- 実行過程を中間表現(IR)として記録・保持する
- 同一条件での**完全再実行(Replay)**を前提に設計されている
LLMが「結果を生成する」モデルだとすれば、
DBMは「推論の過程そのものを構造化する」モデルと言えます。
この設計があることで、はじめて「検証」が成立します。
DBM自体の詳しい話は別記事で改めて書く予定です。
何を作ったのか
一言で言うと、
DBMの推論を保存・再実行して、結果が一致するかを検証するCLI(verification_cli)
です。使い方はシンプルで、こんな感じで実行します。
verification_cli audit --scenario <シナリオ名>
実際に動かしてみた
通常シナリオ:決定性の確認
まず、正常系のシナリオで決定性が保証されていることを確認します。
verification_cli audit --scenario rest-api
verification_cli audit --scenario layered
verification_cli audit --scenario microservice
いずれも同じ結果が返ってきます。
{
"result": "deterministic",
"layer": null,
"cause": null,
"details": {}
}
result: deterministic は、2回の実行結果が完全に一致したことを意味します。
通常の推論シナリオではきちんと再現性が担保されています。
ネガティブシナリオ:非決定性を意図的に起こして検出する
次に、意図的に壊したシナリオを与えて、CLIが不一致を正しく検出できるかを確認します。
シナリオ:外部知識取得の順序ずれ(break-knowledge-order)
verification_cli audit --scenario break-knowledge-order
{
"result": "nondeterministic",
"layer": "knowledge",
"cause": "ExternalNondeterminism",
"details": {
"left": {
"live_results": ["knowledge:web:aaa", "knowledge:web:bbb"],
"knowledge_snapshots": [...]
},
"right": {
"live_results": ["knowledge:web:bbb", "knowledge:web:aaa"],
"knowledge_snapshots": [...]
}
}
}
結果の読み方はこうです。
-
result: nondeterministic→ 2回の実行で結果が一致しなかった -
layer: knowledge→ 不一致は外部知識取得層で起きた -
cause: ExternalNondeterminism→ Web検索など外部依存の結果順序が実行ごとに変わった -
left/right→live_resultsの順序が逆になっており、外部取得結果の非決定性を示している
これはメモリやサーチといった内部層だけでなく、外部依存(Web検索等)も非決定性の発生源になりうることを示しています。
正規化の確認:検出して修正まで
以前のバージョンでは、メモリ取得順序(break-memory-order)や検索同点処理(break-search-tie)が nondeterministic を返していました。
今回はどちらも deterministic になっています。
verification_cli audit --scenario break-memory-order
# → "result": "deterministic"
verification_cli audit --scenario break-search-tie
# → "result": "deterministic"
これは非決定性を検出した後、正規化(canonicalization)によって修正が完了したことを意味します。
「検出できる」だけでなく、「修正して再確認できる」というサイクルが回っています。
テスト全体像
CLIの単体テストも合わせて実行しています。
cargo test -p verification_cli --test cli
→ 7 tests: ok
cargo test -p verification_cli --test determinism_break
→ 11 tests: ok
determinism_breakテストでカバーしている非決定性の種類はこちらです。
-
memory_drift/memory_order/memory_tie:メモリ層の各種パターン -
search_tie:検索同点処理 -
hashmap_order:HashMap順序依存 -
ir_shuffle:中間表現(IR)のシャッフル -
beam_instability:ビーム探索の不安定性 -
patch_order:パッチ適用順序 -
codegen_order:コード生成順序 -
knowledge_order:外部知識取得順序 -
websearch_nondet:Web検索の非決定性
18テストすべてがpassしており、広範な非決定性パターンを網羅しています。
どんな仕組みなのか
内部的には以下の流れで動いています。
1. 推論の完全スナップショット化
実行時の情報をすべて保存します。
- 入力
- 中間表現(IR)
- メモリ状態
- 検索結果・外部知識取得結果
- 実行ステップ
2. 完全再実行(Replay)
保存した状態からWorldStateを再構築し、同一条件で再実行します。
そして2回の結果を突き合わせます。
3. 差分検出(Diff)
一致しなければ、どのレイヤー(layer)で何が原因(cause)なのかを出力します。
4. 根本原因の分類
差分の原因はこんな形で分類されます。
-
RetrievalInstability:メモリ取得順序の不安定 -
SearchOrderingBug:検索同点時の順序未定義 -
ExternalNondeterminism:外部依存(Web検索等)の結果順序のゆらぎ
なぜLLMでは同じことが難しいのか
LLMは確率的な生成モデルなので、内部状態が外から見えません。
実行過程も保持されないため、同じ推論を再実行すること自体ができません。
DBMがこれを実現できているのは、推論を**「状態遷移」として設計しているから**です。
これによって再現性(Determinism)と追跡可能性(Traceability)が保証されます。
まとめ
今回作ったのは、
「DBMの推論に対して、再現性と正当性を検証できる仕組み」
です。そしてこの仕組みによって、
- 非決定性を検出できる
- 原因のレイヤーと分類を特定できる
- 修正後に再検証して確認できる
というサイクルが回るようになっています。
これはある意味、
AIの出力を"信じる"から"検証する"へのシフト
とも言えるかもしれません。
次回
DBM(Design Brain Model)そのものの設計と思想について整理します。
おわりに
verification_cliをひと言で表すなら、
「推論をもう一度動かして、どこで・なぜズレたかを教えてくれるツール」
です。
そしてそれが成り立っているのは、再実行可能な設計を持つDBMがあってこそです。
興味を持っていただけたら、次の記事もぜひ読んでみてください。