Lesson CH04-L01
output_type
Pydanticモデルを output_type に渡し、型付き結果を得る。
- 読了目安
- 10 min
- Colab目安
- 16 min
- 合計
- 26 min
- 前提
- Advanced Tools
関連: 公式ドキュメント
一行サマリ
Agent(model, output_type=YourModel) で、Agent の 最終応答そのものを Pydantic Model に固定 できる。LLM 応答が型に合わなければ自動で retry が走り、result.output には 型付き・検証済み のオブジェクトだけが入る。
ヒーロー: テキスト応答 vs 構造化応答
通常 Agent は文字列を返しますが、output_type を指定すると Pydantic Model のインスタンス が返ります。後続の Python ロジックがそれを直接使えるようになり、「LLM 応答を文字列パースする」苦労が消えます。
概念: output_type の仕組み
output_type=YourModel を Agent に渡すと、PydanticAI は内部で次のことを行います。
- YourModel の JSON Schema を生成 し、LLM への prompt に同梱
- LLM 応答を JSON としてパース して YourModel に変換
- 検証エラーがあれば 自動で retry (デフォルト 1 回)
- 成功したら
result.outputに 型付きインスタンス を入れる
開発者が書くコードは「Model クラスを定義 + Agent に渡す」の 2 行だけ。あとは PydanticAI が schema 生成・パース・検証・retry を肩代わりします。
コード: 4 つのパターン
パターン 1: シンプルな BaseModel
from pydantic import BaseModel
from pydantic_ai import Agent
class WeatherReport(BaseModel):
city: str
condition: str
temp_c: float
agent = Agent(
'google-gla:gemini-3-flash-preview',
output_type=WeatherReport,
instructions='ユーザーの問いから天気情報を構造化して返してください。',
)
result = agent.run_sync('東京は今日晴れで 22 度でした。レポートにして。')
print(type(result.output).__name__) # WeatherReport
print(result.output.city) # 'Tokyo' or '東京'
print(result.output.temp_c) # 22.0ポイント:
output_type=WeatherReportを渡すだけでresult.outputがWeatherReport型に固定- フィールドを 数値で取り出して 後続処理に渡せる (もう正規表現パースは不要)
- LLM が型に合わない応答を返したら自動で retry が走る
パターン 2: ネストした BaseModel
from pydantic import BaseModel
from datetime import date
class Customer(BaseModel):
name: str
age: int
class Booking(BaseModel):
customer: Customer
booking_date: date
party_size: int
agent_b = Agent(
'google-gla:gemini-3-flash-preview',
output_type=Booking,
instructions='予約情報を構造化してください。今日は 2026-05-11 です。',
)
result = agent_b.run_sync('明日の夜、田中 (35歳) で 4 名予約お願いします')
print(result.output.customer.name) # 田中
print(result.output.customer.age) # 35
print(result.output.booking_date) # 2026-05-12
print(result.output.party_size) # 4ネストは 2〜3 段 くらいまでなら LLM が安定して組み立てられます。それ以上深いと組立失敗が増えるので、フラット化を検討。
パターン 3: List[BaseModel] で複数件返す
class TodoItem(BaseModel):
title: str
priority: int # 1〜5
agent_t = Agent(
'google-gla:gemini-3-flash-preview',
output_type=list[TodoItem],
instructions='ユーザーの文章から TODO リストを抽出してください。priority は 1 (低) 〜 5 (高)。',
)
result = agent_t.run_sync('明日までに資料レビューと、来週末までに発表資料準備、緊急で来客対応')
for item in result.output:
print(f'[{item.priority}] {item.title}')output_type=list[TodoItem] のように list[...] を直接渡せます。dict[str, T] も可。
パターン 4: 検証エラーは自動 retry
Annotated[..., Field(...)] を使えば、LLM の組立ミスを自動で直させられます (Ch3-L02 と同じ仕組みが output 側でも効きます)。
from typing import Annotated
from pydantic import BaseModel, Field
class Score(BaseModel):
student: str
points: Annotated[int, Field(ge=0, le=100, description='0〜100 の点数')]
agent_s = Agent(
'google-gla:gemini-3-flash-preview',
output_type=Score,
instructions='学生名と点数を抽出してください。',
)
# わざと範囲外を提案する文を投げる
result = agent_s.run_sync('佐藤さんは 110 点でした (120 点満点中)')
print(result.output.points) # LLM は 100 に丸めるか、別の解釈で範囲内に収めて返すいつ output_type を使うべきか
| 状況 | output_type |
|---|---|
| ユーザーへの自然文応答だけ欲しい (チャット) | 不要 (str で OK) |
| 後続の Python 関数に渡す情報を抽出したい | 必要 |
| データを DB に保存したい | 必要 |
| LLM 応答を JSON として API レスポンスに乗せたい | 必要 |
| 複数の選択肢から 1 つ選ばせたい | 必要 (Literal または Union = Ch4-L03) |
output_type は「Agent と Python コードの境界面」を型で固める仕掛け と覚えてください。
まとめ
output_type=YourModelで Agent の最終応答を Pydantic Model インスタンス に固定- ネストや list/dict もそのまま OK。
Annotated[..., Field(...)]で範囲制約も付けられる - 検証エラーは 自動 retry。Tool の Pydantic バリデーション (Ch3-L02) と同じ仕組み
Field(description=...)を書くと LLM の組立精度が上がる
次レッスンでは、構造化応答を Streaming で逐次受け取るパターンを扱います。
Colab で実際に動かす
本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。
notebooks/ch04/01-output-type.ipynb