--- title: "Structured Outputs from Agents" aliases: [structured-output, agent-json-output, validated-json-output] tags: [agent-sdk, structured-outputs, zod, pydantic, json-schema, typescript, python] sources: [raw/Get structured output from agents.md] created: 2026-04-17 updated: 2026-04-17 --- # Structured Outputs from Agents Return validated, typed JSON from an agent workflow instead of free-form text. The agent still runs its full tool loop; structured output is enforced at the end. ## Why Use It - Agents return free-form text by default — usable for chat, not for app logic - Structured outputs give you typed data ready for databases, UIs, APIs - SDK validates output against your schema; re-prompts on mismatch - If retries exceed the limit, result is an error (not bad data) ## Quick Start Pass `outputFormat` (TS) / `output_format` (Python) to `query()`: ```typescript import { query } from "@anthropic-ai/claude-agent-sdk"; const schema = { type: "object", properties: { company_name: { type: "string" }, founded_year: { type: "number" }, headquarters: { type: "string" } }, required: ["company_name"] }; for await (const message of query({ prompt: "Research Anthropic and provide key company information", options: { outputFormat: { type: "json_schema", schema } } })) { if (message.type === "result" && message.subtype === "success" && message.structured_output) { console.log(message.structured_output); // { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" } } } ``` Validated data is on `message.structured_output` in the `result` message. ## Type-Safe Schemas: Zod (TS) and Pydantic (Python) Instead of hand-writing JSON Schema, use library types — they generate the schema and give you full autocomplete + runtime validation. **TypeScript with Zod:** ```typescript import { z } from "zod"; const FeaturePlan = z.object({ feature_name: z.string(), summary: z.string(), steps: z.array(z.object({ step_number: z.number(), description: z.string(), estimated_complexity: z.enum(["low", "medium", "high"]) })), risks: z.array(z.string()) }); const schema = z.toJSONSchema(FeaturePlan); // generate JSON Schema // pass schema to outputFormat, then: const parsed = FeaturePlan.safeParse(message.structured_output); if (parsed.success) { const plan = parsed.data; // fully typed FeaturePlan } ``` **Benefits over raw JSON Schema:** - Full type inference / type hints - Runtime validation with `safeParse()` or `model_validate()` - Better error messages - Composable, reusable schemas ## outputFormat Config ```typescript outputFormat: { type: "json_schema", // only supported type schema: } ``` Supported JSON Schema features: `object`, `array`, `string`, `number`, `boolean`, `null`, `enum`, `const`, `required`, nested objects, `$ref`. ## Multi-Step Tool Use + Structured Output The agent freely uses tools (Grep, Bash, etc.) during execution. Structured output applies only to the **final result**, not individual tool calls. Example — TODO tracker agent: - Agent uses `Grep` to find TODO comments, `Bash` for git blame - Returns a single validated object with `todos[]` and `total_count` - Optional fields (`author`, `date`) handle cases where git info is unavailable ```typescript const todoSchema = { type: "object", properties: { todos: { type: "array", items: { type: "object", properties: { text: { type: "string" }, file: { type: "string" }, line: { type: "number" }, author: { type: "string" }, // optional date: { type: "string" } // optional }, required: ["text", "file", "line"] } }, total_count: { type: "number" } }, required: ["todos", "total_count"] }; ``` ## Error Handling Check `message.subtype` on the `result` message: | Subtype | Meaning | |---------|---------| | `success` | Output validated successfully | | `error_max_structured_output_retries` | Agent failed to produce valid output after retries | ```typescript if (msg.type === "result") { if (msg.subtype === "success" && msg.structured_output) { // use data } else if (msg.subtype === "error_max_structured_output_retries") { // retry with simpler prompt, fall back to unstructured, etc. } } ``` ## Tips for Avoiding Errors - **Keep schemas focused** — deeply nested + many required fields = harder to satisfy - **Make fields optional** when the task might not surface that data - **Write clear prompts** — ambiguity makes output unpredictable ## Key Takeaways - Pass `outputFormat: { type: "json_schema", schema }` to `query()` to get validated JSON back - Use **Zod** (TS) or **Pydantic** (Python) to generate the schema and get strong types - The agent runs its full tool loop freely; structured output is enforced only at the end - Validation failures auto-retry; persistent failure → `error_max_structured_output_retries` - Optional fields are your friend — don't require data the agent might not find - For single-turn requests without tool use, the Claude API has its own structured outputs endpoint ## Related - [[wiki/agent-sdk/typescript-api-reference|TypeScript API Reference]] — full `query()` signature and options - [[wiki/agent-sdk/python-api-reference|Python API Reference]] — Python `query()` equivalent - [[wiki/agent-sdk/overview|Agent SDK Overview]] — built-in tools, features, quick orientation - [[wiki/agent-sdk/mcp-integration|MCP Integration]] — adding custom tools the agent can call during its loop ## Sources - `raw/Get structured output from agents.md` — official Agent SDK docs on structured outputs