Control Tool Choice
What Tool Choice Controls
When you send tools, Claude normally decides for itself whether to call them (Lesson 84). The tool_choice parameter lets you control that decision:
response = client.messages.create(
model="claude-haiku-5-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "auto"},
messages=[{"role": "user", "content": "What's the weather in Chennai?"}],
)
There are four options:
tool_choice | Behavior |
|---|---|
{"type": "auto"} | Claude decides whether to call tools, and which. The default when tools are provided. |
{"type": "any"} | Claude must call one of the provided tools, but chooses which. |
{"type": "tool", "name": "get_weather"} | Claude must call this specific tool. |
{"type": "none"} | Claude must not call any tool. The default when no tools are provided. |
any and tool are called forced tool use, because they force a tool call.
Model Support for Forced Tool Use
Not every model supports forced tool use. According to the current documentation:
| Model or setting | auto and none | any and tool |
|---|---|---|
| Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, Claude Mythos 5.1 | Supported | Not supported: the request fails with a 400 error |
| Models with adaptive thinking on by default, such as Claude Opus 5 and Claude Haiku 5.5 | Supported | Supported. A forced call skips thinking: the response starts with the tool call, with no thinking block. |
Any model with manual extended thinking enabled (thinking={"type": "enabled", ...}) | Supported | Not supported |
This matters because many tutorials use tool_choice={"type": "any"} or {"type": "tool", ...}. On the current flagship models, that code fails.
What to Use Instead on Models Without Forced Tool Use
The documentation recommends:
| Goal | Alternative |
|---|---|
| Make Claude call a tool | Use auto and instruct Claude to use the tool in the user message, for example "Use the get_weather tool in your response." |
| Guarantee valid tool inputs | Set strict: true on the tool definitions (Lesson 83) |
| Get a response in a fixed JSON shape | Use structured outputs (Lesson 36) instead of a forced "extraction tool" |
Prompting is a strong influence on which tool auto picks, but it is not a hard guarantee. Your code should still check whether the response actually contains the expected tool call.
auto: The Default
With auto, Claude calls tools when they help and answers directly when they do not. That is the right choice for most conversational applications and agents (Lesson 88). Guide its decisions with tool descriptions and the system prompt (Lessons 82 and 84).
Disabling Parallel Tool Calls
By default, Claude may call several tools in one response. To limit that, set disable_parallel_tool_use: True inside tool_choice (it is not a top-level parameter):
tool_choice={"type": "auto", "disable_parallel_tool_use": True}
tool_choice type | Effect of disable_parallel_tool_use: True |
|---|---|
auto | At most one tool call per response; Claude can still answer without tools |
any or tool (where supported) | Exactly one tool call per response |
Use it when tools must run strictly one at a time, for example when each step depends on the previous one and you want Claude to see each result before deciding the next call. For independent calls, leave parallel use enabled: it saves rounds and tokens.
any and tool: Forcing a Call (Where Supported)
On models that support forced tool use, such as Claude Haiku 5.5:
response = client.messages.create(
model="claude-haiku-5-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "tool", "name": "get_weather"},
messages=[{"role": "user", "content": "Chennai"}],
)
Important behaviors from the documentation:
- No text before the call. With
anyortool, the API prefills the assistant message to force a tool call, so the response contains thetool_useblock without a preamble, even if asked for one. - No thinking. A forced call skips thinking: the response starts with the tool call.
- Combine with
strict: trueto guarantee both that a tool is called and that its input matches the schema.
If you want Claude to explain or think before calling a specific tool, use auto with an instruction in the user message instead.
none: Tools Defined, but Not Used
{"type": "none"} prevents tool calls even though tools are included in the request. This is useful when:
- you want a summary turn at the end of an agent run, without new tool calls, while keeping the tools in the request so the conversation history remains consistent (Lesson 88);
- you want to keep the same tool definitions in every request for prompt caching, while temporarily disabling tools for some turns.
Note: with prompt caching, changing
tool_choicebetween requests invalidates cached message blocks. Tool definitions and the system prompt remain cached, but the messages must be reprocessed (Lessons 121–130).
Practical Example: Requiring a Tool Call on Any Model
This helper makes Claude call a tool, using forced tool choice where the model supports it, and the documented alternative (an explicit instruction with auto and strict tools) where it does not. It then verifies that the expected tool was actually called.
"""require_tool.py: get a tool call reliably, on models with and without forced tool use."""
import anthropic
from anthropic import Anthropic
client = Anthropic()
# Models that reject tool_choice "any" and "tool" (per the current documentation)
NO_FORCED_TOOL_CHOICE = {"claude-opus-5-5", "claude-sonnet-5-5", "claude-fable-5-1", "claude-mythos-5-1"}
WEATHER_TOOL = {
"name": "get_weather",
"description": (
"Gets the current weather for a city. Use it for questions about current conditions. "
"Returns temperature in Celsius and a short description. It does not provide forecasts."
),
"strict": True,
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string", "description": "City name, e.g. Chennai"}},
"required": ["city"],
"additionalProperties": False,
},
}
def require_tool_call(model: str, question: str, tool: dict):
"""Return (response, method). The response should contain a call to `tool`."""
request = {"model": model, "max_tokens": 2048, "tools": [tool]}
if model not in NO_FORCED_TOOL_CHOICE:
request["tool_choice"] = {"type": "tool", "name": tool["name"]}
request["messages"] = [{"role": "user", "content": question}]
return client.messages.create(**request), "forced tool_choice"
instruction = f"Use the {tool['name']} tool in your response."
request["tool_choice"] = {"type": "auto"}
request["messages"] = [{"role": "user", "content": f"{question}\n\n{instruction}"}]
return client.messages.create(**request), "auto + instruction"
def called(response, tool_name: str) -> list[dict]:
return [b.input for b in response.content if b.type == "tool_use" and b.name == tool_name]
if __name__ == "__main__":
question = "Should I carry an umbrella in Chennai this evening?"
for model in ["claude-haiku-5-5", "claude-opus-5-5"]:
response, method = require_tool_call(model, question, WEATHER_TOOL)
calls = called(response, "get_weather")
blocks = [b.type for b in response.content]
print(f"{model:<18} via {method:<20} calls={calls} blocks={blocks}")
try:
client.messages.create(
model="claude-opus-5-5", max_tokens=1024, tools=[WEATHER_TOOL],
tool_choice={"type": "any"},
messages=[{"role": "user", "content": question}],
)
except anthropic.BadRequestError as error:
print(f"\nForced tool_choice on claude-opus-5-5 -> HTTP {error.status_code} (not supported)")
Example output:
claude-haiku-5-5 via forced tool_choice calls=[{'city': 'Chennai'}] blocks=['tool_use']
claude-opus-5-5 via auto + instruction calls=[{'city': 'Chennai'}] blocks=['thinking', 'text', 'tool_use']
Forced tool_choice on claude-opus-5-5 -> HTTP 400 (not supported)
How It Works
NO_FORCED_TOOL_CHOICElists the models that the documentation says rejectanyandtool. Keep this list in one place, and update it when you adopt new models (check each model's documentation).- On supported models, the helper sets
tool_choice={"type": "tool", "name": ...}. The response contains only the tool call: no thinking block and no preamble, exactly as documented for forced calls. - On other models, the helper uses
autoand appends an explicit instruction to the user message, the documented alternative. Claude thinks, writes a short preamble, and calls the tool. strict: Truewith"additionalProperties": Falseguarantees that, whenever the tool is called, its input matches the schema (Lesson 83).called()checks the response for the expected tool. Withauto, a call is very likely but not guaranteed, so production code should handle the case wherecallsis empty, for example by retrying once with a firmer instruction, or by continuing without the tool.- The final block shows the failure mode: sending
tool_choice={"type": "any"}to Claude Opus 5.5 raisesanthropic.BadRequestError(HTTP 400).
Choosing the Right Option
| Situation | Recommended setting |
|---|---|
| Chat assistants and agents | auto (the default) |
| One action at a time, each depending on the previous result | auto with disable_parallel_tool_use: True |
| A specific tool must be called, on a model that supports forcing | tool (with strict: true) |
| A specific tool must be called, on Opus 5.5, Sonnet 5.5, Fable 5.1, or Mythos 5.1 | auto + an explicit instruction + strict: true, then verify |
| You need a fixed JSON output, not an action | Structured outputs (Lesson 36), not a forced tool |
| Tools stay defined, but this turn must not call them | none |
Common Mistakes
Using Forced Tool Choice on Models That Reject It
What happens: a 400 error on Claude Opus 5.5, Sonnet 5.5, Fable 5.1, or Mythos 5.1.
Fix: use auto with an instruction and strict tools, or structured outputs.
Forcing Tools for Structured Output
What happens: older "fake extraction tool" patterns break on current models, or skip thinking unnecessarily.
Fix: use structured outputs for fixed JSON shapes.
Putting disable_parallel_tool_use at the Top Level
What happens: the request fails, because the field belongs inside tool_choice.
Fix: tool_choice={"type": "auto", "disable_parallel_tool_use": True}.
Expecting Explanations with Forced Calls
What happens: no preamble text appears, even when the prompt asks for one.
Fix: use auto with an instruction if you want text or thinking before the call.
Assuming auto + an Instruction Always Calls the Tool
What happens: code that reads response.content[...] for a tool call fails on the rare response without one.
Fix: check for the tool call, and handle its absence.
Best Practices
- Use
autoby default, and guide tool use with descriptions and the system prompt. - Know your model's tool-choice support, and keep that knowledge in one place.
- Prefer instructions plus
strict: trueover forced tool choice on current flagship models. - Use structured outputs for fixed JSON responses.
- Disable parallel calls only when steps truly depend on each other.
- Use
noneto pause tool use without changing the tool list. - Always verify that the response contains the tool call your code expects.
Exercise
- Run
require_tool_call()withclaude-sonnet-5-5. Which method does it use? - Send a request to Claude Opus 5.5 that asks about the weather in two cities, with
tool_choice={"type": "auto", "disable_parallel_tool_use": True}. How many tool calls does the first response contain? - Extend
require_tool_call()to retry once with a firmer instruction when theautopath returns no call to the expected tool. - Explain why structured outputs are a better fit than a forced tool when you only need Claude to return data in a fixed JSON format.
Step 2: at most one tool call, for one of the cities. After you return its result, Claude makes the second call in the next round. Disabling parallel use trades extra rounds for strictly sequential calls.
Step 4: a tool call represents an action your application performs, and requires the full tool-use flow: reading the call, returning a result, and continuing. When you only need data in a fixed shape, structured outputs return it directly as the response, guaranteed to match your schema, in a single request, without fake tools or extra rounds. They also work on every current model, including those that reject forced tool choice.