π―
Why Structure Matters
LLMs naturally generate unstructured text. But production systems
need predictable, typed, validated outputs that
can trigger downstream actions, integrate with APIs, populate
databases, and flow through software pipelines. Structured outputs
transform agents from conversational tools into reliable system
components.
β Unstructured Problem
Agent says "Create a high-priority ticket for John about the
login bug." How does your system parse this? What if it says
"urgent" instead of "high"?
β
Structured Solution
Agent outputs: {"assignee": "john@company.com", "priority":
"high", "category": "bug", "title": "Login issue"}. Perfect
for API calls!
β Unstructured Problem
"The meeting should probably be next Tuesday around 2pm with
Sarah and Mike." Ambiguous, unparseable.
β
Structured Solution
{"date": "2025-10-28", "time": "14:00", "duration_minutes":
60, "attendees": ["sarah@co", "mike@co"]}. Calendar API ready!
π§
Pydantic: Type-Safe Output Validation
Simple Schema
Basic type validation with required fields
from pydantic import BaseModel
class TicketOutput(BaseModel):
title: str
priority: str # high, medium, low
assignee: str
estimated_hours: int
# Validates types automatically
ticket = TicketOutput(**llm_output)
Advanced Validation
Constraints, enums, and custom validators
from pydantic import BaseModel, validator
from typing import List
from enum import Enum
class Priority(Enum):
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
class Ticket(BaseModel):
title: str
priority: Priority
tags: List[str]
hours: int
@validator('hours')
def check_hours(cls, v):
if v < 0 or v > 100:
raise ValueError('Invalid hours')
return v
Nested Structures
Complex hierarchical data models
class Action(BaseModel):
action_type: str
owner: str
deadline: str
class MeetingSummary(BaseModel):
title: str
date: str
attendees: List[str]
action_items: List[Action]
key_decisions: List[str]
# Validates entire nested structure
summary = MeetingSummary(**llm_output)
Error Handling
Graceful validation failure management
from pydantic import ValidationError
try:
ticket = TicketOutput(**llm_output)
# Success: use validated ticket
create_ticket_in_system(ticket)
except ValidationError as e:
# Validation failed
print(f"Errors: {e.errors()}")
# Ask LLM to try again with error details
retry_with_feedback(e.errors())
π Structured Output Generation Flow
1
Define Schema
Create Pydantic model with required fields, types, and
constraints
2
Provide to LLM
Send schema as JSON format instruction via function calling or
system prompt
3
Validate Output
Parse LLM response through Pydantic model to check types and
constraints
4
Retry if Failed
If validation fails, provide error details to LLM and request
corrected output