Lesson CH04-L03
Union型
複数候補の出力型をUnionで定義し、分岐を表現する。
- 読了目安
- 10 min
- Colab目安
- 14 min
- 合計
- 24 min
- 前提
- Streamed Output
関連: 公式ドキュメント
一行サマリ
output_type=Success | Error のような Union 型 を Agent に渡すと、LLM は 「どちらを返すか」を判断 して選んだ型のオブジェクトを返す。受け側は isinstance で分岐、または discriminated union で型を一発判別できる。
ヒーロー: 1 つの Agent が複数の "応答形" を持つ
「クエリの結果」と「クエリ失敗の理由」のように、応答が 質的に違う複数の形 を取りうる場面で Union が効きます。LLM 自身が「今の状況ならこっちの型」と選んでくれるので、呼び出し側は型で分岐するだけ。
概念: Union を使うべき 2 つのシーン
| シーン | 例 |
|---|---|
| 成功 / 失敗の分岐 | 在庫照会の結果 vs 在庫切れエラー |
| アクション選択 | "search" / "create" / "delete" の 3 種類のリクエスト型 |
Union[A, B] または Python 3.10+ の A | B の構文どちらでも書けます。
コード: 4 つのパターン
パターン 1: 成功 / 失敗 の Union
from pydantic import BaseModel
from pydantic_ai import Agent
class StockOK(BaseModel):
product: str
quantity: int
class StockError(BaseModel):
product: str
reason: str # '不存在' / '在庫切れ' など
agent = Agent(
'google-gla:gemini-3-flash-preview',
output_type=StockOK | StockError,
instructions='在庫システム照会の結果を返してください。在庫があれば StockOK、なければ StockError。',
)
# 利用側は isinstance で分岐
result = agent.run_sync('商品 X-1 の在庫は?')
if isinstance(result.output, StockOK):
print(f'在庫あり: {result.output.product} × {result.output.quantity}')
else:
print(f'❌ {result.output.product}: {result.output.reason}')ポイント:
output_type=A | Bで どちらの型でも返せる ことを LLM に通知- 利用側は
isinstanceで分岐 (Pyright も narrow してくれる) - LLM が「成功できそう」「無理そう」を判断して型を選ぶ
パターン 2: 3 種類以上のアクション (discriminated union)
Literal フィールドを 判別子 として使うと、LLM が型をきっちり選んでくれます。
from typing import Literal
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class SearchAction(BaseModel):
type: Literal['search'] = 'search'
query: str
class CreateAction(BaseModel):
type: Literal['create'] = 'create'
title: str
body: str
class DeleteAction(BaseModel):
type: Literal['delete'] = 'delete'
id: int
Action = SearchAction | CreateAction | DeleteAction
agent_a = Agent(
'google-gla:gemini-3-flash-preview',
output_type=Action,
instructions=(
'ユーザーの自然文を、3 種類のアクションのいずれかに変換してください。\\n'
'- search: 検索したい場合\\n'
'- create: 何かを作成したい場合\\n'
'- delete: 削除したい場合'
),
)
result = agent_a.run_sync('「PydanticAI入門」というタイトルで記事を書きたい')
match result.output:
case SearchAction(query=q):
print(f'検索: {q}')
case CreateAction(title=t, body=b):
print(f'作成: {t} / {b[:40]}...')
case DeleteAction(id=i):
print(f'削除: id={i}')ポイント:
- 各型に
type: Literal['xxx']を共通フィールドとして持たせる - LLM はこの type フィールドで「どの型を組むか」を明示する
- Python 3.10+ の
match文 で型分岐を綺麗に書ける
パターン 3: Union[T, str] でフォールバック
「構造化できれば Booking、無理ならフリーテキスト」のように、フォールバック として str を混ぜることも可能です。
from datetime import date
from pydantic import BaseModel
from pydantic_ai import Agent
class Booking(BaseModel):
customer: str
booking_date: date
party_size: int
agent_b = Agent(
'google-gla:gemini-3-flash-preview',
output_type=Booking | str,
instructions=(
'予約情報が抽出できれば Booking、'
'不足や曖昧で抽出できなければ追加質問の文字列を返してください。'
),
)
# 不完全な入力で曖昧
result = agent_b.run_sync('明日予約お願いします')
if isinstance(result.output, Booking):
print('予約完了:', result.output)
else:
print('追加質問:', result.output) # strこれで 「フォーマット強制 + 自然言語フォールバック」 の混在が綺麗に書けます。
パターン 4: List of Union (複雑データ)
list[A | B] も書けます。複数アクションの一括解析などに使えます。
agent_multi = Agent(
'google-gla:gemini-3-flash-preview',
output_type=list[SearchAction | CreateAction | DeleteAction],
instructions='ユーザーの文章から、すべてのアクションを順番に抽出してください。',
)
result = agent_multi.run_sync('まず「Python」で検索して、次に「Note 1」を新規作成、最後に id=42 を削除して')
for action in result.output:
match action:
case SearchAction(query=q):
print(f'1. search: {q}')
case CreateAction(title=t):
print(f'2. create: {t}')
case DeleteAction(id=i):
print(f'3. delete: id={i}')いつ Union を使うか
- ✅ 応答パターンが 質的に違う (成功 / 失敗、複数アクション)
- ✅
isinstanceまたはmatchで分岐 したいロジック - ✅ LLM が「どの形を返すか」を 状況から判断 する余地がある
- ❌ 同じ形の中で 1 フィールドだけ違う →
Annotated+Fieldで十分 - ❌ 5 種類以上の Union → 複数 Agent (Multi-Agent / Ch8) に分割を検討
まとめ
output_type=A | Bで 複数の応答型 を表現、LLM が状況に応じて選ぶ- 各型に
type: Literal['x']を持たせると discriminated union として確実に判別 - 利用側は
isinstanceまたはmatch文で分岐 Booking | strで 構造化 + フォールバック自然文 の併用も可能
これで Ch4「Structured Output」全 3 レッスンが完了です。次の Ch5「Capabilities」 からは、Gemini 固有の機能 (Web Search / Thinking / Safety Settings) を扱います。
Colab で実際に動かす
本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。
notebooks/ch04/03-union-output.ipynb