Claude API Adaptive Thinking実践ガイド — budget_tokensからeffort制御への移行とコスト最適化
Claude 4.6のリリースにより、Extended Thinking(budget_tokens)はdeprecatedとなり、後継のAdaptive Thinkingが推奨モードになった。従来はトークン予算を固定で指定していたが、Adaptive Thinkingでは推論の深さをClaude自身が判断する。本記事ではAPI実装者向けに、移行手順、effort 4段階の使い分け、displayオプションによるレイテンシ削減、ストリーミング時の挙動差異まで実コード付きで解説する。
Extended ThinkingからAdaptive Thinkingへ — 何が変わったのか
budget_tokens(固定予算)の限界
従来のExtended Thinkingでは、thinking: {type: 'enabled', budget_tokens: 10000} のようにトークン予算を固定で指定していた。この方式には根本的な問題がある。「Hello」のような単純な入力にも指定量のトークンを消費してしまう点だ。タスクの難易度に関係なく一律のコストが発生するため、プロダクション環境ではチューニングが難しかった。
Adaptive Thinkingの設計思想:Claude自身が推論量を決める
Adaptive Thinkingでは、Claude自身がタスクの複雑さに応じて推論量を動的に調整する。簡単な質問なら思考をスキップし、複雑な問題には深く考える。開発者が制御するのは「どれくらい頑張るか」のシグナル(effort)だけだ。
主な変更点を整理する。
thinking: {type: 'enabled', budget_tokens: N}はOpus 4.6 / Sonnet 4.6でdeprecated。将来のリリースで削除予定- 旧モデル(Opus 4.5、Sonnet 4.5以前)は引き続きmanualモード(
type: 'enabled')のみ対応 - Adaptive Thinkingではbeta headerが不要
budget_tokensは「常に指定量を消費する固定コスト」だったが、effortは「行動シグナル」であり、簡単なタスクでは思考をスキップできる
移行のコード変更は最小限で済む。
# Before: Extended Thinking(deprecated)
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000
},
messages=[{"role": "user", "content": prompt}]
)
# After: Adaptive Thinking
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=16000,
thinking={
"type": "adaptive"
},
messages=[{"role": "user", "content": prompt}]
)
effort 4段階の使い分け判断フロー
low / medium / high / max の挙動と適用シーン
effortパラメータは output_config 内に配置する(thinking 内ではない点に注意)。
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=8000,
thinking={"type": "adaptive"},
output_config={"effort": "medium"},
messages=[{"role": "user", "content": prompt}]
)
各レベルの特性は以下のとおりだ。
| effort | 思考の深さ | 適用シーン |
|---|---|---|
low | 最小限。簡単なタスクでは思考をスキップ | 分類、ルーティング、フォーマット変換 |
medium | バランス型。Sonnet 4.6での推奨 | 一般的なコーディング、要約、翻訳 |
high | デフォルト。しっかり考える | 複雑な推論、エージェントのメイン処理 |
max | 最深。Opus 4.6専用 | 数学的証明、高度なコード分析、研究 |
重要なのは、low に設定しても十分に難しい問題ではthinkingが発動する場合がある点だ。effortは完全なオン/オフスイッチではなく、あくまでClaude への「ヒント」として機能する。また、effortは思考だけでなくテキスト応答やツールコールの丁寧さにも影響する。
タスク別effortレベル選定フローチャート
実装時の判断基準をまとめる。
- 入力の分類・振り分けだけ? →
low - 定型的なコード生成・文章処理? →
medium - 複数ステップの推論やエージェント制御? →
high - Opus 4.6で最高精度が必要? →
max
エージェント開発では、サブエージェント(ツール選択、入力検証)に low、メインの推論ループに high を割り当てるパターンが効果的だ。正直、このeffortの使い分けだけでAPIコストが大きく変わるので、最初にしっかり設計しておく価値がある。
displayオプションでレイテンシを最適化する
summarized(デフォルト)vs omitted
display オプションは thinking オブジェクト内で指定する。
# 思考の要約を返す(デフォルト)
thinking={"type": "adaptive", "display": "summarized"}
# 思考を省略する(signatureのみ返る)
thinking={"type": "adaptive", "display": "omitted"}
summarized では要約モデルが生成した思考の概要が返る。Claude 4系では常に要約であり、ターゲットモデルのフル出力ではない。
omitted ではthinkingフィールドが空になるが、signature は返る。このsignatureはマルチターン会話の継続に必要なので、削除してはいけない。
コスト・課金への影響(よくある誤解)
ここで最も重要な注意点がある。omitted に設定してもコストは変わらない。課金はフル思考トークン数ベースで計算されるため、レスポンスに含めないだけで内部的には同量の思考が行われている。
omitted の真の価値はストリーミング時のレイテンシ削減だ。thinking_deltaイベントが省略されることで、最初のテキストトークンまでの時間(time-to-first-text-token)が短縮される。
TypeScript SDKでは現時点で display が型定義に反映されていないため、型アサーションが必要になる。
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 8000,
thinking: {
type: "adaptive",
display: "omitted",
} as any,
messages: [{ role: "user", content: prompt }],
});
ストリーミング時の挙動差異とインターリーブ思考
summarized / omitted でのSSEイベント比較
ストリーミング時のイベントシーケンスはdisplay設定で大きく異なる。
summarized(デフォルト)の場合:
content_block_start (type: thinking)
→ thinking_delta(思考の要約テキスト)
→ signature_delta
→ content_block_start (type: text)
→ text_delta(応答テキスト)
omittedの場合:
content_block_start (type: thinking)
→ signature_delta のみ
→ content_block_start (type: text)
→ text_delta(応答テキスト)
ストリーミング処理の実装例を示す。
import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-6",
max_tokens=8000,
thinking={"type": "adaptive", "display": "summarized"},
messages=[{"role": "user", "content": "Pythonで効率的なLRUキャッシュを実装して"}]
) as stream:
for event in stream:
if event.type == "content_block_start":
if event.content_block.type == "thinking":
print("[思考開始]")
elif event.content_block.type == "text":
print("\n[応答開始]")
elif event.type == "content_block_delta":
if event.delta.type == "thinking_delta":
print(event.delta.thinking, end="", flush=True)
elif event.delta.type == "text_delta":
print(event.delta.text, end="", flush=True)
インターリーブ思考(ツールコール間の推論)
Adaptive ThinkingではOpus 4.6でインターリーブ思考が自動的に有効になる。これはツールコールの結果を受け取った後、次のアクションを決める前に追加の思考を挟む機能だ。manualモード(type: 'enabled')では利用できない。
Sonnet 4.6ではmanualモードでも interleaved-thinking-2025-05-14 beta headerを付ければ利用可能だが、adaptiveモードなら何も追加せずに使える。エージェントワークフローでは、ツール結果の解釈精度が上がるため特に効果的だ。
移行時のハマりポイントと実践Tips
マルチターンでのsignature受け渡し
display: 'omitted' を使う場合でも、レスポンスに含まれるsignatureブロックはそのまま次のターンのmessagesに含める必要がある。
# 1ターン目のレスポンスからsignatureを含むthinkingブロックを保持
first_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8000,
thinking={"type": "adaptive", "display": "omitted"},
messages=[{"role": "user", "content": "Rustでメモリアロケータを設計して"}]
)
# 2ターン目: assistantメッセージにthinkingブロック(signature含む)をそのまま渡す
messages = [
{"role": "user", "content": "Rustでメモリアロケータを設計して"},
{"role": "assistant", "content": first_response.content}, # thinkingブロック含む
{"role": "user", "content": "スレッドセーフにするにはどう変更する?"}
]
second_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8000,
thinking={"type": "adaptive", "display": "omitted"},
messages=messages
)
signatureを削除するとコンテキストが途切れ、会話の一貫性が失われる。これは地味にハマりやすいポイントだ。
プロンプトキャッシュの罠
adaptive ↔ enabled / disabled を途中で切り替えると、messagesのキャッシュブレークポイントが破壊される。systemやtoolsのキャッシュは維持されるが、会話履歴部分のキャッシュが無効になりコストが増加する。thinkingモードはセッション内で固定するのが望ましい。
その他の注意点をまとめる。
stop_reason: 'max_tokens'が返ったら、max_tokensを増やすかeffortを下げて対応するmaxはOpus 4.6限定。モデル名をパラメータ化している場合、effortレベルのバリデーションを入れておくとAPIエラーを防げるdisplayの値はターン間で切り替え可能(初回summarized→ 2ターン目omittedなど)
まとめ
Adaptive Thinkingへの移行は、thinking.type を 'adaptive' に変えるだけで始められる。effortレベルとdisplayオプションを組み合わせることで、タスクごとに推論品質・レイテンシ・コストの最適なバランスを取れるようになった。
特にエージェント開発では、サブエージェントに low、メイン推論に high / max と使い分けることで、従来の budget_tokens 固定よりも効率的な設計が可能になる。まずは既存の budget_tokens 指定を adaptive に置き換え、effort: 'medium' から始めて、タスク特性に応じて調整していくのがおすすめだ。
