What you will be able to do
- Explain why defining an extraction tool with a JSON schema, especially with strict: true, gives schema-compliant output that never has JSON syntax errors
- Read the extracted data out of the input field of a tool_use block
- Pick tool_choice auto, any, or a forced tool for a given extraction pipeline
- Recognise when forced tool choice is rejected (manual extended thinking, the newest models) and what to use instead
Key concept
Extraction tool — An extraction tool is defined only so that Claude will fill in its JSON-schema input. The structured data you want is the tool call's input object. You are not asking Claude to run an operation. With strict mode on, that input is guaranteed to match the schema.
1.Why a tool schema beats asking for JSON
If you ask Claude in plain prose to 'reply in JSON', the result depends on how well it follows instructions. You can get a stray preamble, a missing brace, or a number written as a string. Tool use takes a different approach. Anthropic describes it as a contract: your application states which operations exist and what shape their inputs take, and Claude decides when to call them. Claude never runs anything itself. It produces a structured request that matches your schema.
For extraction, that structured request is the output you want. The Anthropic cookbook describes a print_sentiment_scores tool whose only job is to get Claude to produce well-structured JSON. The tool does nothing. Its schema defines the shape of the answer.
On its own, a schema guides Claude but does not guarantee anything. The strict tool use docs say that without strict mode Claude can still return the wrong types or leave out required fields. Setting strict: true closes that gap with grammar-constrained sampling: Claude can only generate tokens that keep the output valid for the schema. Malformed JSON can't be produced at all.
Checkpoint 1 of 6· Check yourself
A booking tool needs passengers as an integer. Without strict mode, what does the documentation say can happen?
Without strict mode the schema guides Claude but does not constrain it, so type mismatches and missing required fields are possible. strict: true is what turns guidance into a guarantee.
“Without strict mode, Claude might return incompatible types ("2" instead of 2) or omit required fields, breaking your functions and causing runtime errors.”Source: platform.claude.com
2.Defining the tool and reading the tool_use block
Setup takes three steps. First, write a JSON schema as the tool's input_schema. Second, add strict: true at the top level of the tool definition, next to name, description and input_schema. Third, handle the call. When Claude uses the tool, the response has stop_reason set to tool_use and contains one or more tool_use content blocks. Each block has an id, the tool name, and an input object that follows your schema.
{
"type": "tool_use",
"name": "get_weather",
"input": {
"location": "San Francisco, CA"
}
}Your code finds this block in response.content and reads input. That object is your structured record. For an extraction tool, input is already the result, so there's no real work to run on it. In an agentic loop, your code would run the operation and send the output back in a tool_result block. Strict mode also guarantees the tool name is always valid, so your dispatch code can trust it.
Checkpoint 2 of 6· Put it in order
Put the steps for enabling strict tool use in order
- 1.Set "strict": true as a top-level property of the tool definition
- 2.Define a JSON schema for the tool's input_schema
- 3.Read the input field of the returned tool_use block, which follows the schema
The docs list these steps in order: define the schema, add strict: true next to name, description and input_schema, then handle the tool call, whose input follows the schema.
“Set "strict": true as a top-level property in your tool definition, alongside name, description, and input_schema.”Source: platform.claude.com
3.tool_choice: auto, any, or a named tool
Defining a tool doesn't make Claude use it. The tool_choice field controls whether a call happens. In the cookbook's deliberately weak example, Claude got a sentiment tool and a calculator under auto. For an excited tweet about a meal it replied with friendly chat and called no tool. For a tweet about cats it called the calculator. Strict mode doesn't help here: it controls the shape of a tool call, not whether one is made.
| tool_choice | Behaviour | Extraction use |
|---|---|---|
| {"type": "auto"} (default with tools) | Claude decides whether to call any tool, and may reply with text | Conversational flows; pipelines that need every input extracted must not rely on it |
| {"type": "any"} | Claude must call one of the provided tools but picks which | Several extraction schemas (invoice, contract, receipt) and an unknown document type |
| {"type": "tool", "name": "..."} | Claude must call that specific tool | Make sure a particular metadata extraction step runs before any enrichment |
| {"type": "none"} | Claude cannot use tools (default when no tools are provided) | Turns where you want prose only |
any fits a document classifier that has several extraction schemas. The cookbook describes it as telling Claude "you must call a tool, but you can pick which one". A text-free response is ruled out, but Claude still chooses the schema that fits the document. Forcing a named tool is stricter. Use it when one particular extraction has to happen, for example pulling metadata before later steps depend on it.
Checkpoint 3 of 6· Fill the gap
Complete the request so Claude must call get_weather specifically
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": " ? ", "name": "get_weather"},
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)Forcing one named tool takes type "tool" plus a name. "any" forces some tool without choosing which one, and "auto" forces nothing.
Source: platform.claude.com4.What forcing costs, and where it is rejected
With any or a named tool, the API prefills the assistant turn so that a tool call is required. As a result, Claude writes no natural-language explanation before the tool_use block, even if your prompt asks for one. Anthropic says its testing shows this should not reduce performance. If you need commentary as well as the tool call, the documented approach is to keep tool_choice at auto and add an explicit instruction in the user message, for example telling Claude to use the get_weather tool.
Checkpoint 4 of 6· Exam question
A team is building a pipeline that asks Claude to read free-form support tickets and return a JSON object with fields like priority, category, and summary. Early prototypes used a prompt asking Claude to "reply with only JSON", but downstream parsing occasionally failed on malformed brackets and stray commentary text. Which approach most reliably eliminates these JSON syntax failures?
Correct answer: A — Define an extraction tool with an input_schema describing the fields, and parse the structured arguments from the resulting tool_use block instead of parsing free text
- A. Correct. Tool use with a JSON schema constrains the model's output to match the schema's structure, guaranteeing well-formed structured data extracted from the tool_use block rather than relying on the model to format free text correctly.
- B. Stronger wording in the system prompt can reduce but not eliminate malformed output, and retry loops add latency and cost without guaranteeing correctness.
- C. Lowering temperature makes responses more consistent but does not enforce a schema; the model can still emit prose, missing brackets, or truncated JSON.
- D. Markdown fencing is a formatting convention, not a schema constraint; the enclosed content itself can still be malformed or contain extra commentary.
Forced tool use also isn't supported everywhere. In those cases any and named-tool choices fail, while auto and none still work. Two situations matter. The first is manual extended thinking, thinking: {type: "enabled"}. The second is the newest models: Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1 and Claude Mythos 5.1, which return a 400 error whatever the thinking settings.
| Setting | any / tool | What to use instead |
|---|---|---|
| Manual extended thinking (thinking: {type: "enabled"}) | Not supported; request errors | auto or none. Adaptive thinking does not block forced tool use (Claude Opus 5 supports it with thinking on) |
| Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, Claude Mythos 5.1 | 400 error | auto with strict tool use for schema-valid inputs, or structured outputs for a fixed JSON response shape |
On those models, auto plus strict: true still guarantees that any tool call is schema-valid. The documentation notes that your prompt still influences which tool Claude picks under auto, so it's the prompt, not the API, that makes Claude call the extraction tool.
Checkpoint 5 of 6· Exam question
A document-processing service receives files that could be invoices, resumes, or contracts, but the type is not known ahead of time. The service defines three separate extraction tools (extract_invoice, extract_resume, extract_contract) and needs Claude to always call exactly one of them so the pipeline never falls back to plain text. Which tool_choice configuration should be used?
Correct answer: A — Set tool_choice to {"type": "any"} so Claude must call one of the three tools but can pick whichever matches the document
- A. Correct. tool_choice: "any" forces Claude to call some tool but leaves the choice of which tool up to the model, which is exactly what's needed when the document type is unknown but a tool call must always happen.
- B. "auto" is the default and permits Claude to respond with plain text instead of calling any tool, which does not guarantee structured output.
- C. Forcing a single named tool would incorrectly run invoice extraction even on resumes or contracts, since the document type is unknown in advance.
- D. Without the tools parameter there is no schema enforcement at all; Claude would be generating free-form text that happens to look like JSON, reintroducing syntax risk.
Checkpoint 6 of 6· Check yourself
An extraction pipeline moves to Claude Opus 5.5 and keeps tool_choice: {"type": "tool", "name": "extract_metadata"}. What happens, and what does the documentation recommend?
Claude Opus 5.5 rejects any and tool choices with a 400 error. The documented replacement is auto with strict tool use, or structured outputs when you need a fixed JSON response shape.
“auto with strict tool use to guarantee schema-valid tool inputs”Source: platform.claude.com
Sources5
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.With a forced tool choice, you can still ask Claude to explain its reasoning in text before the tool call.Why is that wrong?
With any or a named tool, the API prefills the assistant turn, so Claude writes no natural-language text before the tool_use block. To get commentary, use auto and ask for the tool in the user message.
Covered in What forcing costs, and where it is rejected
2.tool_choice any or a named tool works with every model and every thinking mode.Why is that wrong?
Manual extended thinking rejects both, and Claude Opus 5.5, Sonnet 5.5, Fable 5.1 and Mythos 5.1 return a 400 error. Adaptive thinking does not block forced tool use on models that support it.
Covered in What forcing costs, and where it is rejected
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Tool use is a contract between your application and the model.”
↩︎ Why a tool schema beats asking for JSON - 2.
“Setting strict: true on a tool definition guarantees Claude's tool inputs match your JSON Schema”
↩︎ Why a tool schema beats asking for JSON“Tool name is always valid (from provided tools or server tools)”
↩︎ Defining the tool and reading the tool_use block“Setting strict: true on a tool definition guarantees Claude's tool inputs match your JSON Schema”
↩︎ Key concept“Without strict mode, Claude might return incompatible types ("2" instead of 2) or omit required fields, breaking your functions and causing runtime errors.”
↩︎ Checkpoint“Set "strict": true as a top-level property in your tool definition, alongside name, description, and input_schema.”
↩︎ Checkpoint - 3.https://platform.claude.com/cookbook/tool-use-tool-choiceSecondary source
“a tool that "tricks" Claude into generating well-structured JSON output containing sentiment analysis data”
↩︎ Why a tool schema beats asking for JSON“Claude does not call our sentiment analysis tool”
↩︎ tool_choice: auto, any, or a named tool“you must call a tool, but you can pick which one”
↩︎ tool_choice: auto, any, or a named tool - 4.
“input: An object containing the input being passed to the tool, conforming to the tool's input_schema.”
↩︎ Defining the tool and reading the tool_use block - 5.
“any tells Claude that it must use one of the provided tools, but doesn't force a particular tool.”
↩︎ tool_choice: auto, any, or a named tool“you can use {"type": "auto"} for tool_choice (the default) and add explicit instructions in a user message.”
↩︎ What forcing costs, and where it is rejected“any and tool return a 400 error”
↩︎ What forcing costs, and where it is rejected“Adaptive thinking itself doesn't block forced tool use (Claude Opus 5 supports it with thinking on)”
↩︎ What forcing costs, and where it is rejected“the models will not emit a natural language response or explanation before tool_use content blocks, even if explicitly asked to do so.”
↩︎ Exam trap 1“any and tool are not supported and result in an error”
↩︎ Exam trap 2“auto allows Claude to decide whether to call any provided tools or not. This is the default value when tools are provided.”
↩︎ Prediction“auto with strict tool use to guarantee schema-valid tool inputs”
↩︎ Checkpoint