Structured Outputs: AI as JSON API for Decisionmaking
Separating probabilistic thinking from deterministic execution
The Pattern
Instead of letting AI generate whatever it wants (freeform text, code, mixed formats), you constrain it to return valid JSON matching a predefined schema.
Then your deterministic code parses that JSON and executes the appropriate actions. This is what OpenAI calls "structured outputs"
Why It Works
Separation of Concerns
- AI does probabilistic thinking - Understanding intent, making decisions, reasoning about what should happen
- Code does deterministic execution - Parsing JSON, updating files, running commands, enforcing constraints
AI is unreliable at precise syntax at scale but excellent at precision semantic understanding. Code is terrible at understanding intent but perfect at following rules.
Structured outputs let each do what it's good at.
Predictable Failures
When AI returns freeform text, failures are messy: hallucinated code, syntax errors, missing edge cases, broken formatting. Every failure mode is different.
With structured outputs, there are only two failure modes:
- Invalid JSON - Easy to detect, easy to retry
- Wrong semantic decision - AI understood the format but chose the wrong action
Both are recoverable. Invalid JSON gets caught immediately. Wrong decisions are visible in the structured data and can be fixed with better prompts or manual overrides.
Real-World Example
Without Structured Outputs
Prompt: "Create a calendar event for lunch with Sarah tomorrow at noon"
AI returns freeform text:
I'll create a calendar event for you:
Event: Lunch with Sarah
Date: Tomorrow at 12:00 PM
Location: TBD
Would you like me to set a reminder?Now you need to parse natural language, extract the data, guess at timezone, handle the question about reminders, convert "tomorrow" to an actual date...
With Structured Outputs
Same prompt, but AI returns JSON:
{
"action": "create_event",
"event": {
"title": "Lunch with Sarah",
"start": "2026-01-28T12:00:00Z",
"duration_minutes": 60,
"attendees": ["sarah@example.com"]
},
"confirmation": "Created lunch event for tomorrow at noon"
}Your code parses this trivially:
const response = await ai.chat(prompt, { schema: calendarEventSchema });
const action = response.action;
if (action === 'create_event') {
await calendar.createEvent(response.event);
}No guessing, no parsing natural language, no edge cases. Just data in, actions out.
The AI as API Mental Model
When you frame it as "AI as API", the pattern becomes obvious:
- Input: Natural language (flexible, human-friendly)
- Processing: AI reasoning (probabilistic, semantic)
- Output: Structured JSON (predictable, machine-friendly)
- Execution: Deterministic code (reliable, testable)
You wouldn't call a REST API and expect it to return freeform text that you parse manually. You expect JSON matching a schema. AI should work the same way.
Benefits at Scale
Composability
Once AI returns structured data, you can pipe it to other systems:
- Store it in a database
- Send it to another API
- Transform it with standard JSON tools
- Validate it against schemas
- Cache it for replay/debugging
Reliability
Deterministic execution means you can test and verify behavior:
- Write unit tests against the JSON schema
- Validate constraints before execution
- Roll back changes if validation fails
- Audit all actions through structured logs
Iteration Speed
When AI returns structured data, debugging is straightforward:
- Inspect the JSON to see exactly what AI decided
- Modify prompts to change AI's decisions
- Override specific fields if needed
- Replay the same JSON to reproduce issues
Implementation Notes
Schema Definition
Define schemas using TypeScript types or JSON Schema:
interface CalendarEvent {
action: 'create_event' | 'update_event' | 'delete_event';
event: {
title: string;
start: string; // ISO 8601
duration_minutes: number;
attendees?: string[];
};
confirmation: string;
}Prompt Engineering
Include the schema in your system prompt:
You are a calendar assistant. Always respond with valid JSON matching this schema:
{
"action": "create_event" | "update_event" | "delete_event",
"event": {
"title": string,
"start": ISO 8601 date,
"duration_minutes": number,
"attendees": [emails]
},
"confirmation": string
}
Do not include any text outside the JSON.Validation
Always validate before execution:
const response = await ai.chat(prompt);
const parsed = JSON.parse(response);
// Validate against schema
if (!isValidCalendarEvent(parsed)) {
throw new Error('Invalid response from AI');
}
// Execute only if valid
await executeCalendarAction(parsed);When Not to Use This
Structured outputs aren't always the answer:
- Creative content generation - When you want natural prose, not data
- Exploratory conversations - When schema would constrain thinking
- One-off tasks - Overhead of defining schemas isn't worth it
But for building reliable AI-powered systems that integrate with code, structured outputs are essential.
The Bigger Picture
Structured outputs are part of a larger philosophy: use AI for what it's good at, use code for what it's good at.
AI excels at understanding messy human intent and making semantic decisions. Code excels at precise execution and enforcing constraints.
The structured outputs pattern puts both in their ideal roles. That's why it works.
See also: Work at the Speed of Thought for how this fits into the broader workflow optimization pattern.