Structured Output Enforcer
Prerequisites & Dependencies
- Node.js 18+ with npm or pnpm
- Mandatory packages:
npm i zod for runtime validation and type inference, or npm i jsonschema for pure JSON Schema validation
- Optional:
npm i ai-sdk or npm i openai to integrate with LLM APIs
- TypeScript for type-safe Zod schemas (highly recommended)
Execution Steps
- Define a Zod schema (or JSON Schema) that describes the expected output structure: required fields, types, enums, arrays, and nested objects
- Call the LLM with a prompt that instructs it to output JSON matching the schema (e.g.,
Output valid JSON only, matching this schema:...)
- Parse the LLM's raw response as JSON (strip markdown fences if needed)
- Validate the parsed object against the Zod schema using
z.parse(data) or schema.safeParse(data)
- If validation fails, retry with a refined prompt that includes the error details and schema excerpt
- On success, return the validated JSON object to the caller; log and discard invalid attempts after N retries
- Optionally generate TypeScript types from the Zod schema:
z.infer<typeof schema> for end-to-end type safety
// Example: Zod schema for LLM-structured output
import { z } from 'zod';
const UserProfileSchema = z.object({
name: z.string().min(1, 'Name is required'),
age: z.number().int().min(13).max(120, 'Age must be between 13 and 120'),
email: z.string().email('Invalid email address'),
role: z.enum(['admin', 'user', 'guest'], 'Role must be admin, user, or guest'),
preferences: z.object({
theme: z.enum(['light', 'dark', 'system']),
notifications: z.boolean(),
}),
});
type UserProfile = z.infer<typeof UserProfileSchema>;
// Simulated LLM output (would come from OpenAI/Anthropic API call)
const rawLLMOutput = `{
"name": "Alice",
"age": 30,
"email": "alice@example.com",
"role": "user",
"preferences": {
"theme": "dark",
"notifications": true
}
}`;
try {
const parsed = UserProfileSchema.parse(JSON.parse(rawLLMOutput));
console.log('Validated user profile:', parsed);
} catch (error) {
console.error('Validation errors:', error.errors);
}
npm i zod
npm i -D @types/zod
1---2name: structured-output-enforcer3description: Convert unstructured LLM output into validated JSON adhering to strict Zod or JSON Schema rules.4---56# Structured Output Enforcer78## Prerequisites & Dependencies9- Node.js 18+ with npm or pnpm10- Mandatory packages: `npm i zod` for runtime validation and type inference, or `npm i jsonschema` for pure JSON Schema validation11- Optional: `npm i ai-sdk` or `npm i openai` to integrate with LLM APIs12- TypeScript for type-safe Zod schemas (highly recommended)1314## Execution Steps151. Define a Zod schema (or JSON Schema) that describes the expected output structure: required fields, types, enums, arrays, and nested objects162. Call the LLM with a prompt that instructs it to output JSON matching the schema (e.g., `Output valid JSON only, matching this schema:...`)173. Parse the LLM's raw response as JSON (strip markdown fences if needed)184. Validate the parsed object against the Zod schema using `z.parse(data)` or `schema.safeParse(data)`195. If validation fails, retry with a refined prompt that includes the error details and schema excerpt206. On success, return the validated JSON object to the caller; log and discard invalid attempts after N retries217. Optionally generate TypeScript types from the Zod schema: `z.infer<typeof schema>` for end-to-end type safety2223```typescript24// Example: Zod schema for LLM-structured output25import { z } from 'zod';2627const UserProfileSchema = z.object({28 name: z.string().min(1, 'Name is required'),29 age: z.number().int().min(13).max(120, 'Age must be between 13 and 120'),30 email: z.string().email('Invalid email address'),31 role: z.enum(['admin', 'user', 'guest'], 'Role must be admin, user, or guest'),32 preferences: z.object({33 theme: z.enum(['light', 'dark', 'system']),34 notifications: z.boolean(),35 }),36});3738type UserProfile = z.infer<typeof UserProfileSchema>;3940// Simulated LLM output (would come from OpenAI/Anthropic API call)41const rawLLMOutput = `{42 "name": "Alice",43 "age": 30,44 "email": "alice@example.com",45 "role": "user",46 "preferences": {47 "theme": "dark",48 "notifications": true49 }50}`;5152try {53 const parsed = UserProfileSchema.parse(JSON.parse(rawLLMOutput));54 console.log('Validated user profile:', parsed);55} catch (error) {56 console.error('Validation errors:', error.errors);57}58```5960```bash61npm i zod62npm i -D @types/zod63```