「Extended Thinking を有効にしているのに、応答が普段と何も変わらない」という相談を、最近よくいただきます。私自身、SDKを書きながら同じ落とし穴に何度も落ちてきましたが、原因は大きく分けて7つに整理できることが分かってきました。表示の問題なのか、設定の問題なのか、実装の問題なのかを切り分けるための診断手順をまとめます。
ややこしいのは、Extended Thinking は「ONにしただけでは不十分」なケースが意外と多く、しかも「動いているように見えて実は動いていない」という状態に陥りやすいことです。ここではAPI レスポンスを見て「本当に thinking が走っているか」を確認するところから始めます。
まず確認すべき: thinking が「走っていることをどう判断するか」
Extended Thinking が動作している時、Claude API は応答の content 配列に type: "thinking" のブロックを含めて返します。もしこのブロックが無ければ、何かしらの理由で thinking が無効化されています。
import anthropic
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
thinking={"type": "enabled", "budget_tokens": 4096},
messages=[{"role": "user", "content": "1から100までの素数の総和は?"}]
)
# 確認1: thinking ブロックが存在するか
thinking_blocks = [b for b in response.content if b.type == "thinking"]
text_blocks = [b for b in response.content if b.type == "text"]
print(f"thinking blocks: {len(thinking_blocks)}")
print(f"text blocks: {len(text_blocks)}")
print(f"thinking length: {sum(len(b.thinking) for b in thinking_blocks)} chars")
# 確認2: usage に thinking_tokens があるか
print(f"thinking tokens used: {response.usage.thinking_tokens if hasattr(response.usage, 'thinking_tokens') else 'N/A'}")thinking_blocks が空、または thinking_tokens が0なら、以降の7つの原因のいずれかに該当します。
原因1: モデルが Extended Thinking 非対応
最初に確認すべきは「使っているモデルが Extended Thinking をサポートしているか」です。Extended Thinking が利用可能なモデルは限定されており、claude-haiku-3-5 などは未対応です。2026年4月時点の対応モデルは以下の通りで、私は API リクエスト前にモデル名を厳格にチェックする習慣をつけています。
| モデル | Extended Thinking対応 | 推奨 budget_tokens |
|---|---|---|
| claude-opus-4-6 | ◯(強く推奨) | 4096〜32000 |
| claude-sonnet-4-6 | ◯ | 2048〜16000 |
| claude-haiku-4-5 | ◯(軽量タスク向け) | 1024〜8192 |
| claude-haiku-3-5 | × | — |
未対応モデルに thinking パラメータを送ると、API は エラーを返さず黙って無視 します。これが「効いていないように見える」最大の原因の一つです。
原因2: budget_tokens が小さすぎる
budget_tokens は thinking に使えるトークンの上限ですが、これが小さすぎると Claude は「thinking を始めるけれど、すぐ打ち切る」挙動になり、ほぼ何も考えていない状態の応答が返ります。私の経験則では、1024 トークン未満ではほぼ意味がありません。最低 2048、複雑な推論を期待するなら 4096 以上を推奨します。
特に注意したいのは max_tokens との関係です。max_tokens は thinking + text の合計上限 なので、max_tokens=4096, budget_tokens=4096 のような設定では、thinking が予算を使い切って text が0トークンになる事故が起きます。原則として max_tokens >= budget_tokens + 期待する応答の長さ で組んでください。
原因3: Claude.ai(Webチャット)と API の仕様差
Claude.ai のチャットUIで「Extended Thinking」をONにしている場合、内部でどのモデル・どの budget で動いているかは公開されていません。Pro / Max プランでは比較的長く考えますが、Free プランや Pro プランの後半では budget が縮小される時間帯があるようです。
「APIで動かすと考えるのに、チャットだと考えない」という現象に遭遇したら、まずはチャット側の Pro プランに切り替えて再現するか、API で同じプロンプトを試して挙動が一致するか確認するのが診断の基本です。私はチャットで詰まった時、必ず API でも同じプロンプトを流して比較するようにしています。
原因4: ストリーミング受信時の thinking ブロック取りこぼし
stream=True で応答を受け取る場合、SDK のイベント処理で thinking ブロックを正しくハンドリングしていないと、画面には表示されないけれど API レスポンスには含まれている、という状態が起きます。
# よくある間違い: text ブロックだけ拾っている
with client.messages.stream(
model="claude-opus-4-6",
max_tokens=8192,
thinking={"type": "enabled", "budget_tokens": 4096},
messages=[{"role": "user", "content": "..."}]
) as stream:
for text in stream.text_stream: # ← thinking が来ない
print(text, end="")
# 正しい実装: イベント単位で処理
with client.messages.stream(...) as stream:
for event in stream:
if event.type == "content_block_start":
if event.content_block.type == "thinking":
print("\n[Thinking starts]")
elif event.content_block.type == "text":
print("\n[Answer starts]")
elif event.type == "content_block_delta":
if event.delta.type == "thinking_delta":
print(event.delta.thinking, end="")
elif event.delta.type == "text_delta":
print(event.delta.text, end="")text_stream は便利な反面、thinking を捨ててしまうので、Extended Thinking を活かしたい場合は明示的にイベントを処理する必要があります。
原因5: Tool Use との組み合わせで interleaved thinking が無効
ツール呼び出しと thinking を併用する時、標準では「最初の応答ブロックでのみ thinking が起きる」 仕様です。複数ツール呼び出しの間で繰り返し考えてほしい場合は、interleaved-thinking-2025-05-14 ベータヘッダを有効化する必要があります。
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=16000,
thinking={"type": "enabled", "budget_tokens": 8000},
extra_headers={"anthropic-beta": "interleaved-thinking-2025-05-14"},
tools=[your_tools],
messages=[...]
)これを設定していないと、「最初のツール呼び出しでは thinking するが、その結果を受けてからは普通の応答に戻る」という挙動になり、複雑なエージェントワークフローで本来期待した推論深度が出ません。私は Agent 系のシステムを組む時、これを忘れて1日溶かした経験があります。
原因6: prompt caching との競合
Prompt Caching を使っている場合、キャッシュヒットした部分には thinking が走りません。これは仕様で、キャッシュ済みコンテキストに対しては既に推論済みとみなされるためです。
「キャッシュヒット率が上がってから急に thinking が浅くなった気がする」と感じた時は、response.usage.cache_read_input_tokens を確認してください。キャッシュ済み部分が支配的な場合、thinking は新規入力部分のみに対して行われます。これを避けたい場合は、思考が必要な部分はキャッシュ対象外にする設計にする必要があります。
原因7: ベータ機能のリージョン制限
AWS Bedrock や GCP Vertex AI 経由で Claude を呼んでいる場合、Extended Thinking のベータ機能サポートはリージョンによって展開時期が異なります。「Anthropic直APIでは動くが Bedrock経由では動かない」という相談を何度か見ましたが、たいていはリージョンとモデルバージョンの組み合わせ問題です。
切り分けるには、Anthropic直APIで同じモデル・同じパラメータで動くかを確認するのが最も速いです。直接APIで動いてBedrock経由で動かないなら、Bedrock側のモデル更新を待つか、対応リージョンに切り替える必要があります。
診断フロー: 上から試して原因を特定する
私が実際に使っているチェックリストは以下の通りです。
- モデル名を確認(claude-haiku-3-5 など未対応モデルでないか)
- API レスポンスの content 配列を直接 print して thinking ブロックの有無を確認
- budget_tokens を 8192 に上げて再実行 — それでも無ければ設定の問題ではない
- stream=True なら text_stream を使わず event ループに変更
- Tool use 併用時は
interleaved-thinking-2025-05-14ヘッダを追加 - prompt caching の cache_read_input_tokens を確認 — キャッシュ部分が支配的なら thinking は走らない
- 直接 Anthropic API で動くか確認 — 動けば中継サービス側の問題
この順序でほぼ全ての「Extended Thinking が効いていない」問題は切り分けられます。
おまけ: thinking が「効きすぎている」場合の対処
逆に「thinking が長すぎてレスポンスが遅い」「thinking_tokens のコストが想定以上」というケースもあります。この場合は budget_tokens を半分に、それでも足りなければ extra_headers={"anthropic-beta": "thinking-budget-policy-2025-09-15"} で動的予算制御を試してみてください。
Extended Thinking は強力ですが、「効かせる」と「効かせ過ぎない」の両方の調整が必要な機能です。本記事の診断フローを手元に置いておけば、次に詰まった時の解決時間を大幅に短縮できるはずです。