Guides

Structured Output

Generating schema-validated, typed final answers using Zod.

When building production applications, you often need the model's final response to be a structured object (like JSON) rather than a paragraph of free-form text. Chai AI SDK provides first-class support for schema-validated structured output.


Defining Structured Output

Chai AI SDK integrates with Zod to validate and type-infer final answers. By passing an outputSchema to .generate(), TypeScript automatically types the returning result.output:

import { Agent } from "chai-ai";
import { google } from "@chai-ai/google";
import { z } from "zod";

const personSchema = z.object({
  name: z.string(),
  age: z.number(),
  profession: z.string(),
  city: z.string(),
});

const agent = new Agent({
  name: "extractor-agent",
  instructions: "Extract details about individuals mentioned in the prompt.",
  model: google("gemini-3.1-pro-preview"),
});

const result = await agent.generate({
  prompt: "John is a 34-year-old software engineer from Austin.",
  outputSchema: personSchema,
});

// result.output is fully typed as:
// { name: string; age: number; profession: string; city: string }
console.log(result.output.name); // "John"
console.log(result.output.age);  // 34

Why Client-Side Validation & Repair?

Instead of relying on vendor-specific native JSON options (which vary wildly in capabilities and requirements), Chai AI SDK implements validation and auto-repair entirely inside the SDK:

  • Provider Simplicity: Provider adapter packages (@chai-ai/google, @chai-ai/openai, @chai-ai/anthropic) stay focused entirely on wire-format translation.
  • Resilience: If the model outputs invalid JSON or deviates from the schema, the SDK intercepts the response, extracts the parsing error, and prompts the model to correct it in a subsequent turn.
  • Unified Retry Budget: Auto-repair turns consume the active agent's maxSteps budget exactly like a tool round trip does. If it never gets it right within the budget, it throws a standard AgentError.

Helper Mechanics

Two main internal functions drive this capability (located in packages/ai/src/structured-output.ts):

  1. outputInstructions(schema): Converts the Zod schema to standard JSON Schema and appends explicit instructions to the system prompt telling the model to respond only with the JSON representing that schema.
  2. parseStructuredOutput(text, schema): Strips markdown code fences (like ```json), parses the JSON, and calls schema.safeParse(). It returns { success: true, data } or { success: false, error: string } without throwing errors.

Sequence Trace

Successful Parse (No Repair Needed)

agent.generate({ prompt, outputSchema })
  → Append system prompt instructions: "Respond again with ONLY corrected JSON matching the schema..."
  → Call Model
  ← Model returns JSON text: '{"name":"John", "age":34, ...}'
  → parseStructuredOutput() → { success: true, data: { name: "John", age: 34, ... } }
  ← Returns { text, output: { name: "John", age: 34, ... } }

Auto-Repair Cycle

If the model outputs invalid JSON first, the SDK triggers a repair step:

agent.generate({ prompt, outputSchema })
  → Call Model
  ← Model returns invalid JSON text: "Sure! Here is the JSON: {...}"
  → parseStructuredOutput() → { success: false, error: "Failed to parse JSON..." }
  → Push invalid response as assistant message
  → Push corrective prompt as user message: "Your previous response was invalid: <error>. Respond again with ONLY corrected JSON."
  → Re-call Model (Iteration 2 of maxSteps)
  ← Model returns valid JSON text: '{"name":"John", "age":34, ...}'
  → parseStructuredOutput() → { success: true, data: { name: "John", age: 34, ... } }
  ← Returns { text, output: { name: "John", age: 34, ... } }

On this page