Structured output with tool use and JSON schemas
What this covers
- Guarantee schema-compliant tool input with
strict: truerather than parsing prose - Choose between auto, any, and a forced named tool
- Design schemas that do not push the model into fabricating
- Separate the syntax errors a strict schema removes from the semantic ones it leaves
- Check the response stop reason before treating a tool call as a successful extraction
- State date and unit normalization rules in the prompt alongside the schema
process plate / 4.3
Valid JSON can still contain wrong values
Send three responses through the extraction gates. Stop reason, expected strict tool identity, schema conformance, and semantic checks answer different questions.
process reading / no usable extraction
Handle the stop reason.
No expected strict tool input was returned, so there is nothing schema-validated to consume.
Read the complete diagram as text
- First inspect stop_reason and require the tool-use path.
- Confirm that the expected strict tool call is actually present before reading its input.
- Treat that strict tool input as schema-conformant, not automatically true.
- Run deterministic semantic checks such as totals and cross-field consistency.
- Accept, retry with specific feedback, or route for review according to the semantic result.
Key terms
- Command line (CLI)
- A text-based way to run programs and work with files.
- JSON Schema
- A set of rules that describes the required shape and allowed values of JSON data.
- Structured output
- Model output constrained to a defined format that software can read reliably.
- Tool
- A function an agent can call to read information or take an allowed action.
- Tool call
- A structured request from a model to run a tool with specific input.
Tool use is the reliable path
Asking for JSON in prose and parsing it is a recurring source of syntax errors. Strict tool use is the reliable approach: define the input schema, set strict: true on the tool, and choose a tool-choice mode that requires the call. The resulting tool name and input are schema-validated, so downstream code doesn't have to repair almost-JSON.
Repairing almost-JSON with a tolerant parser is the tempting shortcut, and it is a guess. A parser that silently closes a brace or drops a stray token can silently change which field a value landed in, and nothing downstream records that a repair happened.
A non-strict tool schema guides generation but doesn't make that guarantee. Also inspect the response status: a refusal, a token limit, or any other stop reason must be handled before treating a response as a successful extraction.
Check the stop reason before you read anything out of the response:
if (response.stop_reason !== 'tool_use') {
// refusal, max_tokens, or a plain text answer — nothing was validated
return handleIncomplete(response.stop_reason);
}
const call = response.content.find((block) => block.type === 'tool_use');
const invoice = call.input; // schema-validated only on this pathif response.stop_reason != "tool_use":
# refusal, max_tokens, or a plain text answer — nothing was validated
return handle_incomplete(response.stop_reason)
call = next(b for b in response.content if b.type == "tool_use")
invoice = call.input # schema-validated only on this pathThe guarantee attaches to a tool call, not to the response. Reading input off a response that stopped for any other reason is reading a field that is not there.
The three tool_choice modes
auto— the model may call a tool, or may just answer in text. Fine when a tool is optional; useless as a structured-output guarantee.any— the model must call a tool, but chooses which. This is the setting when several extraction schemas exist and you do not know the document type in advance.- Forced,
{"type": "tool", "name": "extract_metadata"}— a specific named tool must be called. Use it when a particular extraction has to run, for instance before an enrichment step that depends on it.
What schemas do not validate
A strict schema eliminates syntax errors. It does nothing about semantic ones.
Line items that do not sum to the stated total, a value placed in the wrong field, a date that parses but is wrong — all of these are perfectly schema-valid. Validation of meaning is a separate job, and 4.4 is where it lives.
Optional fields prevent fabrication
If a field is required and the source document does not contain it, the model must still return a value. That can lead it to invent one. Mark fields optional or nullable when the source may genuinely omit them.
You've met a form that won't submit until every box is filled, including boxes that don't apply to you. You typed something anyway. A required field puts a model in that position, and it will type something too.
An empty string isn't a substitute. It's a value, so downstream code can't tell a field the source omitted from one the source left blank, and the two mean different things to anyone reconciling the record later. Absence has to be representable as absence.
Enums need the same escape hatch. Add unclear for ambiguous cases, and other paired with a detail string for categories you didn't anticipate. Here are all three moves in the properties block of one extraction tool, on a tool declared with strict: true:
"properties": {
"purchase_order": { "type": ["string", "null"] },
"category": { "enum": ["hardware", "services", "other"] },
"category_detail": { "type": "string" }
}purchase_order accepts null, so an invoice that never carried one can say so instead of inventing a number. category keeps its enum, and other paired with category_detail is where an unforeseen category lands without being forced into hardware.
Dropping the constraint and accepting free text is the other way to stop misclassification, and it costs the guarantee that made the field usable: every consumer downstream now has to interpret arbitrary strings. Keep the enum and add the escape value instead.
Without them, every unforeseen case gets forced into the nearest listed value and the data silently misrepresents the source.
Normalization belongs in the prompt
Schemas constrain shape, not formatting. If sources express dates or units inconsistently, state the normalization rules in the prompt alongside the strict schema.
tool_useJSON Schematool_choiceenums
Field note — common misconceptions
- MythThat schema compliance implies the values are right
- ActuallyA strict schema removes syntax errors only; a wrong value in the right field still validates.
- MythThat required fields improve data quality
- ActuallyA required field the source lacks forces the model to invent one; mark it optional or nullable.
- MythThat
anyand forcing a named tool are interchangeable - Actually
anyguarantees some tool is called; only forcing a named tool guarantees which one runs.
Guided review
Review this lesson as a study deck
Review the lesson's main ideas in five guided slides, then test yourself with three flashcards.
Open Task 4.3 study deckCross-domain reasoning
Connect this idea
Structured data still needs checks and sources
A schema controls format, validation checks meaning, batch IDs keep requests and results matched, and provenance records the evidence behind each result.
Applied practice
Practice this lesson in a lab
Use a related lab to create a decision, implementation or diagram, evidence record, and review.
- Lab 7 · CI review with a strict output contract
Make a review job distinguish a clean diff from malformed output, execution failure, and invalid evidence.
- Lab 8 · Structured extraction and batch evaluation
Compare extraction strategies against labeled synthetic data without hiding critical-field failures.