Summary

Structured Output prompting ensures LLM responses conform to predefined schemas or formats. By specifying output structures (JSON, XML, specific formats), outputs become machine-readable and directly usable in downstream systems. This technique reduces parsing errors and enables reliable integration with APIs and databases.

Common formats

  • JSON: API responses, data structures
  • Markdown: Documentation, formatted text
  • Tables: Tabular data presentation
  • Code blocks: Programming language output

Implementation approaches

  1. Explicit instruction: Describe format in natural language
  2. Schema specification: Provide JSON schema or type definition
  3. Few-shot examples: Show desired output format
  4. Constrained decoding: Use API-level format controls

Validation checklist

  • Schema matches actual output
  • Required fields are present
  • Type constraints are respected
  • Edge cases are handled
  • Error recovery is planned

Build This Pattern

Copy this prompt and paste it into Claude Code, OpenCode, Codex, or Cursor to implement this pattern.

Build a structured output system for LLMs with schema validation. ROLE: You are a type-safe output system that constrains LLM outputs to valid JSON matching defined schemas, with validation and retry logic. CONSTRAINTS: - Use Zod for schema definition and runtime validation - Support native structured output (response_format) where available - Fallback to JSON mode with post-generation validation - Maximum 2 retries on validation failure; inject error context into prompt - Handle nested objects up to configurable depth (default 5) TOOL CALLING: - Use function calling for: define_schema(schema_data), validate_output(output, schema_id?), generate_structured_output(prompt, schema_id, mode?), get_validation_stats(schema_id?) - Each tool returns structured JSON with schema data and metadata STRUCTURED OUTPUT: - Schema definition must return JSON: { schema_id: string, name: string, schema: Record<string, any>, zod_string: string, created_at: string, validation_count: number } - Validation result must return JSON: { valid: boolean, output: any, errors: [{ path: string, message: string, received: string }], schema_id: string, validation_time_ms: number } - Structured generation must return JSON: { output: any, schema_id: string, mode: 'native' | 'json_fallback', validated: boolean, attempts: number, generation_time_ms: number } - Validation stats must return JSON: { schema_id: string, total_validations: number, success_rate: number, avg_validation_time_ms: number, common_errors: [{ error: string, count: number }] } CHAIN OF THOUGHT: - Schema definition: define structure → convert to Zod → generate TypeScript types → store - Output generation: select mode (native/fallback) → generate output → validate against schema - Validation: parse output → check against schema → collect errors → return structured result - Retry: if validation fails → inject error context → regenerate → validate again FEW-SHOT EXAMPLES: Schema: { name: 'User', schema: { name: 'string', age: 'number', email: 'string (email format)' } } Zod: z.object({ name: z.string(), age: z.number().positive(), email: z.string().email() }) Output: { name: 'John Doe', age: 30, email: 'john@example.com' } Validation: { valid: true, output: { name: 'John Doe', age: 30, email: 'john@example.com' }, errors: [] } Invalid Output: { name: 'John', age: -5, email: 'not-an-email' } Validation: { valid: false, errors: [{ path: 'age', message: 'Number must be positive', received: '-5' }, { path: 'email', message: 'Invalid email', received: 'not-an-email' }] } EVALUATION CRITERIA: - Validation accuracy: percentage of outputs correctly validated against schema - Retry success rate: percentage of retries that produce valid output - Schema coverage: percentage of common data types supported - Error clarity: percentage of validation errors that help LLM correct its output The system should: 1) Define schemas using Zod for runtime validation and TypeScript type inference, 2) Implement schema-to-prompt converter that generates natural language descriptions of expected output format from Zod schema, 3) Support multiple output modes: native structured output via response_format parameter where available, and JSON mode with post-generation validation as fallback, 4) Include validation pipeline that parses LLM output against schema and provides friendly error messages pointing to specific schema violations, 5) If validation fails, retry with error context injected into prompt so LLM can fix output (max 2 retries), 6) If LLM repeatedly outputs invalid JSON, try structured output parameter first, then fall back to explicit JSON instruction, 7) Handle nested objects up to configurable depth, 8) Support arrays with min-max length constraints, enums with descriptions, optional fields with defaults, and discriminated unions, 9) Handle very large outputs by streaming validation.