5.6 KiB
| title | aliases | tags | sources | created | updated | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Structured Outputs from Agents |
|
|
|
2026-04-17 | 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():
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:
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()ormodel_validate() - Better error messages
- Composable, reusable schemas
outputFormat Config
outputFormat: {
type: "json_schema", // only supported type
schema: <JSON Schema object>
}
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
Grepto find TODO comments,Bashfor git blame - Returns a single validated object with
todos[]andtotal_count - Optional fields (
author,date) handle cases where git info is unavailable
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 |
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 }toquery()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 — full
query()signature and options - wiki/agent-sdk/python-api-reference — Python
query()equivalent - wiki/agent-sdk/overview — built-in tools, features, quick orientation
- wiki/agent-sdk/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