Claude Media
「tool_choice: any」と拡張思考が同時に使えない理由

「tool_choice: any」と拡張思考が同時に使えない理由

拡張思考の手動モードとtool_choice: any/toolは併用できずエラーになります。原因、Fable 5.1・Mythos 5.1での例外、代わりに使える手段をまとめます。

tool_choice: any/toolと拡張思考の非互換

拡張思考を手動で有効にした状態(thinking: {"type": "enabled"})でtool_choice{"type": "any"}{"type": "tool", "name": "..."}にすると、Claude APIはエラーを返します。使えるのはauto(既定)とnoneだけです。ツールを強制的に呼ばせたい場合、この2つの設定は選べません。

adaptive(適応的)思考に切り替えれば、forced tool useは使えるようになります。ただしClaude Fable 5.1とClaude Mythos 5.1の2モデルだけは、adaptive思考でも一律で拒否します。3つの層に分かれていて、どれに当てはまるかで対処が変わります。

エラーを再現してみる

手動の拡張思考とforced tool useを両方指定すると、次のようなリクエストになります。

curl -sS https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-opus-5",
    "max_tokens": 1024,
    "thinking": {"type": "enabled", "budget_tokens": 4000},
    "tools": [{
      "name": "get_weather",
      "description": "Get the current weather in a given location",
      "input_schema": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"]
      }
    }],
    "tool_choice": {"type": "any"},
    "messages": [{"role": "user", "content": "What is the weather in Tokyo?"}]
  }'

このリクエストは400のinvalid_request_errorで失敗します。原因はモデルでもツール定義でもなく、thinkingtool_choiceの組み合わせそのものです。tool_choice{"type": "auto"}に戻すだけで、他のフィールドを一切変えずに通ります。

なぜ手動モードだけforced tool useを拒否するのか

tool_choiceanytoolのとき、APIはassistantメッセージ側をあらかじめ埋め込み、ツール呼び出しを強制します。自然文の説明は一切出ません。プロンプトで「説明も添えて」と頼んでも、tool_useブロックの前にテキストが現れることはありません。

一方、拡張思考の手動モードには別の制約が重なります。thinkingが有効なリクエストでは、そのターンの最後のassistantメッセージはthinkingブロックから始まる必要があります。forced tool useのプリフィルと、thinkingブロックで始まる要求は両立しません。ここが競合の正体です。

adaptive思考はこの制約を緩めます。どのassistantターンもthinkingブロックで始まる必要がなく、Claudeが必要と判断したときだけ考えます。だからadaptive思考ではforced tool useが通ります。Opus 5のようにthinkingが既定で有効なモデルも、この層に含まれます。

モデル・設定別の対応早見表

設定 / モデルany / tool代わりに使えるもの
拡張思考の手動モード(thinking.type.enabled)any / tool使えない(エラー)代わりに使えるものautoまたはnone
adaptive思考(Opus 5など既定で有効な場合も含む)any / tool使える代わりに使えるもの
Claude Fable 5.1 / Claude Mythos 5.1any / tool使えない(400エラー、adaptiveでも常に拒否)代わりに使えるものauto + strict tool use、またはstructured outputs

thinkingをまったく使わないリクエストであれば、この制約自体がかかりません。公式が制限として挙げているのは、thinkingが関わる2つの層(手動モードそのもの、Fable 5.1・Mythos 5.1というモデル固有の制限)です。

Fable 5.1・Mythos 5.1は例外 — 実際のエラー文言

Fable 5.1とMythos 5.1は、thinkingを手動でオフにできないモデルです。常にadaptive思考で動きます。それでもforced tool useは一律で拒否します。tool_choice: {"type": "any"}または{"type": "tool", "name": "..."}を送ると、この2モデルに限って常に400エラーが返ります。

tool_choice: type "tool" and "any" are not supported for this model.

トークンカウントのエンドポイント(/v1/messages/count_tokens)に同じリクエストを送った場合も、同じ扱いで拒否されます。「本番は通ったのにカウントAPIだけ失敗する」という切り分けを避けるなら、両方のエンドポイントで同じtool_choice設定を試しておくのが確実です。

この制限は「5.1」という版名が付くモデルに固有です。公式がforced tool use非対応として挙げているのはClaude Fable 5.1とClaude Mythos 5.1の2モデルのみで、無印のClaude Fable 5やClaude Mythos 5、Claude Mythos Previewについては非対応という記載がありません(Claude Mythos Previewはassistant prefillに非対応という別の制約が公式ドキュメントに記載されており、forced tool useの可否を断定できる材料ではありません)。モデル名に「5.1」が付くかどうかだけを見て判断すると、Fable系・Mythos系の間で挙動が割れていることを見落とします。

回避策 — autoにstrict tool useかstructured outputs

手動の拡張思考を使い続けたいなら、tool_choiceauto(既定)のままにします。ツール入力のスキーマ違反を防ぎたいだけなら、forced tool use自体が必須ではありません。

curl -sS https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-opus-5",
    "max_tokens": 1024,
    "thinking": {"type": "enabled", "budget_tokens": 4000},
    "tools": [{
      "name": "get_weather",
      "description": "Get the current weather in a given location",
      "input_schema": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"]
      },
      "strict": true
    }],
    "tool_choice": {"type": "auto"},
    "messages": [{"role": "user", "content": "What is the weather in Tokyo?"}]
  }'

