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
Explicit instruction: Describe format in natural language
Schema specification: Provide JSON schema or type definition
Few-shot examples: Show desired output format
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.