or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

agent.mdindex.mdmessages.mdmodels.mdoutput.mdsettings.mdstreaming.mdtools.md

output.mddocs/

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

```