Back to course overview
Module 2Structured prompting 12 min

Output schemas

Defining the shape of the answer before you ask: fields, types, enums, and the discipline that makes output machine-usable.

Reading JSON in 90 seconds

You'll read JSON in this course, not write code. Here's all you need: braces { } group a set of fields; each field is "name": value; commas separate fields; quotes wrap text values. And when a schema writes "A" | "B" | "C", the | means "one of these values" — it's a description of the allowed choices, not something the model literally prints. That's the whole notation. When you see a schema below, you're reading a shape to copy, not a program to run.

So far the model answers in prose, and a human reads it. Production systems are different: software reads the output — to route the email, fill the ticket, update the sheet. Software can't parse 'well, this one feels like a complaint'. It needs a contract. An output schema is that contract: the exact fields, their types, and their allowed values, declared in advance.

Designing the schema — decisions, not syntax

  • Enumerate everything enumerable. category isn't 'a string' — it's one of five exact values. Enums turn infinite creative answers into a checkable multiple-choice.
  • Type every field. urgency is an enum, order_id is a string-or-null, damage_mentioned is a boolean. Types are assertions you can verify in code.
  • Make uncertainty a field, not a vibe. Add confidence: HIGH | MEDIUM | LOW and a rule for when to use LOW. Module 6 routes LOW to a human.
  • Every field earns its place. Each one costs tokens and adds a failure surface. If nothing downstream reads it, delete it.
triage-output-schema.txttext
OUTPUT
Return ONLY a JSON object with exactly these fields:
{
  "category": "COMPLAINT" | "INQUIRY" | "RETURN_REQUEST" | "ORDER_STATUS" | "OTHER",
  "urgency": "LOW" | "NORMAL" | "HIGH",
  "confidence": "HIGH" | "MEDIUM" | "LOW",
  "order_id": string | null,        // exactly as written in the email, else null
  "damage_mentioned": boolean,
  "summary": string,                 // one sentence, max 25 words
  "suggested_reply": string | null   // null when category is OTHER
}
No text before or after the JSON. If a field is unknown, use null — never invent.

Read the last line again: 'if unknown, use null — never invent.' Without an explicit escape hatch, a schema pressures the model to hallucinate — it will produce an order ID because the contract demanded one. Every schema needs a legal way to say 'I don't know'. This one line prevents more production incidents than any other in the file.

Native structured output

Most model APIs now accept a formal JSON Schema and constrain generation to match ('structured outputs' / 'JSON mode'). Use it when you build for real — but everything in this lesson still applies, because the API enforces shape, not sense. The enum can be valid while the classification is wrong; only your rules, examples, and evals fix that.

Prompt to try

Here's a description of what my workflow needs from each processed document: [describe]. Design the output schema: field names, types, enums where possible, null policy, and one comment per field saying who consumes it downstream. Flag any field that seems like it would invite hallucination and propose a safer design.