9.2.3 チェーン推論戦略
前の節を一言でまとめると、次のようになります。
- 推論問題は中間状態に依存する
では、この節で答えるべきことは何でしょうか。
どうすればモデルに、中間状態をもっと積極的に、もっと安定して、明示的に書かせられるのでしょうか?
チェーン推論戦略、つまり CoT のいちばん大きな考え方は次の通りです。
- いきなり答えを求めない
- まずモデルに手順を分解させてから、結論を出させる
学習目標
- チェーン推論戦略がなぜ複数ステップのタスク性能を高めるのかを理解する
- CoT がどんなタスクに向き、どんなタスクに向かないかを理解する
- 実行できるサンプルを通して、「直接答える」と「段階的に答える」の違いを理解する
- 本番環境で、無制限な長文ではなく構造化された推論をどう使うかを理解する
なぜ「先に手順を考える」と役立つのか?
なぜなら、多くの問題は一気にゴールへ飛べないから
たとえば、この問題です。
- 商品の元値は 80 元で、2 割引のあとにさらに 5 元引きます。最後はいくらですか?
モデルがそのまま答えを生成すると、
とても典型的なミスをしやすくなります。
- 「8 折」を 8 元引きと勘違いする
- 最後の 5 元引きを忘れる
- 手順の順番を間違える
一方、先に流れを分けると、次のようになります。
80 * 0.8 = 6464 - 5 = 59
最終的な答えは、たいていより安定します。
CoT の核心は「たくさん書くこと」ではなく、「中間構造を見えるようにすること」
これはとても重要です。
チェーン推論で本当に役立つのは、次のようなことではありません。
- 出力を長くすること
本当に重要なのは、次の内容を明示することです。
- 局所的な事実
- 中間変数
- 手順の依存関係
たとえ話:下書きは、真面目さを見せるためではない
学生が問題を解くときに下書きをするのは、答えを長く見せるためではありません。
むしろ、次のためです。
- 頭の中の状態が抜け落ちるのを防ぐ
- 複雑な問題を小さく分ける
- 後で見直しやすくする
CoT がモデルに対して果たす役割は、これにとてもよく似ています。
まず「直接答える」方法と「チェーン推論」の比較を見てみよう
次の例では LLM は呼び出しません。
でも、次のことをとてもはっきり示せます。
- なぜ「雑に直接対応させる」だけだとミスしやすいのか
- なぜ「先に手順を分けてから計算する」と安定しやすいのか
import re
problem = "商品の定価は80円です。20%引きのあとさらに5円引きなら、最終価格はいくらですか?"
def bad_direct_answer(text):
numbers = list(map(int, re.findall(r"\d+", text)))
original, discount, minus = numbers
# よくあるミス:「20%引き」を「20円引き」と誤解する
return original - discount - minus
def chain_reason_answer(text):
original, discount, minus = map(int, re.findall(r"\d+", text))
steps = []
discounted_price = original * (1 - discount / 100)
steps.append(f"まず割引後の価格を計算する:{original} * (1 - {discount}/100) = {discounted_price}")
final_price = discounted_price - minus
steps.append(f"次に追加の {minus} 円を引く:{discounted_price} - {minus} = {final_price}")
return final_price, steps
print("problem:", problem)
print("bad direct answer:", bad_direct_answer(problem))
answer, steps = chain_reason_answer(problem)
print("\nchain reasoning steps:")
for step in steps:
print("-", step)
print("final answer:", answer)
期待される出力:
problem: 商品の定価は80円です。20%引きのあとさらに5円引きなら、最終価格はいくらですか?
bad direct answer: 55
chain reasoning steps:
- まず割引後の価格を計算する:80 * (1 - 20/100) = 64.0
- 次に追加の 5 円を引く:64.0 - 5 = 59.0
final answer: 59.0
このコードがいちばんよく示していることは?
次のことです。
- 直接対応させるだけだと、問題文の意味を誤解しやすい
- 手順を明示的に分けると、ミスが見えやすくなる
たとえばここでは、
- 「8 折」は
-8なのか、それとも*0.8なのか
この1点をきちんと書くだけで、
間違いは隠れにくくなります。
なぜ CoT は数学、論理、計画系タスクで特に有効なことが多いのか?
これらのタスクには、たいてい次の特徴があります。
- 中間変数がはっきりしている
- 手順の順序がはっきりしている
- 局所的な依存関係がはっきりしている
これはチェーン推論と自然に合っています。
なぜ CoT は、すべてのタスクで使うべきとは限らないのか?
すべての問題に段階分けが必要なわけではないからです。
たとえば、
- 「フランスの首都はどこですか?」
このような問題は、どちらかというと検索に近く、長い推論は必要ありません。
つまり CoT は、常に多ければよいわけではありません。
むしろ、
- 複数ステップの問題でこそ価値が高い
のです。
Agent では CoT を通常どう使うのか?
まず分解してから、ツールを呼ぶ
多くの Agent タスクでは、CoT は必ずしもそのまま計算に使うわけではありません。
代わりに、次の判断に使われます。
- まず何をするか
- 次に何をするか
- どのステップでツールが必要か
たとえば、次のような流れです。
- 問題の種類を識別する
- 先にポリシーを調べるか、在庫を調べるかを決める
- 取得した観測結果をもとに結論をまとめる
より構造化された「推論スロット」にすることもできる
本番環境では、モデルに大きな自然言語の思考過程を出力させる必要は必ずしもありません。
多くのシステムでは、代わりに次のような短くて構造化された形式にします。
factssubtasksdecisionnext_action
このような構造は、たいてい次の点で扱いやすくなります。
- 検証しやすい
- 記録しやすい
- デバッグしやすい
CoT は自己チェックと組み合わせることも多い
とてもよくある強化方法は、次の流れです。
- まず推論する
- 次に重要な手順をチェックする
- 最後に答えを出す
こうすると、うっかりミスを一部減らせます。

