# What are structured outputs in an LLM API?

A setting that makes a model's answer follow a JSON schema you give it, so your code can read fields such as a category or an order number without parsing free text.

- Page: https://tecyfy.com/concepts/structured-output
- Subject: How AI works (https://tecyfy.com/concepts)
- Level: intermediate
- Also called: Structured Outputs, JSON Mode, JSON Schema Output

Ask a model to "reply in JSON" and it usually will. Usually is the problem. Now and then it wraps the JSON in a sentence, drops a field or invents one, and the line of code that reads `result["category"]` fails in production. Structured outputs remove that gap: you send a JSON schema with the request, and the model's answer is made to fit it.

## How it works

A model writes one [Token](https://tecyfy.com/concepts/token) at a time, choosing from every token it knows. With structured outputs, the API turns your schema into a grammar and, at each step, only lets the model pick tokens that keep the answer valid against it. This is called constrained decoding. The model cannot open a field your schema does not have or close the object before a required field is written, because those tokens are not on offer.

That is why it is stronger than an instruction in the [System Prompt](https://tecyfy.com/concepts/system-prompt). An instruction asks; the grammar enforces. It is also stronger than the older "JSON mode", which only promised valid JSON, not your fields.

## What it looks like in code

In the Claude API you pass the schema in `output_config`, or in Python you give the SDK a Pydantic class and it builds the schema for you:

```python
from pydantic import BaseModel
import anthropic

class Ticket(BaseModel):
    category: str
    order_id: str | None

client = anthropic.Anthropic()
response = client.messages.parse(
    model="claude-opus-5-5",
    max_tokens=4000,
    messages=[{"role": "user", "content": "Where is my parcel? Order 88231."}],
    output_format=Ticket,
)
print(response.parsed_output.order_id)
```

OpenAI's Responses API does the same with `text.format` set to a strict JSON schema, or `client.responses.parse` with a Pydantic class.

## What it does not guarantee

The shape is guaranteed. The content is not. A schema can force a `category` field, but nothing in it makes the category right, so you still check answers with an eval set. 3 more things sit outside the guarantee:

- **A refusal.** If the model declines, the answer is a refusal, not your object. Check for it before you read fields.
- **Running out of room.** If the answer hits `max_tokens`, it stops mid-object. Check the stop reason, and leave room in `max_tokens`.
- **A schema the grammar cannot express.** Limits such as a minimum number or a maximum length are not enforced, so validate those in your own code. Recursive schemas are not supported at all.

In the Python SDK, a refusal or a cut-off answer makes `messages.parse` raise a validation error during the call, before you can read the stop reason. Catch it, or send the schema with `messages.create` and `output_config`, check that the stop reason is `end_turn`, and validate the text yourself.

The first request with a new schema is slower, because the grammar is compiled and then cached for 24 hours. A schema that changes on every request pays that cost every time.

## Structured outputs or tools

If you want an answer in a fixed shape, use structured outputs. If you want the model to decide whether to call a function, give it a tool with a [Function Schema](https://tecyfy.com/concepts/function-schema); strict tool use applies the same grammar to the tool's inputs. An app can use both: tools while the model works, a schema for the final answer.

## Related

- [JSON](https://tecyfy.com/concepts#json): JavaScript Object Notation - a lightweight data interchange format
- [Function Calling](https://tecyfy.com/concepts/function-calling): The developer's name for tool use. The model replies with the name of a function and its arguments in a fixed format, and your code runs it.
- [Function Schema](https://tecyfy.com/concepts/function-schema): The description of a tool that a model reads before calling it, its name, what it does and a JSON Schema of its arguments. The model fills in the arguments; your code checks them and runs the function.
- [Tool Use](https://tecyfy.com/concepts/tool-use): Giving a model a list of things it can ask to have done, such as search the web or read a file. The model asks; the program around it does the work and hands back the result.
- [System Prompt](https://tecyfy.com/concepts/system-prompt): Instructions the builder of an AI app gives the model before you type anything. It sets the role, the tone and the rules, and it outranks what users say.

## Sources

- [Structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)
- [Structured model outputs](https://developers.openai.com/api/docs/guides/structured-outputs)
- [Anthropic Python SDK](https://github.com/anthropics/anthropic-sdk-python)
