0
# Output Types and Validation
1
2
Flexible output handling supporting structured data validation using Pydantic models, text outputs, tool-based outputs, and native model outputs with comprehensive type safety.
3
4
## Capabilities
5
6
### Structured Output Types
7
8
Output configuration classes that determine how agent responses are processed and validated.
9
10
```python { .api }
11
class ToolOutput[OutputDataT]:
12
"""
13
Tool-based output configuration where tools generate the final result.
14
"""
15
def __init__(
16
self,
17
tools: list[Tool],
18
*,
19
defer: bool = False
20
):
21
"""
22
Configure tool-based output.
23
24
Parameters:
25
- tools: List of tools that can generate output
26
- defer: Whether to defer tool execution
27
"""
28
29
class NativeOutput[OutputDataT]:
30
"""
31
Native structured output configuration using model's built-in structured output.
32
"""
33
pass
34
35
class PromptedOutput[OutputDataT]:
36
"""
37
Prompted output configuration where model is prompted to return structured data.
38
"""
39
pass
40
41
class TextOutput[OutputDataT]:
42
"""
43
Text output configuration with optional conversion function.
44
"""
45
def __init__(
46
self,
47
converter: TextOutputFunc[OutputDataT] | None = None
48
):
49
"""
50
Configure text output.
51
52
Parameters:
53
- converter: Optional function to convert text to desired type
54
"""
55
```
56
57
### Deferred Tool Calls
58
59
Container for managing deferred tool execution.
60
61
```python { .api }
62
class DeferredToolCalls:
63
"""
64
Container for deferred tool calls that can be executed later.
65
"""
66
def __init__(self, tool_calls: list[ToolCallPart]): ...
67
68
def execute_all(
69
self,
70
deps: Any = None
71
) -> list[Any]:
72
"""
73
Execute all deferred tool calls.
74
75
Parameters:
76
- deps: Dependencies to pass to tools
77
78
Returns:
79
List of tool execution results
80
"""
81
```
82
83
### Structured Dictionary Factory
84
85
Factory function for creating structured dictionary types.
86
87
```python { .api }
88
def StructuredDict() -> type[dict[str, Any]]:
89
"""
90
Create structured dictionary type for flexible output handling.
91
92
Returns:
93
Dictionary type that can be used as result_type for agents
94
"""
95
```
96
97
### Output Type Aliases
98
99
Type definitions for various output configurations and functions.
100
101
```python { .api }
102
OutputMode = Literal['tools', 'json', 'str']
103
104
StructuredOutputMode = Literal['json', 'str']
105
106
OutputSpec[T_co] = (
107
type[T_co] |
108
ToolOutput[T_co] |
109
NativeOutput[T_co] |
110
PromptedOutput[T_co] |
111
TextOutput[T_co]
112
)
113
114
OutputTypeOrFunction[T_co] = (
115
OutputSpec[T_co] |
116
Callable[[str], T_co]
117
)
118
119
TextOutputFunc[T_co] = Callable[[str], T_co]
120
```
121
122
### Output Processing
123
124
Internal types and functions for output processing (advanced usage).
125
126
```python { .api }
127
class OutputTypeWrapper[T]:
128
"""Internal wrapper for output type processing."""
129
def __init__(
130
self,
131
output_type: OutputSpec[T],
132
allow_text_output: bool = True
133
): ...
134
135
def validate_output(self, data: Any) -> T: ...
136
def get_output_mode(self) -> OutputMode: ...
137
```
138
139
## Usage Examples
140
141
### Basic Structured Output with Pydantic
142
143
```python
144
from pydantic_ai import Agent
145
from pydantic import BaseModel
146
147
class WeatherInfo(BaseModel):
148
location: str
149
temperature: float
150
condition: str
151
humidity: int
152
153
# Agent with structured output
154
agent = Agent(
155
model='gpt-4',
156
system_prompt='Extract weather information from text.',
157
result_type=WeatherInfo
158
)
159
160
result = agent.run_sync(
161
'The weather in Paris is sunny, 22°C with 65% humidity'
162
)
163
164
print(result.data.location) # "Paris"
165
print(result.data.temperature) # 22.0
166
print(result.data.condition) # "sunny"
167
print(result.data.humidity) # 65
168
```
169
170
### Tool-Based Output
171
172
```python
173
from pydantic_ai import Agent, ToolOutput, tool
174
175
@tool
176
def calculate_result(numbers: list[float], operation: str) -> float:
177
"""Perform calculation on numbers."""
178
if operation == 'sum':
179
return sum(numbers)
180
elif operation == 'average':
181
return sum(numbers) / len(numbers)
182
elif operation == 'max':
183
return max(numbers)
184
else:
185
raise ValueError(f"Unknown operation: {operation}")
186
187
# Agent with tool-based output
188
agent = Agent(
189
model='gpt-4',
190
system_prompt='Use tools to calculate results.',
191
result_type=ToolOutput([calculate_result])
192
)
193
194
result = agent.run_sync('Calculate the average of 10, 20, 30, 40')
195
print(result.data) # 25.0
196
```
197
198
### Text Output with Conversion
199
200
```python
201
from pydantic_ai import Agent, TextOutput
202
import json
203
204
def parse_json_response(text: str) -> dict:
205
"""Parse JSON from model response."""
206
# Extract JSON from text if needed
207
start = text.find('{')
208
end = text.rfind('}') + 1
209
json_str = text[start:end]
210
return json.loads(json_str)
211
212
# Agent with text output conversion
213
agent = Agent(
214
model='gpt-4',
215
system_prompt='Return responses as JSON.',
216
result_type=TextOutput(parse_json_response)
217
)
218
219
result = agent.run_sync('Create a person object with name and age')
220
print(result.data) # {'name': 'John Doe', 'age': 30}
221
```
222
223
### Structured Dictionary Output
224
225
```python
226
from pydantic_ai import Agent, StructuredDict
227
228
# Agent with flexible dictionary output
229
agent = Agent(
230
model='gpt-4',
231
system_prompt='Return structured data as a dictionary.',
232
result_type=StructuredDict()
233
)
234
235
result = agent.run_sync('Create a product with name, price, and category')
236
print(result.data) # {'name': 'Laptop', 'price': 999.99, 'category': 'Electronics'}
237
```
238
239
### Native vs Prompted Output
240
241
```python
242
from pydantic_ai import Agent, NativeOutput, PromptedOutput
243
from pydantic import BaseModel
244
245
class TaskInfo(BaseModel):
246
title: str
247
priority: int
248
completed: bool
249
250
# Native structured output (uses model's built-in structured output)
251
native_agent = Agent(
252
model='gpt-4',
253
system_prompt='Create task information.',
254
result_type=NativeOutput[TaskInfo]
255
)
256
257
# Prompted structured output (prompts model to return structured data)
258
prompted_agent = Agent(
259
model='gpt-4',
260
system_prompt='Create task information.',
261
result_type=PromptedOutput[TaskInfo]
262
)
263
264
# Both work similarly but use different underlying mechanisms
265
result1 = native_agent.run_sync('Create a high priority task for code review')
266
result2 = prompted_agent.run_sync('Create a high priority task for code review')
267
268
print(result1.data.title) # "Code Review"
269
print(result1.data.priority) # 3
270
print(result1.data.completed) # False
271
```
272
273
### Deferred Tool Execution
274
275
```python
276
from pydantic_ai import Agent, ToolOutput, tool
277
278
@tool
279
def expensive_calculation(data: list[int]) -> int:
280
"""Perform expensive calculation."""
281
# Simulate expensive operation
282
return sum(x ** 2 for x in data)
283
284
# Agent with deferred tool execution
285
agent = Agent(
286
model='gpt-4',
287
system_prompt='Plan calculations but defer execution.',
288
result_type=ToolOutput([expensive_calculation], defer=True)
289
)
290
291
result = agent.run_sync('Plan calculation for numbers 1 through 100')
292
293
# result.data is now DeferredToolCalls
294
if isinstance(result.data, DeferredToolCalls):
295
# Execute when ready
296
actual_results = result.data.execute_all()
297
print(actual_results[0]) # Result of expensive calculation
298
```
299
300
### Complex Nested Output
301
302
```python
303
from pydantic_ai import Agent
304
from pydantic import BaseModel
305
from typing import List
306
307
class Address(BaseModel):
308
street: str
309
city: str
310
country: str
311
postal_code: str
312
313
class Person(BaseModel):
314
name: str
315
age: int
316
email: str
317
addresses: List[Address]
318
319
class Company(BaseModel):
320
name: str
321
employees: List[Person]
322
headquarters: Address
323
324
# Agent with complex nested output
325
agent = Agent(
326
model='gpt-4',
327
system_prompt='Extract company information.',
328
result_type=Company
329
)
330
331
result = agent.run_sync('''
332
Create a company called TechCorp with headquarters in San Francisco.
333
Include 2 employees: John (30, john@techcorp.com) and Jane (28, jane@techcorp.com).
334
''')
335
336
print(result.data.name) # "TechCorp"
337
print(len(result.data.employees)) # 2
338
print(result.data.employees[0].name) # "John"
339
print(result.data.headquarters.city) # "San Francisco"
340
```
341
342
### Custom Validation
343
344
```python
345
from pydantic_ai import Agent
346
from pydantic import BaseModel, validator
347
348
class ValidatedOutput(BaseModel):
349
score: float
350
grade: str
351
352
@validator('score')
353
def score_must_be_valid(cls, v):
354
if not 0 <= v <= 100:
355
raise ValueError('Score must be between 0 and 100')
356
return v
357
358
@validator('grade')
359
def grade_must_match_score(cls, v, values):
360
score = values.get('score', 0)
361
expected_grades = {
362
(90, 100): 'A',
363
(80, 89): 'B',
364
(70, 79): 'C',
365
(60, 69): 'D',
366
(0, 59): 'F'
367
}
368
369
for (min_score, max_score), expected_grade in expected_grades.items():
370
if min_score <= score <= max_score:
371
if v != expected_grade:
372
raise ValueError(f'Grade {v} does not match score {score}')
373
break
374
return v
375
376
# Agent with custom validation
377
agent = Agent(
378
model='gpt-4',
379
system_prompt='Grade student performance.',
380
result_type=ValidatedOutput
381
)
382
383
result = agent.run_sync('Student scored 85 points on the exam')
384
print(result.data.score) # 85.0
385
print(result.data.grade) # "B"
386
```