AnthropicClaude Certified Architect – Foundations2026-104.3 Enforce structured output using tool use and JSON schemas
Read extracted records from tool inputs
Completed by the knowledge check
Learning objective
Define extraction tools with JSON Schema input contracts and read structured tool_use blocks instead of parsing free-form answers.
Core idea
For a document-extraction pipeline, the output record can be the input to a client tool. Define extract_invoice so its input_schema describes invoice fields. Claude returns a tool_use block whose input contains those fields. Your application reads that object rather than searching an assistant’s prose for something that resembles JSON.
This changes the integration boundary. A tool’s name identifies the contract, its schema describes the record, and the content-block type identifies where to read it. A sentence such as “Here is the invoice” is no longer the payload your downstream consumer parses.
A schema declaration alone is not an enforcement guarantee. Add strict: true when you require schema-constrained tool inputs. See 4.3.2 for the choice between this mechanism and native JSON outputs, and 4.3.3 for requiring an extraction call on supported models.
How it works
Define the record as the tool contract
Pass client-tool definitions in the Messages API request’s tools array. Each definition has a name, a description, and an input_schema. For extraction, describe when the tool applies and what each field means in the source document. You are asking Claude to propose the record as arguments, rather than asking it to execute a parser that exists on Anthropic’s infrastructure.
The following tool definition illustrates the boundary with two fields:
{
"name": "extract_invoice",
"description": "Record the invoice identifier and stated total from one supplier invoice. Use the field labelled invoice number, not an order reference. Record the stated total without recomputing it. Use null when the corresponding evidence is absent.",
"strict": true,
"input_schema": {
"type": "object",
"properties": {
"invoice_number": { "type": ["string", "null"] },
"total": { "type": ["number", "null"] }
},
"required": ["invoice_number", "total"],
"additionalProperties": false
}
}The tool and field names in this example are application-defined. tools, input_schema, and strict are API identifiers. The required keys give consumers a stable record shape; the nullable types let the document lack a value. See 4.3.4 for designing that distinction deliberately.
Tool descriptions matter to interpretation and selection. A schema that accepts two strings cannot distinguish an invoice identifier from a purchase-order identifier on its own. Put that distinction in description, including field-level descriptions where useful. See 2.1.1 for the broader description contract; here the specific responsibility is choosing evidence for extracted fields.
Read blocks by type and name
A client-tool response has stop_reason: "tool_use" and one or more tool_use blocks in content. Each block carries id, name, and input. The id identifies this particular call, while name identifies which contract its arguments use.
Do not assume content[0] is the extraction record. A response can contain text and tool blocks, or multiple calls. Iterate through content, select blocks whose type is tool_use, and dispatch by name. Then read input as the object to validate and consume. For a single-record endpoint, reject a response that lacks the expected extraction call or supplies a call count the endpoint does not accept.
The response fragment your consumer needs looks like this:
{
"type": "tool_use",
"id": "toolu_EXAMPLE",
"name": "extract_invoice",
"input": { "invoice_number": "INV-42", "total": 1240 }
}toolu_EXAMPLE is an illustrative call identifier. The consumer reads input.invoice_number and input.total; it does not parse the assistant’s text block. The API response itself is serialized JSON, but that transport parsing is different from extracting JSON out of generated prose.
Decide whether the conversation continues
Client-tool execution belongs to your application. For a one-shot extraction, you can treat receiving and checking input as the terminal result of your endpoint. This is an application design: it does not mean client tools universally have no implementation or never execute.
If you continue the conversation, preserve the assistant’s content and return a user-message tool_result whose tool_use_id matches the call’s id. Its content can acknowledge acceptance or explain a validation failure. Do not continue as though the call never happened. See 1.1.2 for the full history contract rather than rebuilding that protocol here.
Keep extraction acceptance separate from posting a payment or changing a business record. The fact that Claude requested extract_invoice does not authorize downstream effects. Your consumer first decides whether the proposed record meets the application’s evidence and value checks.
Key distinctions and trade-offs
Structured block versus schema enforcement: Reading tool_use.input removes the need to locate a record inside prose. strict: true adds grammar-constrained schema compliance. A tool without strict mode can still supply incompatible types or omit required fields.
Extracted arguments versus tool results: The extracted fields are in the assistant’s tool_use.input. A later tool_result carries what your application did with those arguments. Reading the latter as the original extraction loses the interface distinction.
Shape versus evidence: A numeric total can have the right type and the wrong value. A string can be copied from the wrong part of the document. Strict mode enforces the supported schema, not the relationship between the proposed record and the invoice. See 4.3.5 for semantic validation.
This pattern fits a workflow already organized around tools and named record types. When the only requirement is a final JSON record, native JSON outputs can avoid introducing a synthetic extraction call; see 4.3.2.
Architecture / decision scenario
An accounts-payable service receives an invoice containing an invoice number, an order reference, and a stated total. Its first implementation asks for JSON, removes Markdown fences from the answer, and passes the resulting string to a JSON parser. Some responses include an explanation before the record, so the pipeline fails before it can examine values.
Replace that boundary with extract_invoice in tools, a precise input_schema, and strict: true. The consumer inspects the response outcome, selects the expected tool_use block by type and name, and reads input. An explanatory text block is harmless because it is not the payload.
The service checks that the selected identifier matches the invoice-number evidence rather than the order reference. It accepts one record for the one-document request and holds anything outside that contract. For the endpoint that ends at extraction, it returns the accepted record directly. For an enrichment conversation, it preserves the call and sends a correlated tool_result before the next inference. Both designs consume the same structured input; neither depends on extracting a JSON substring from prose.
Common exam traps
- Parsing a text answer when the extracted record is already in
tool_use.input. - Assuming the first content block always contains the record.
- Confusing a tool name with a particular call’s
id. - Treating an ordinary
input_schemaas equivalent tostrict: true. - Leaving
tool_choiceonautoand parsing the text answer when notool_useblock arrives. - Continuing the conversation without a matching
tool_result.
Where the exam guide differs
The exam guide describes tool use with JSON schemas as guaranteeing schema-compliant output. Anthropic distinguishes ordinary tool schemas from strict tool use: strict: true supplies the enforcement guarantee. Read an exam option favoring schema-based extraction over parsing prose as the interface choice, and distinguish it from the separate requirement to enable strict mode.
What to remember
Define the extracted record in input_schema, describe its evidence semantics, and read tool_use.input by block type and tool name. Strict mode enforces shape; your application accepts the values. If the conversation continues, preserve the call and its correlated result.
Knowledge check
An accounts-payable service asks Claude to “return the invoice as JSON”, strips Markdown fences, and parses the reply. Some replies open with a sentence of explanation, so parsing fails before any value is checked. The consumer must read the record without searching generated prose. Which change meets that requirement?
{ and the last } before parsingextract_invoice client tool and read the record from its tool_use.inputtool_use block, and the consumer reads that object while any explanatory text block is simply not the payload. A firmer instruction or a few examples make a clean reply more likely but still leave the record inside generated text, and substring extraction parses prose that can contain a stray brace or a missing comma.Your consumer reads response.content[0].input as the extracted invoice. In production some responses fail with no input on that block, although stop_reason is "tool_use". How should the consumer locate the record?
content and select the tool_use block whose name is extract_invoicecontent , where the tool call follows any explanatory textcontent and select the block whose id is extract_invoicecontent[0] and instruct Claude to call the tool before writing textid identifies one particular call, such as toolu_… , while the name identifies the contract its arguments follow.After accepting an extract_invoice record, an enrichment flow continues the same conversation so Claude can look up the supplier. What must the next request contain for the extraction call?
tool_result whose tool_use_id names the tool extract_invoicetool_result matching the call’s id , without the assistant’s tool calltool_result matching the call’s idtool_use block and answering it with a tool_result whose tool_use_id is that call’s id . The tool name identifies the contract rather than the call, and restating the record as ordinary text continues as though the call never happened.An extraction tool lists invoice_number and total in required, but logs show occasional calls that omit total or send it as the string "1240". The tool definition has no strict field. Which change prevents these failures in emitted calls?
total stating that it is always a numberstrict: true to the extract_invoice tool definitiontool_choice to require a call to extract_invoicetotal is a required numberinput_schema guides Claude but does not enforce itself: without strict mode a call can omit required fields or use incompatible types. strict: true constrains the arguments of every emitted call to the supported schema. Descriptions and prompts are more guidance of the kind the schema already gave, and requiring a call decides whether the tool is used, not what its arguments contain.References
- Anthropic, Define tools
- Anthropic, Handle tool calls
- Anthropic, Strict tool use
- Anthropic, Claude Certified Architect – Foundations Exam Guide