型安全にLLMを扱う:`pydantic_ai`の使い方大全【実例豊富】
LLM をアプリケーションに組み込む際、多くの人が経験しているであろう問題はこれです:
- モデル出力が「ただの文字列」で扱いにくい
- JSONに変換させても崩れることが多い
- 想定外のフォーマットで返ってきてバグる
そんなときに使えるのが pydantic_ai。
これは LLMの入出力をPydanticモデルで型安全に扱えるライブラリ です。
この記事では、基本から応用まで 実例たっぷり で pydantic_ai を紹介します。
✅ インストール
pip install pydantic-ai
OpenAIを使う場合は、環境変数 OPENAI_API_KEY をセットしてください。
1. 基本:レスポンスを構造化する
from pydantic_ai import Agent
from pydantic import BaseModel
class WeatherInfo(BaseModel):
location: str
temperature: float
condition: str
agent = Agent("openai:gpt-4o-mini", output_type=WeatherInfo)
result = agent.run_sync("東京の天気を教えて")
print(result.output)
出力例
WeatherInfo(location='東京', temperature=29.3, condition='晴れ')
👉 文字列ではなく構造化データ が返るため、そのままDB保存やAPIレスポンスに利用できます。
2. 入力データを渡す(依存性注入)
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
from pydantic import BaseModel
class Task(BaseModel):
title: str
deadline: str
@dataclass
class TaskDeps:
title: str
deadline: str
agent = Agent("openai:gpt-4o-mini", deps_type=TaskDeps, output_type=Task)
@agent.system_prompt
def system(ctx: RunContext[TaskDeps]) -> str:
d = ctx.deps
return f"次の情報で Task を生成: title={d.title}, deadline={d.deadline}"
result = agent.run_sync(
"新しいタスクを作成してください",
deps=TaskDeps(title="月次レポート提出", deadline="2025-09-01"),
)
print(result.output)
出力例
Task(title='月次レポート提出', deadline='2025-09-01')
👉 外部データを依存性として注入しつつ構造化出力 が可能です。
3. 複雑なデータ構造を扱う
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
tags: list[str]
class Catalog(BaseModel):
items: list[Product]
agent = Agent("openai:gpt-4o-mini", output_type=Catalog)
result = agent.run_sync("人気のプログラミング関連商品を3つ紹介してください")
print(result.output)
出力例
Catalog(items=[
Product(name="Python入門書", price=2500, tags=["python", "book"]),
Product(name="Raspberry Pi 5", price=8000, tags=["hardware", "iot"]),
Product(name="VSCode拡張パック", price=0, tags=["editor", "plugin"])
])
4. バリデーションと例外処理
不正な出力は即エラーに。
try:
result = agent.run_sync("わけのわからない形式で出力して")
print(result.output)
except Exception as e:
print("Validation Error:", e)
👉 output_validator によるバリデーションエラー を標準で検出できます。
5. 関数呼び出し(ツール / 出力関数)
関数を呼び出し、その返り値を最終出力にする場合は「出力関数(output function)」として登録します。
from pydantic_ai import Agent
def add_numbers(a: int, b: int) -> int:
return a + b
agent = Agent("openai:gpt-4o-mini", output_type=add_numbers)
result = agent.run_sync("3と5を足してください")
print(result.output)
出力例
8
👉 OpenAIの「function calling」と同等の仕組みを もっと簡単に 利用できます。
6. ストリーミング応答
# asyncio 環境で
async with agent.run_stream("東京の観光スポットを教えて") as result:
async for message in result.stream_text():
print(message)
👉 リアルタイムUIやチャットボット に最適。
7. データ正規化に使う
ユーザー入力を標準化して保存する例。
class User(BaseModel):
name: str
email: str
age: int
agent = Agent("openai:gpt-4o-mini", output_type=User)
result = agent.run_sync("私は田中太郎、30歳、メールは taro at example.com")
print(result.output.model_dump())
出力例
{'name': '田中太郎', 'email': 'taro@example.com', 'age': 30}
👉 入力の揺れを吸収 し、クリーンなデータを得られます。
8. 複数候補を返す(ランキングや提案)
class Idea(BaseModel):
title: str
description: str
class IdeaList(BaseModel):
ideas: list[Idea]
agent = Agent("openai:gpt-4o-mini", output_type=IdeaList)
result = agent.run_sync("新しいSaaSアイデアを5つ提案してください")
print(result.output)
👉 候補リストを構造化して返せる ので、そのままUIに表示可能。
9. 複数ツールの組み合わせ
from datetime import datetime
from pydantic_ai import Agent
def current_time() -> str:
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def multiply(a: int, b: int) -> int:
return a * b
agent = Agent("openai:gpt-4o-mini", tools=[current_time, multiply])
result = agent.run_sync("今の時刻を表示し、7×8を計算してください")
print(result.output)
👉 エージェントに複数の関数を渡してオーケストレーション が可能です。
(最終出力を関数値にしたい場合は「出力関数」として output_type に登録)
🔥 まとめ
pydantic_ai を使うと…
- LLM出力を 型安全に 扱える
- 依存性注入 で応答を制御可能
- 複雑なJSON構造 を直接取得できる
- 関数呼び出しやツール連携 が簡単
- バリデーションで 出力の破損を防止
つまり、従来の「文字列ベースで無理やりパースするコード」から解放され、信頼できるAIアプリ開発 が実現できます。
💡 個人的には、「LLM × APIサーバ」や「LLM × DB」 のケースで特に威力を発揮すると思います。
これからLLMアプリを作る人は、まず pydantic_ai を導入することを強くおすすめします。
Discussion
現時点で
result_typeやresult.dataはoutput_typeやresult.outputに変わってます。記事を修正してください。
ご指摘ありがとうございます。最新の仕様に従って修正しました。ありがとうございました。