Lesson 11 · Domain 4 — Prompt Engineering & Structured Output (20% of exam)

Structured Output & Validation Loops

Explicit criteria and few-shot examples shape what Claude decides. This lesson is about guaranteeing the shape of what comes back — and knowing exactly where that guarantee stops.

tool_use + JSON schema: what it actually guarantees

Defining an extraction tool with an input_schema and reading the result out of the tool_use block is the reliable way to get schema-compliant structured output. It eliminates an entire class of failure — malformed JSON, missing quotes, trailing commas — that used to require regex cleanup on free-text output.

It does not eliminate semantic errors. Line items that don't sum to the stated total, a value landing in the wrong field, a category that's technically valid JSON but factually wrong — none of that is caught by schema validation. The schema checks shape, not truth.

const invoiceSchema = {
  name: "extract_invoice",
  input_schema: {
    type: "object",
    properties: {
      total: { type: "number" },
      lineItems: {
        type: "array",
        items: {
          type: "object",
          properties: {
            description: { type: "string" },
            amount: { type: "number" },
          },
        },
      },
      vendorTaxId: { type: ["string", "null"] }, // nullable — don't fabricate
      category: {
        type: "string",
        enum: ["utilities", "supplies", "travel", "other"],
      },
    },
    required: ["total", "lineItems", "category"],
  },
};

Two schema-design habits worth internalizing: make a field nullable/optional rather than required when the source document genuinely might not contain that information — a required field the model can't fill honestly gets fabricated to satisfy the schema instead. And give enum fields an "other" escape valve (paired with a free-text detail field) plus an "unclear" value for genuinely ambiguous cases, so the model isn't forced into a wrong bucket just because none of the fixed options fit.

Validation-retry: works for format, not for absence

When a semantic validation error is caught downstream (totals don't reconcile, a required relationship is violated), appending the specific error back into a follow-up request — original document, the failed extraction, and the exact validation error — reliably guides the model to self-correct. This is retry-with-error-feedback.

It has one hard limit: retrying cannot produce information that was never in the source document to begin with. If a required field is simply absent from what you gave the model, no amount of retrying fixes that — the fix there is making the field nullable, not looping harder.

A useful diagnostic habit: have extractions include a detected_pattern field describing what in the text triggered a given finding. When developers start dismissing findings, this field lets you analyze why systematically instead of guessing.

Two failure modes, two different fixes
Structural/format error (bad JSON, wrong type) → tool_use + schema prevents it outright. Semantic error (values don't reconcile, wrong field) → retry-with-error-feedback can catch and correct it. Missing information (the fact isn't in the source at all) → neither fixes this; the schema needs to allow "I don't know" instead of forcing an answer.

Why this matters beyond the exam

Primary source: Anthropic's Claude API docs cover tool use and JSON schema enforcement directly — this lesson compresses Task Statements 4.3 and 4.4.

Check your understanding

Q1. You enforce output with tool_use and a strict JSON schema. Line items sometimes don't sum to the stated total. What does this tell you?
Q2. A required schema field can't be found anywhere in a given source document. What's the safest schema design?
Q3. Retry-with-error-feedback fixes a validation failure. When does this approach NOT work?

Want to design a schema for a real extraction task you have in mind? Describe the source documents and I'll help you think through required vs. nullable fields.