CClaude Cert Prep
ExplainerCCAR-P · P28 min read

Structured Output & JSON with Claude, Explained

Force the shape with tools and schemas, then validate the meaning

The short answer

To get reliable structured output from Claude, force the shape rather than requesting it: define a tool whose input schema is your target JSON, and use tool_choice to require that tool. Pair it with clear instructions. The critical trap is that schema-valid is not semantically correct — the model can emit well-formed JSON with wrong or invented values, so validate against the source, not just the shape.

The moment an LLM stops writing prose for humans and starts producing data for other software, a new requirement appears: the output must be machine-parseable, every time, in a shape your code expects. A single stray sentence of preamble, a trailing comma, or a hallucinated field can break the pipeline downstream. This is the structured output problem.

This article covers the two ways to get JSON out of Claude, why forcing the shape with a tool schema is more reliable than politely asking for it, how tool_choice guarantees you get structured data back, and — most importantly — why passing schema validation is only half the job. A response can be perfectly valid JSON and still be wrong.

Two approaches: prompted JSON vs tool-forced schema

There are two broad strategies for getting structured output. The first is prompted JSON: you ask, in natural language, for the model to reply with JSON matching a described shape. The second is tool-forced schema: you define a tool whose input_schema is your target structure and require the model to call it, so the model's arguments are your structured data.

AspectPrompted JSONTool-forced schema
How the shape is specifiedDescribed in proseDeclared as a JSON Schema
Reliability of shapeGood with care, but can driftHigh — arguments conform to the schema
Risk of extra proseModel may add preambleStructured call, no chatty wrapper
Best forSimple, low-stakes shapesProduction pipelines and nested data

Prompted JSON is quick and fine for a throwaway script. But the more your downstream code depends on the exact shape, the more you want the schema itself to be the contract — which is what tool use gives you. Check the Claude docs for the current tool-use request format, since field names and options evolve.

Forcing output with tool_choice

Defining a tool is not enough on its own — by default the model decides whether to call it. To guarantee structured output, set tool_choice to require your specific tool. Now the model cannot answer in free prose; it must return arguments that satisfy your schema. This turns 'please reply with JSON' into a structural guarantee rather than a polite request.

code
{
  "model": "claude-...",
  "tools": [
    {
      "name": "record_invoice",
      "description": "Extract structured fields from an invoice.",
      "input_schema": {
        "type": "object",
        "properties": {
          "invoice_number": { "type": "string" },
          "total_amount":   { "type": "number" },
          "currency":       { "type": "string", "enum": ["USD", "EUR", "INR"] },
          "line_items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "description": { "type": "string" },
                "amount":      { "type": "number" }
              },
              "required": ["description", "amount"]
            }
          }
        },
        "required": ["invoice_number", "total_amount", "currency"]
      }
    }
  ],
  "tool_choice": { "type": "tool", "name": "record_invoice" }
}

Reliability techniques

Forcing the shape gets you most of the way; a few habits close the rest of the gap between 'usually works' and 'safe in production.'

  • Make the schema strict: use enums, types, required arrays, and formats so fewer wrong values are even expressible.
  • Describe every field: put a clear description on each property; the model reads them, and good descriptions cut ambiguity.
  • Instruct for the unknown: give an explicit rule for missing data (for example null) so the model does not invent a plausible value.
  • Keep instructions and schema consistent: if the prose and the schema disagree, you invite drift — make them say the same thing.
  • Handle refusals and truncation: a stop for max_tokens can cut a tool call mid-object, so check stop_reason and re-request when needed.
  • Set enough output headroom: nested JSON is verbose; reserve enough output tokens for the whole structure to complete.

The trap: schema-valid is not semantically correct

This is where teams get burned. Because the JSON parses and matches the schema, it looks trustworthy — a green check from your validator. But schema validation only checks structure and types. It cannot tell you whether total_amount actually matches the invoice, whether the invoice_number was read correctly, or whether a line item was quietly invented. A confidently wrong number is still perfectly valid JSON.

QuestionSchema validation answers it?
Is this a number?Yes
Is it the right number from the source?No
Are all required fields present?Yes
Was any value hallucinated or misread?No
Does the currency enum member match the document?No

Layered validation in practice

A robust pipeline validates in layers, cheapest and most structural first, then semantic. Each layer catches a different class of failure.

  • Layer 1 — Structural: parse the JSON and validate it against the schema (types, required fields, enums). Reject or retry on failure.
  • Layer 2 — Semantic and referential: check values against the source — do the line items sum to the total? Does the invoice_number appear in the document? Are dates plausible?
  • Layer 3 — Business rules: apply domain constraints your schema cannot express, such as totals within an expected range or currency matching the vendor's country.
  • Layer 4 — Confidence and escalation: on low-confidence or failed checks, route to a human or a second-pass verification rather than silently accepting.

The point is that the forced schema handles Layer 1 for you and nothing more. Layers 2 through 4 are where correctness actually lives, and they are code you write against the source of truth — not something the model or the schema can guarantee.

Key takeaways

  • →There are two paths to structured output: prompted JSON described in prose, and a tool whose input_schema is your target structure — the tool path makes the schema the contract.
  • →Use tool_choice to require your specific tool, turning 'please reply in JSON' into a structural guarantee; read the result from the tool_use block's input, not from free text.
  • →Strict schemas (enums, types, required, descriptions) plus an explicit rule for missing data reduce the space of wrong outputs.
  • →Handle refusals and truncation: check stop_reason and reserve enough output tokens for verbose nested JSON to complete.
  • →Schema validation only proves the output is parseable and correctly shaped — it says nothing about whether the values are true.
  • →The core trap is schema-valid is not semantically correct: a hallucinated or misread value is still valid JSON.
  • →Validate in layers — structural, then semantic/referential against the source, then business rules, then human escalation — because correctness lives beyond the schema.

Now practice it

Reading builds recognition; practice builds judgment. Try these on the P2 material.

Frequently asked

Should I use prompted JSON or a forced tool schema?

For quick or low-stakes work, prompted JSON with clear instructions is fine. For anything a downstream system depends on, define a tool whose input_schema is your target shape and force it with tool_choice. The schema then becomes an enforced contract rather than a described hope.

How exactly does tool_choice force structured output?

By default the model chooses whether to call a tool. Setting tool_choice to require a specific tool removes that choice: the model must respond with a tool_use block whose input conforms to that tool's schema, so you get structured arguments instead of free prose.

If the JSON passes schema validation, is it correct?

No. Schema validation checks structure and types only — that it parses, has the required fields, and the values are the right kind. It cannot tell whether a number matches the source or whether a field was hallucinated. A confidently wrong value is still schema-valid.

How do I actually check semantic correctness?

Validate values against the source or ground truth. Use deterministic round-trip checks where possible — confirm line items sum to the total, confirm an extracted string appears in the document, confirm dates and ranges are plausible — then apply business rules and escalate low-confidence cases to a human.

What breaks structured output most often in production?

Two things: truncation, where a max_tokens stop cuts a tool call mid-object (check stop_reason and reserve output headroom), and over-trusting the schema, where valid-but-wrong values flow downstream because no one validated against the source. Design for both.

All explainers

Independent, unofficial study material from Claude Cert Prep. Not affiliated with Anthropic.