この図が強調しているのは、「構造化された中間状態」です。モデルに無限に長い思考文を書かせることではありません。本番環境では、推論を facts、subtasks、decision、next_action のような検証可能なスロットに圧縮するほうが一般的です。
どんなときに CoT が最も役立つのか?
手順分解が必要な問題
たとえば、次のようなものです。
- 複数ステップの計算
- 条件による選別
- 組み合わせた意思決定
- 複雑なルール判定
途中の理由を説明したい問題
たとえば、次のようなものです。
- なぜこの案をおすすめするのか
- なぜこの依頼は実行できないのか
- なぜこの答えがルールに合っているのか
システムが結論だけでなく理由も示す必要があるとき、
明示的な中間過程はとても価値があります。
間違いのコストが高い問題
もし、1回でも計算ミスや判断ミスをすると、
影響が大きいなら、
明示的な手順を入れる価値は高くなります。
どんなときに CoT はかえって足を引っ張るのか?
簡単な検索問題
問題自体が段階分けを必要としないなら、
無理に長い過程を出させても、たいてい次のようになるだけです。
- 遅くなる
- 長くなる
- コストが上がる
推論チェーンが長すぎると、自分で自分を迷わせることがある
チェーンが長くなると、モデルは次のような状態になりえます。
- 先頭の手順は正しいのに、後半でずれる
- 同じ説明を繰り返す
- 中間状態の前後が一致しなくなる
つまり、CoT は無限に長くすればよいわけではありません。
外部公開のときは、そのまま見せるのが適切でない場合がある
多くの製品では、次のやり方のほうが適切です。
- 内部では推論構造を持つ
- ユーザーには要点だけを見せる
なぜなら、ユーザーが本当に必要なのはたいてい次のものだからです。
- わかりやすい結論
- 必要最小限の理由
長い下書きそのものではありません。
より実用的な構造化 CoT の書き方
次の例は、Agent により向いた書き方を示しています。
- 大きな自由文を出力しない
- 固定されたスロットに分ける
ticket = {
"question": "注文は未発送です。定価80円の商品が20%引きになり、さらに5円引きされた場合、返金額はいくらですか?",
"policy": "未発送の注文は、元の支払い方法へ返金できます。",
}
def structured_reasoning(ticket):
facts = [
"注文は未発送なので、元の支払い方法で返金できる",
"商品の定価は 80 円で、20%引きのあとさらに 5 円引き",
]
calculation = ["80 * 0.8 = 64", "64 - 5 = 59"]
decision = "返金額は 59 円で、元の支払い方法にそのまま返金する。"
return {
"facts": facts,
"calculation": calculation,
"decision": decision,
}
result = structured_reasoning(ticket)
print(result)
期待される出力:
{'facts': ['注文は未発送なので、元の支払い方法で返金できる', '商品の定価は 80 円で、20%引きのあとさらに 5 円引き'], 'calculation': ['80 * 0.8 = 64', '64 - 5 = 59'], 'decision': '返金額は 59 円で、元の支払い方法にそのまま返金する。'}
この形式の利点は次の通りです。
- 読みやすい
- テストしやすい
- 後処理しやすい
よくある誤解
誤解その1:CoT は、モデルを少しおしゃべりにすること
違います。
核心は、
- 中間構造を明示すること
です。
誤解その2:すべてのタスクでデフォルト CoT にすべき
違います。
有効かどうかは、その問題が本当に複数ステップかどうかで決まります。
誤解その3:CoT があれば、答えは必ず正確になる
これも違います。
チェーン推論は安定性を高めますが、
すべての誤りを自動で消してくれるわけではありません。
まとめ
この節でいちばん大事なのは、Chain-of-Thought という英語名を覚えることではありません。
むしろ、実用的な判断基準を身につけることです。
問題が複数ステップの中間状態に依存するなら、モデルにまず手順を明示的に分解させると、安定性が上がることが多い。ただし CoT の価値は構造化された中間過程にあり、出力を無限に長くすることではない。
この理解ができていれば、
この先に出てくる次の内容も理解しやすくなります。
- ReAct
- Plan-and-Execute
- 自己チェックと評価
これらはすべて、CoT の上にさらに組織化を重ねたものだとわかるはずです。
練習
- 例の割引問題を、自分の多段階の問題に置き換えて、
bad_direct_answerとchain_reason_answerを比べてみましょう。 - なぜ CoT の核心は「出力を長くすること」ではなく「中間構造を明示すること」だと言えるのでしょうか?
- CoT に向かない簡単な問題を 1 つ考えて、理由を説明してみましょう。
- CoT を製品に使うなら、自由文と構造化スロットのどちらを選びますか? その理由は何ですか?