strict: trueを各ツール定義に付けると、Claudeが実際にツールを呼んだときの入力は必ずスキーマどおりの形になります。これはプロンプトでの指示ではなく、モデルのトークンサンプリング自体をスキーマに適合する出力だけに制約する仕組み(grammar-constrained sampling)によるものです。passengers: intのようなフィールドに"2"という文字列が入ってくる、必須フィールドが欠落する、といった型不一致がなくなります。

strictはツールが呼ばれたときの入力形式を保証する仕組みで、ツールが呼ばれること自体は保証しません。forced tool useが担っていたのは後者です。パラメーターの欠落による再試行はstrict: trueで減らせますが、「ツールを一切呼ばずに直接テキストで答える」という選択肢自体はautoである以上残ります。

応答そのものを固定のJSON構造で受け取りたい場合は、ツール呼び出しではなくstructured outputsのoutput_config.formatが選択肢になります。どちらの手段を使っても、プロンプト側の指示はautoがどのツールを選ぶかに引き続き影響します。「必ず1つは呼ぶ」という保証だけがなくなる点は変わりません。

この「必ず呼ぶ」保証の欠如は、地味に見えて設計上の影響が大きい違いです。forced tool useを前提に組んだエージェントループは、Claudeがツールを呼ばずテキストだけで返してきた場合の分岐を持っていないことがあります。autoへ切り替える際は、ツール呼び出しが無いレスポンスをどう扱うかを呼び出し側のコードに用意しておく必要があります。

ターンの途中でthinking設定を変えられるか

「このツール呼び出しだけforced tool useにして、それ以外は手動思考のまま」という設計を考える人もいます。結論から言うと、それはできません。

ツール呼び出しから結果の受け渡しまでを含む一連のやり取りは、モデルから見ると1つのassistantターンです。ユーザーの質問、thinkingtool_use、ツール実行結果、最終的な回答という流れ全体が1ターンとして扱われます。このターンの途中でthinkingモードを切り替えることはできません。

途中で設定を変えて送ると、APIはエラーにはせず、代わりにそのリクエストのthinkingを無効化します。会話の整合性を保つために、矛盾するターン構造を作りかねないthinkingブロックを取り除く場合もあります。「エラーにならないから設定は反映された」と思い込むと、実際には無効化されたthinkingのまま処理が進んでいることに気づきません。レスポンスにthinkingブロックが含まれているかどうかで、実際に有効だったかを確認できます。

設定を変えるタイミングは、ターンとターンの間に限られます。1つのassistantターンが完結してから、次のユーザーメッセージを送る前にthinkingtool_choiceの組み合わせを変更する、という運用であれば問題なく機能します。

tool_choiceの切り替えはキャッシュに影響する

tool_choiceを変更すると、キャッシュされたメッセージブロックが無効になります。ツール定義とシステムプロンプトのキャッシュは保持されますが、メッセージ本体は再処理されます。

手動思考とadaptive思考をリクエストごとに切り替える設計では、この再処理コストも見積もりに入れておく必要があります。同じ会話の途中でtool_choiceだけをautoからanyへ切り替えるような実装は、キャッシュヒット率を下げる副作用を伴います。

Agent SDK・Claude Codeから見た位置づけ

tool_choiceはMessages APIの生パラメーターです。Claude Code CLIの通常利用でこの値を直接指定する場面はほとんどなく、影響するのはAgent SDKやAPIを直接呼び出してカスタムのエージェントループを組んでいる場合です。

ツール呼び出しのループ自体をSDKに任せる設計であれば、Tool RunnerでAnthropic APIのツール呼び出しループを自動化するがこの種の整形やリトライを内部で吸収します。手動でこの組み合わせを気にする必要があるのは、tool_choiceを自前で制御している実装に限られます。

似ているが別物のエラーと混同しない

似た文脈で出るエラーにthinking.type.enabled is not supported for this modelがあります。これはモデル世代そのものが拡張思考の旧パラメーター形式を受け付けなくなったときのエラーで、原因はまったく別です。原因の切り分けと直し方は「thinking.type.enabled」エラーの原因と対処法にまとめています。

tool_useのあとにthinkingブロックを編集・並べ替えして送り返した場合に出るthinking block mismatchも別のエラーです。こちらはtool_choiceの制約ではなく、thinkingブロックをそのままの形で返していないことが原因で、thinking block mismatchエラーの原因とrewindでの直し方で扱っています。エラーメッセージにtool_choiceという語が含まれているかどうかで、まずどちらの系統かを見分けられます。

まとめ

拡張思考を手動で有効にしている間は、tool_choiceanytoolにできません。使えるのはautononeだけです。adaptive思考に切り替えればforced tool useは使えますが、Fable 5.1とMythos 5.1だけは例外で常に拒否されます。

強制的な呼び出しを諦められない実装では、autoにstrict tool useかstructured outputsを組み合わせるのが現実的な代替です。どちらもforced tool useそのものを再現するわけではなく、「入力のスキーマを保証する」という近い効果を別の手段で得る形になります。

この記事を共有:XはてブLinkedIn