LLMが「指示を守らない」本質的な理由と、業務システムで実用に耐える設計指針
出典: takunisf

業務システムでLLMに明確なルールを与えても「しかし、より詳細に検討すると」と答えを覆してしまう問題。これはプロンプトの問題ではなく、LLMの確率的性質とRLHF学習による「親切さの最大化」が原因だった。本記事では、この現象の構造的理解と、実務で使える対処法を解説する。
LLMが正解を出した直後に答えを覆す謎
業務システムにLLMを組み込む際、多くの開発者が直面する深刻な問題がある。それは「明確なルールを与えているのに、LLMが自分で導いた正解を覆してしまう」という現象だ。
特に厄介なのは、LLMが思考過程(thinking)では正しくルールを適用し、正解を導き出しているにもかかわらず、最終回答で「しかし、より詳細に検討すると...」と自己否定を始めるケースである。プロンプトエンジニアリングで解決できると思いがちだが、実はこれは表面的な対処では根本解決できない構造的な問題なのだ。
問題の本質:確率的生成とRLHFの相克
なぜLLMは「考え直して」しまうのか
この問題の核心は、LLMの2つの本質的特性にある:
1. **確率的テキスト生成**: LLMは次のトークンを確率分布から選択する。正解を出した後も、生成は続く。その時点で「しかし」「ただし」といった転換表現が高確率トークンとして出現しやすい
2. **RLHF(人間フィードバックによる強化学習)の影響**: 現代のLLMは「親切で丁寧な回答」を高評価されるよう訓練されている。そのため「多角的な視点を示す」「慎重に検討する姿勢を見せる」行動パターンが強化されている
つまり、ルールベースのタスクで求められる「決定的な判断」と、RLHFで学習した「慎重で多面的な思考」が根本的に衝突しているのだ。
プロンプト修正だけでは限界がある理由
「絶対に覆すな」と強調しても効果が薄いのは、これが単なる指示の伝達ミスではないからだ。LLMのアーキテクチャレベルでの挙動であり、プロンプトは生成確率を調整するだけで、生成プロセス自体を変更できない。
編集部の視点
従来のルールエンジンとの比較で見える本質
従来の業務システムでは、ルールベースの分類は決定木やエキスパートシステムで実装されてきた。これらは入力に対して**決定論的**に出力を返す。同じ入力なら必ず同じ出力だ。
一方、LLMは本質的に**確率論的**である。temperature=0でも、モデル更新やサンプリング手法の違いで結果が変わりうる。この根本的な性質の違いを理解せずにLLMを導入すると、「なぜ不安定なのか」という問いに答えられない。
ChatGPTとClaude、どちらが「指示に従順」か
実務経験から言えば、この問題の発生頻度はモデルによって異なる。Claudeシリーズは「慎重な検討」を示す傾向が強く、特にClaude 3以降は多段階推論を好む。対してGPT-4系は比較的簡潔な回答を出しやすい。ただし、これはRLHFのチューニング方針の違いであり、どちらが優れているという話ではない。
重要なのは、**使用するモデルの「癖」を理解した上で、システム設計を行う**ことだ。
メリットと注意点の両面分析
**LLMをルールベースタスクに使うメリット:**
**構造的な注意点:**
適用範囲の考察:どこでLLMを使うべきか
LLMが真価を発揮するのは:
逆に、LLMを避けるべきは:
実務で使える対処法
元投稿では触れられていないが、この問題への実践的アプローチを3つ紹介する。
1. 構造化出力の強制(Function Calling / JSON Mode)
最も効果的なのは、LLMに自由形式テキストを生成させないことだ。
# OpenAI Function Calling の例
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
functions=[{
"name": "classify",
"parameters": {
"type": "object",
"properties": {
"category": {"type": "string", "enum": ["A", "B", "C"]},
"reasoning": {"type": "string"}
},
"required": ["category"]
}
}],
function_call={"name": "classify"}
)これにより、LLMは決められたスキーマのJSONのみを出力する。「しかし」と続ける余地がない。
2. 二段階検証パターン
LLMの出力を別のLLM(または軽量なルールエンジン)で検証する。
[第1段階] LLMが分類実行 → 結果Aを出力
[第2段階] 別インスタンスが「結果Aはルールに合致するか?」を検証コストは2倍になるが、自己矛盾を検出できる。本番適用前のテストフェーズで有効だ。
3. Few-shot Examplesで「即断する」パターンを学習させる
プロンプトに「正解を出したら即座に終了する」例を複数含める。
例1:
入力: [データ]
思考: ルール2に該当。
回答: B
例2:
入力: [データ]
思考: ルール1の条件を満たす。
回答: A
# あなたのタスク
入力: [実際のデータ]RLHFの「丁寧さ」バイアスを、Few-shotの「簡潔さ」パターンで上書きする手法だ。
今日から試せるアクション
アクション1: 現在のプロンプトを「構造化出力」に変換する
既存のプロンプトをJSON Modeやfunction callingに書き換えてみよう。OpenAI、Anthropic、Google Geminiいずれも対応している。変換手順:
1. 期待する出力フォーマットをJSONスキーマで定義
2. プロンプトから「〜として出力してください」という指示を削除
3. APIパラメータでスキーマを指定
アクション2: 出力の「揺れ」を定量測定する
同じ入力を10回実行し、出力の一致率を測定する簡単なスクリプトを書こう:
results = [call_llm(same_input) for _ in range(10)]
unique_outputs = len(set(results))
consistency_rate = (10 - unique_outputs + 1) / 10
print(f"一貫性: {consistency_rate * 100}%")これで「どの程度不安定か」が可視化される。80%以下なら構造化出力への移行を検討すべきだ。
アクション3: ルールの「LLM適性」を評価する
すべてのルールをLLMで処理する必要はない。各ルールについて:
このトリアージだけで、システムの安定性とコストが大きく改善する。
まとめ:LLMの「性格」を理解した設計を
LLMが指示を守らない問題は、プロンプトの巧拙ではなく、LLMの確率的性質とRLHF学習の結果として必然的に起こる。これを「不具合」と捉えるのではなく、LLMという道具の性質として受け入れ、適切な設計パターンで対処することが、業務システムへの実装成功の鍵となる。
構造化出力、二段階検証、適用範囲の見極め—これらの実践的手法を組み合わせることで、LLMの柔軟性を活かしながら、業務に求められる安定性を確保できる。
この情報は @takunisf さんの投稿を参考にしています。
出典: takunisf


