12 Structured Output
Get typed, validated responses instead of raw strings.
Note
Code Reference: code/v0.9/src/agentsilex/
agent.pyrunner.py
12.1 The Problem
By default, LLMs return plain text:
result = runner.run(agent, "What's the weather in Tokyo?")
print(result.final_output)
# "The weather in Tokyo is currently 22°C with partly cloudy skies
# and 65% humidity."But you often need structured data:
# What you want:
result.final_output.temperature # 22.0
result.final_output.condition # "partly cloudy"
result.final_output.humidity # 65Parsing free-form text is fragile. Regex breaks. JSON extraction fails on edge cases.
12.2 The Solution
Define a Pydantic model and pass it as output_type:
from pydantic import BaseModel
from agentsilex import Agent, Runner, Session
class WeatherReport(BaseModel):
city: str
temperature: float
condition: str
humidity: int
agent = Agent(
name="Weather Reporter",
model="gemini/gemini-2.0-flash",
instructions="You are a weather reporter. Respond with realistic weather data.",
output_type=WeatherReport, # ← Specify output type
)
session = Session()
result = Runner(session).run(agent, "What's the weather in Tokyo?")
# result.final_output is now a WeatherReport instance
print(f"City: {result.final_output.city}") # Tokyo
print(f"Temperature: {result.final_output.temperature}°C") # 22.0
print(f"Condition: {result.final_output.condition}") # partly cloudy
print(f"Humidity: {result.final_output.humidity}%") # 65
print(type(result.final_output)) # <class 'WeatherReport'>12.3 How It Works
12.3.1 Agent Changes
The Agent class accepts an optional output_type:
class Agent:
def __init__(
self,
name: str,
model: Any,
instructions: str,
tools: List[FunctionTool] | None = None,
handoffs: List["Agent"] | None = None,
output_type: Type[BaseModel] | None = None, # ← New
):
# ...
self.output_type = output_type12.3.2 Runner Changes
The Runner passes output_type to LiteLLM and parses the response:
# In Runner.run()
response = completion(
model=current_agent.model,
messages=complete_dialogs,
tools=tools_spec if tools_spec else None,
response_format=current_agent.output_type, # ← Pass to LLM
)
# When returning the result:
if current_agent.output_type:
return RunResult(
final_output=current_agent.output_type.model_validate_json(
response_message.content
)
)
else:
return RunResult(
final_output=response_message.content,
)The magic happens in two places:
response_format=output_type— LiteLLM tells the LLM to respond in JSON matching the schemamodel_validate_json()— Pydantic parses and validates the JSON response
12.4 More Examples
12.4.1 Complex Nested Structures
from typing import List
from pydantic import BaseModel
class Address(BaseModel):
street: str
city: str
country: str
class Person(BaseModel):
name: str
age: int
email: str
addresses: List[Address]
agent = Agent(
name="Data Extractor",
model="gpt-4o",
instructions="Extract person information from the given text.",
output_type=Person,
)
result = runner.run(agent, """
John Smith is 35 years old. His email is john@example.com.
He lives at 123 Main St, New York, USA and also has a vacation
home at 456 Beach Rd, Miami, USA.
""")
print(result.final_output.name) # "John Smith"
print(result.final_output.addresses[0].city) # "New York"
print(result.final_output.addresses[1].city) # "Miami"12.4.2 With Validation
Pydantic validates the LLM’s response:
from pydantic import BaseModel, Field
class ProductReview(BaseModel):
rating: int = Field(ge=1, le=5) # Must be 1-5
summary: str = Field(max_length=100)
pros: List[str]
cons: List[str]
agent = Agent(
name="Review Analyzer",
model="gpt-4o",
instructions="Analyze product reviews and extract structured feedback.",
output_type=ProductReview,
)If the LLM returns an invalid rating (e.g., 6), Pydantic raises a ValidationError.
12.5 Streaming with Structured Output
Structured output also works with streaming:
for event in runner.run_stream(agent, "What's the weather?"):
if isinstance(event, FinalResultEvent):
# event.final_output is the parsed Pydantic model
print(event.final_output.temperature)12.6 When to Use
| Use Case | Recommendation |
|---|---|
| Chat responses | Plain text (no output_type) |
| Data extraction | Structured output |
| API responses | Structured output |
| Form filling | Structured output |
| Classification | Structured output with enum fields |
12.7 Key Points
| Aspect | Details |
|---|---|
output_type |
Any Pydantic BaseModel subclass |
| Validation | Automatic via Pydantic |
| Nested models | Fully supported |
| Streaming | Works with run_stream() |
| LLM support | Requires model with JSON mode support |
TipCheckpoint
cd code/v0.9You now have structured output support. The agent can return typed, validated data instead of raw strings.