Skip to main content
An agent that answers in prose is hard to build on. You end up parsing sentences, and the parsing breaks the first time the model phrases something differently. Tell the agent what shape you want instead. Describe it as a Pydantic model, and result.final_output comes back as an instance of that model — already validated, with the right types.

Ask for a shape

No parsing, no json.loads, no prompt asking nicely for JSON. The schema goes to the provider, the provider constrains the model to it, and Agentor validates what comes back before handing it to you.

Nest and make things optional

Models can contain other models, and fields can be optional. Both survive the round trip:
An optional field still appears in every response — the model fills it with null rather than leaving it out. That is what the provider’s strict mode requires, and Pydantic turns it back into None.

Open-ended dictionaries are not supported

A field like dict[str, int] accepts any keys at all, and strict structured output has no way to describe that. Agentor rejects it when you build the agent, rather than letting the provider reject it mid-run:
Both fixes in the message work. Name the keys if you know them:
Or use a list of pairs if you do not:

When output does not match

If the model returns something that fails validation, the run raises rather than handing you a half-filled object:
The raw text is included so you can see what the model actually said. Clearer field names and an instructions line describing what each field means usually fix it.
output_type must be a Pydantic BaseModel subclass. Passing a plain dict, a dataclass, or a TypedDict raises TypeError: output_type must be a pydantic BaseModel.

Tools and structured output together

They compose. The agent calls whatever tools it needs, and shapes only the final answer:

Streaming returns text, not the object

stream_chat() yields the model’s raw JSON as it arrives, because there is no object to hand over until the last token lands:
Use agent.run() or await agent.arun() when you want the parsed object.

Next steps

Durable runs

Save a run so another process can finish it after a crash.

Model providers

Structured output works against any OpenAI-compatible provider.
Last modified on July 29, 2026