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); // 34Why 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
maxStepsbudget exactly like a tool round trip does. If it never gets it right within the budget, it throws a standardAgentError.
Helper Mechanics
Two main internal functions drive this capability (located in packages/ai/src/structured-output.ts):
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.parseStructuredOutput(text, schema): Strips markdown code fences (like```json), parses the JSON, and callsschema.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, ... } }