Back to Blog

Structured Outputs in the Claude Agent SDK - Getting Reliable Data From AI Agents

April 6, 20266 min readMichael Ridland

Structured Outputs in the Claude Agent SDK - Getting Reliable Data From AI Agents

If you've built anything production-grade with LLMs, you've hit the free-text problem. You ask the model to extract data, classify something, or make a decision, and it gives you a beautifully written paragraph that's completely useless to your downstream code.

Your code expects {"status": "approved", "confidence": 0.87}. The model gives you "Based on my analysis, I would classify this as likely approved with a high degree of confidence." Good luck parsing that reliably.

Structured outputs fix this. And the way the Claude Agent SDK handles them is worth understanding, because it gets several design decisions right that make the feature genuinely practical rather than just theoretically available.

What Structured Outputs Actually Do

At a basic level, structured outputs constrain the model's response to match a schema you define. You say "I want a JSON object with these fields, these types, and these constraints" and the model responds with valid JSON matching that schema. Every time.

This isn't the same as prompting the model to "please respond in JSON format" and hoping for the best. That approach works maybe 95% of the time, which sounds fine until you realise that 5% failure rate means your production system breaks every 20 requests. Structured outputs use constrained decoding at the model level, which means the output is guaranteed to match your schema.

The Claude Agent SDK makes this available through a clean interface that fits naturally into the agent loop. You define your output schema, attach it to your agent or tool call, and the response comes back as typed data you can use directly.

How It Works in Practice

The pattern is straightforward. You define a schema - typically using a JSON Schema definition or, in TypeScript, a Zod schema - and pass it as part of your agent configuration.

import { Agent } from '@anthropic-ai/agent-sdk';
import { z } from 'zod';

const sentimentSchema = z.object({
  sentiment: z.enum(['positive', 'negative', 'neutral']),
  confidence: z.number().min(0).max(1),
  key_phrases: z.array(z.string()),
  summary: z.string().max(200)
});

const agent = new Agent({
  model: 'claude-sonnet-4-5-20250929',
  system: 'Analyse customer feedback and extract sentiment data.',
  outputSchema: sentimentSchema
});

When this agent runs, the response is guaranteed to be a valid object matching that schema. sentiment will be one of the three allowed values. confidence will be a number between 0 and 1. key_phrases will be an array of strings. No parsing, no validation, no "let me try to extract the JSON from this markdown code block" nonsense.

This is a big deal for production systems. You can write your downstream code knowing exactly what shape the data will be. No try-catch blocks around JSON.parse. No regex extraction. No fallback logic for when the model decides to be chatty.

Where This Gets Really Useful

The obvious use case is data extraction - pull structured information from unstructured text. But the more interesting applications are in agent decision-making.

Routing Decisions

When an agent needs to decide what to do next, structured outputs turn a vague "what should I do?" into a concrete, machine-readable decision.

const routingSchema = z.object({
  action: z.enum(['escalate', 'respond', 'transfer', 'close']),
  department: z.string().optional(),
  priority: z.enum(['low', 'medium', 'high', 'critical']),
  reasoning: z.string()
});

The reasoning field is a nice pattern - it forces the model to explain its decision in text (useful for logging and debugging) while the actual decision fields are constrained to valid options. You get human-readable explanations and machine-parseable outputs from the same response.

Multi-Step Agent Workflows

In agentic workflows where one step feeds into the next, structured outputs are what make the chain reliable. Step one extracts data, step two classifies it, step three takes action based on the classification. If any step returns free text, the chain is fragile. Structured outputs make each handoff predictable.

Document Processing Pipelines

We've been using this pattern for document processing with several clients. Insurance claims, invoices, contracts - documents where you need to pull out specific fields reliably.

const invoiceSchema = z.object({
  vendor_name: z.string(),
  invoice_number: z.string(),
  date: z.string(),
  line_items: z.array(z.object({
    description: z.string(),
    quantity: z.number(),
    unit_price: z.number(),
    total: z.number()
  })),
  subtotal: z.number(),
  tax: z.number(),
  total: z.number(),
  currency: z.string().default('AUD')
});

Without structured outputs, you'd need to parse free-text responses and handle edge cases where the model formats numbers differently, uses different date formats, or includes explanatory text alongside the data. With structured outputs, the data comes back ready to write to a database.

Practical Considerations

A few things I've learned from using this in production that the documentation doesn't emphasise enough.

Schema design matters. A schema that's too rigid forces the model into awkward responses. A schema that's too loose defeats the purpose. Use optional() for fields that genuinely might not be present in the input. Use enums when you know the valid options. Use string fields with descriptions when the content is truly variable.

Don't over-nest. Deeply nested schemas with arrays of objects containing arrays of objects make the constrained decoding work harder and can affect response quality. Flatten where you can. If your schema is more than three levels deep, consider whether you can restructure it.

The model still needs good instructions. Structured outputs constrain the format, not the quality. A poorly prompted agent with a perfect schema will give you valid JSON containing wrong answers. Your system prompt still needs to clearly explain what each field should contain and how to handle ambiguous cases.

Performance is slightly different. Constrained decoding can add a small amount of latency compared to free-form responses. In practice, the difference is negligible for most use cases - and you save time on the parsing and validation you'd otherwise need. Net win.

Combine with tools for richer patterns. Structured outputs work alongside the tool-calling pattern in the Agent SDK. An agent can use tools to gather information (query a database, call an API, read a file) and then return structured output as its final response. The tools handle the "doing" and the structured output handles the "reporting."

What to Watch Out For

Structured outputs don't make every problem disappear.

The model can still hallucinate within the schema. If you ask it to extract an invoice number and the document doesn't contain one, the model will still give you a string for that field. It won't return null unless your schema explicitly allows it. Design your schemas with nullable() or optional() for fields that might legitimately be absent.

Error handling is different too. Instead of parsing errors (which structured outputs eliminate), you now need to think about semantic errors - responses that are valid JSON matching your schema but contain incorrect data. Confidence scores, verification steps, and human review loops are still important for high-stakes applications.

Building With Structured Outputs

If you're building AI-powered applications that need reliable data extraction, classification, or decision-making, structured outputs should be a foundational part of your architecture. They're the difference between a demo that works when you're watching and a production system that works when you're not.

Our AI agent development team uses the Claude Agent SDK extensively in production applications. If you're looking to build agents that actually work reliably - not just impressive demos - we can help with architecture, implementation, and the operational patterns that make AI systems trustworthy.

We also offer AI strategy consulting for organisations figuring out where AI agents fit in their operations. Sometimes the right answer isn't "build an agent" - it's understanding which problems are worth solving with this technology and which are better handled with simpler approaches.

For the full API reference and advanced patterns, see the Claude Agent SDK structured outputs documentation. The SDK is well-documented and the TypeScript types make integration straightforward if you're already working in that ecosystem.