Pydantic AI入門 2026 — FastAPI感覚で型安全なAIエージェントを作る完全ガイド
AIエージェントを作ろうとしたとき、最初に選ぶフレームワークによってその後の体験がかなり変わってくる、ということを最近しみじみ感じています。
LangChainを使ってみたけれど、なんか複雑すぎてしんどい。生のAPI呼び出しだと型安全じゃないし、構造化出力の取り扱いが面倒くさい。そういう悩みを持っている方に、今回は Pydantic AI を紹介したいと思います。
「FastAPIを知っているなら、すぐわかる。」そんなフレームワークです。
1. LangChainに感じた「もやもや」はあなただけじゃない
正直に言いましょう。LangChainは素晴らしいフレームワークです。エコシステムも大きいし、コミュニティも活発。でも実際に使い込んでいくと、いくつかの「もやもや」が蓄積していきます。
型安全じゃない。 LangChainのチェーンはランタイムまでエラーが発見できないケースが多い。IDEの補完もイマイチ効かない。
テストが重い。 エージェント全体をモックしないとユニットテストが書けない。ちょっとした動作確認のたびにAPIコールが発生してしまう。
モデル切り替えが大がかり。 OpenAIからAnthropicに変えたいと思ったとき、設定箇所が複数あって、「あれっ、どこ変えればいいんだっけ?」ってなる。
これはLangChainが悪いというより、「設計の思想の違い」なんだと思います。LangChainは汎用性と柔軟性を最優先にして設計されている。一方、Pydantic AIは 型安全とテスタビリティ を最優先にした設計になっています。
何を優先するかによって、適するフレームワークが変わる。それだけの話なんですが、2026年時点でPython開発者として型システムを活かした開発をしているなら、Pydantic AIは一度触ってみる価値があると思っています。
2. Pydantic AIって何? FastAPIを知っていれば即わかる
Pydantic AIは、Pydanticチームが開発したPythonエージェントフレームワークです。2024年末にリリースされ、2026年現在は本番運用で使えるレベルに成熟してきています。
「FastAPIのAI版」 と言うと、ピンとくる方が多いかもしれません。
FastAPIでは、エンドポイントに型付きパラメータとレスポンスモデルを宣言します。それだけでバリデーション、OpenAPI生成、IDEの補完が全部ついてくる。
Pydantic AIでは、エージェントに 型付き依存性 と 出力型 を宣言します。それだけで構造化出力のバリデーション、モデル切り替え、テスト可能な設計が整います。
# FastAPIのアナロジーで理解する
# FastAPI: エンドポイントを宣言
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserResponse(BaseModel):
name: str
email: str
@app.get("/user/{user_id}", response_model=UserResponse)
def get_user(user_id: int) -> UserResponse:
...
# Pydantic AI: エージェントを宣言
from pydantic_ai import Agent
from pydantic import BaseModel
class AnalysisResult(BaseModel):
sentiment: str
confidence: float
summary: str
agent = Agent(
"openai:gpt-4o",
output_type=AnalysisResult,
system_prompt="テキストの感情分析を行うエージェントです。"
)
この対称性は偶然ではありません。FastAPIが「HTTPリクエストに対する型安全なレスポンス」を実現したように、Pydantic AIは「LLMへのリクエストに対する型安全なレスポンス」を実現しています。
Pydantic AIの核心概念:
- Agent — コアオブジェクト。モデル名・出力型・システムプロンプトを持つ
- Output Types — Pydanticモデルとして宣言した構造化出力型
- Tools — エージェントが呼び出せる関数(型付きパラメータ)
- Dependencies — 依存性注入でテスト可能な外部リソース(DB、APIクライアント等)
3. インストールと最初のエージェント
まずは環境を作りましょう。2026年3月時点の最新安定版は pydantic-ai >= 0.0.40 あたりです。
# pipでインストール
pip install pydantic-ai
# OpenAIを使う場合
pip install pydantic-ai[openai]
# Anthropicを使う場合
pip install pydantic-ai[anthropic]
# バージョン確認
python -c "import pydantic_ai; print(pydantic_ai.__version__)"
環境変数を設定します:
# .envファイルに追記、またはexportで設定
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
最初のエージェントを動かしてみましょう:
# hello_agent.py
import asyncio
from pydantic_ai import Agent
# シンプルなテキスト出力エージェント
agent = Agent(
"openai:gpt-4o-mini",
system_prompt="あなたは親切なアシスタントです。日本語で応答してください。"
)
async def main():
result = await agent.run("Pythonで型安全なコードを書くメリットを3つ教えてください。")
print(result.output)
print(f"\n--- 使用トークン: {result.usage()} ---")
asyncio.run(main())
これだけです。agent.run() に文字列を渡すと、LLMからのレスポンスが result.output に入ります。使用トークン数も簡単に確認できます。
同期版(非同期なしで手っ取り早く試したい場合):
# 同期版: run_sync()を使う
result = agent.run_sync("質問をここに")
print(result.output)
async/await に慣れていなくても run_sync() で始められます。
4. 型安全という快感 — 構造化出力の実装
ここからが本番です。Pydantic AIの最大の魅力は「LLMの出力を型安全に取得できる」点です。
例えば、ユーザーのレビューを分析して、感情・評価スコア・要約を取得したいとします。生のAPI呼び出しだとJSONをパースしてバリデーションする処理を自分で書く必要があります。Pydantic AIでは:
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class ReviewAnalysis(BaseModel):
"""レビュー分析結果"""
sentiment: str = Field(description="positive / negative / neutral のいずれか")
score: float = Field(ge=0.0, le=5.0, description="評価スコア(0〜5)")
summary: str = Field(max_length=200, description="100文字以内の要約")
key_points: list[str] = Field(description="主要なポイント(最大5つ)")
# output_typeにPydanticモデルを渡すだけ
analysis_agent = Agent(
"openai:gpt-4o",
output_type=ReviewAnalysis,
system_prompt=(
"あなたは商品レビュー分析の専門家です。"
"与えられたレビューを分析し、構造化された形式で返してください。"
)
)
async def analyze_review(review_text: str) -> ReviewAnalysis:
result = await analysis_agent.run(review_text)
return result.output # 型: ReviewAnalysis
# 使用例
async def main():
review = """
このコーヒーメーカーを1ヶ月使ってみました。
朝の一杯がとても美味しく仕上がります。
ただ、洗い方がちょっと面倒で、分解してから洗う必要があります。
デザインはシンプルで気に入っています。全体的には満足しています。
"""
analysis = await analyze_review(review)
print(f"感情: {analysis.sentiment}")
print(f"スコア: {analysis.score}/5.0")
print(f"要約: {analysis.summary}")
print(f"ポイント: {analysis.key_points}")
result.output は ReviewAnalysis 型として返ってくるので、IDEの補完が効いて、mypy/pyrightでの型チェックも通ります。score が 0〜5 の範囲外の値を返した場合は、Pydanticのバリデーションが走って自動的に再試行されます。
これが型安全の「快感」です。実行してから気づくエラーが、書いている時点でわかる。
バリデーションの仕組みを少し掘り下げると...
Pydantic AIは内部でLLMの出力を受け取り、宣言した output_type に対してバリデーションを実行します。バリデーション失敗時は自動的にリトライし、エラー情報をLLMにフィードバックして修正を促します。このループがデフォルトで組み込まれているので、JSONパースのトライキャッチを自分で書く必要がありません。
5. ツールとDependency Injection — テスト可能な設計
Pydantic AIのもう一つの柱が「ツール」と「依存性注入」です。
ツールとは: エージェントが呼び出せる関数のこと。LangChainの「ツール」と同じ概念ですが、型付きデコレータで宣言するだけで済みます。
依存性注入とは: エージェントが必要とする外部リソース(データベース、HTTPクライアント等)を、実行時に注入できる仕組みです。本番用とテスト用を切り替えるのが非常に簡単になります。
実際のコードで見てみましょう。「商品在庫を確認してから購入可否を判断するエージェント」を作ります:
from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext
# 依存性の型定義
@dataclass
class Deps:
db_client: "InventoryDatabase" # 実際のDBクライアント or テスト用Mock
class InventoryDatabase:
"""本番用データベースクライアント(例)"""
async def check_stock(self, product_id: str) -> int:
# 実際のDB照会
return 42 # 在庫数を返す
async def get_product_info(self, product_id: str) -> dict:
return {"name": "コーヒーメーカー", "price": 12800}
# エージェントの宣言
class PurchaseDecision(BaseModel):
can_purchase: bool
reason: str
stock_count: int
recommendation: str
purchase_agent = Agent(
"anthropic:claude-sonnet-4-20250514",
deps_type=Deps,
output_type=PurchaseDecision,
system_prompt="在庫情報を元に購入可否を判断してください。"
)
# ツールの定義
@purchase_agent.tool
async def check_inventory(ctx: RunContext[Deps], product_id: str) -> dict:
"""指定商品の在庫数を確認する"""
stock = await ctx.deps.db_client.check_stock(product_id)
info = await ctx.deps.db_client.get_product_info(product_id)
return {
"stock_count": stock,
"product_name": info["name"],
"price": info["price"]
}
# 実行
async def main():
deps = Deps(db_client=InventoryDatabase())
result = await purchase_agent.run(
"商品ID: COFFEE-MAKER-001 は今すぐ購入できますか?",
deps=deps
)
decision = result.output
print(f"購入可否: {'可能' if decision.can_purchase else '不可'}")
print(f"理由: {decision.reason}")
print(f"在庫: {decision.stock_count}個")
@purchase_agent.tool デコレータをつけるだけで、エージェントが自動的にツールとして認識します。ctx.deps を通じて依存性にアクセスできます。型は全部 Deps クラスから推論されるので、IDEが補完してくれます。
なぜ依存性注入がテストで嬉しいか:
本番では InventoryDatabase() を注入する。テストでは Mock を注入する。エージェントのコード自体は一切変えない。これだけで、APIコールなしのユニットテストが書けます。
6. TestModelで高速テスト — APIコール0のCI/CDを実現
Pydantic AIには TestModel という組み込みのテスト用モデルがあります。LLMのAPIを一切呼ばずに、エージェントの振る舞いをテストできます。
CI/CDを回すたびに実際のLLM APIを呼ぶのは、コストがかかるし、テストが非決定論的になるし、速度も遅い。TestModel はこの問題を解決します。
# test_purchase_agent.py
import pytest
from pydantic_ai.models.test import TestModel
from pydantic_ai import Agent
# テスト用のMock DB
@dataclass
class MockInventoryDatabase:
stock_data: dict[str, int]
async def check_stock(self, product_id: str) -> int:
return self.stock_data.get(product_id, 0)
async def get_product_info(self, product_id: str) -> dict:
return {"name": "テスト商品", "price": 9999}
@pytest.mark.asyncio
async def test_purchase_agent_with_stock():
"""在庫あり時のテスト"""
mock_db = MockInventoryDatabase(stock_data={"TEST-001": 10})
mock_deps = Deps(db_client=mock_db)
# TestModelを使うことでAPIコールなし
with purchase_agent.override(model=TestModel()):
result = await purchase_agent.run(
"TEST-001 は購入できますか?",
deps=mock_deps
)
# ツールが呼ばれたかを検証
assert result.output is not None
# TestModelはデフォルトで全ツールを1回呼び出す
@pytest.mark.asyncio
async def test_purchase_agent_no_stock():
"""在庫なし時のテスト"""
mock_db = MockInventoryDatabase(stock_data={"TEST-002": 0})
mock_deps = Deps(db_client=mock_db)
with purchase_agent.override(model=TestModel()):
result = await purchase_agent.run(
"TEST-002 は購入できますか?",
deps=mock_deps
)
# ツールの呼び出し履歴を検証
for call in result.all_messages():
print(call) # どんな会話が発生したかトレース可能
purchase_agent.override(model=TestModel()) のコンテキストマネージャー内では、実際のLLM呼び出しが発生しません。ツールの呼び出しパターンや会話履歴をローコストで検証できます。
pytest-asyncioと組み合わせるとCI/CDがこう変わります:
# CI上でのテスト実行
# APIキーなしで実行可能
PYTHONPATH=. pytest tests/ -v
# 実行時間: 数秒 (APIコールなし)
# 費用: $0
# 再現性: 100%
これはかなり実務的に嬉しい変化です。「テストを書くたびにAPIを消費する」ストレスから解放されます。
7. モデルを1行で切り替える & 本番運用のヒント
Pydantic AIのモデル指定は文字列で行うため、切り替えが非常に簡単です。
# 開発時: 安いモデルで動作確認
agent = Agent("openai:gpt-4o-mini", output_type=MyOutput)
# 本番: 性能重視
agent = Agent("openai:gpt-4o", output_type=MyOutput)
# コスト最適化したい
agent = Agent("anthropic:claude-haiku-4-20250514", output_type=MyOutput)
# ローカルモデル (Ollama)
agent = Agent("ollama:llama3.3", output_type=MyOutput)
# フォールバック設定
from pydantic_ai.models.fallback import FallbackModel
fallback_model = FallbackModel(
"openai:gpt-4o", # プライマリ
"anthropic:claude-sonnet-4-20250514" # フォールバック
)
agent = Agent(fallback_model, output_type=MyOutput)
環境変数でモデルを切り替えるパターン:
import os
from pydantic_ai import Agent
MODEL = os.getenv("AI_MODEL", "openai:gpt-4o-mini")
agent = Agent(MODEL, output_type=MyOutput)
本番とステージングでモデルを変えたいとき、コードを一切変えずに環境変数だけで制御できます。
本番運用のヒント:
① Pydantic Logfireでトレーシング
import logfire
logfire.configure()
logfire.instrument_pydantic_ai()
# 以降、エージェントの全実行が自動的にトレース記録される
agent = Agent("openai:gpt-4o", output_type=MyOutput)
どのプロンプトがどれだけのトークンを使ったか、ツールの実行時間、エラー率などをダッシュボードで確認できます。
② リトライ設定のカスタマイズ
from pydantic_ai import Agent
from pydantic_ai.settings import ModelSettings
agent = Agent(
"openai:gpt-4o",
output_type=MyOutput,
model_settings=ModelSettings(
max_tokens=2000,
temperature=0.7,
),
retries=3 # バリデーション失敗時のリトライ回数
)
③ 非同期処理の最適化
import asyncio
from pydantic_ai import Agent
agent = Agent("openai:gpt-4o-mini", output_type=MyOutput)
# 複数のリクエストを並列処理
async def batch_process(queries: list[str]) -> list[MyOutput]:
tasks = [agent.run(q) for q in queries]
results = await asyncio.gather(*tasks)
return [r.output for r in results]
# 10件のリクエストを並列実行(順番にやる10倍速い)
outputs = await batch_process(queries)
asyncio.gather() との組み合わせで、複数のエージェント実行を並列化できます。API呼び出しが I/O バウンドなので、非同期による恩恵が大きい。
8. まとめ: 型安全なAIエージェント開発の新しい標準へ
Pydantic AIを使ってみると、「なんでこれ最初からなかったんやろ」という感覚になります。
型安全。テスタブル。モデル非依存。依存性注入。Observable。これ全部、普通のサーバーサイド開発ではとっくに当たり前になっていたことです。AIエージェントの世界でも同じことが当たり前になる時代が来た、ということかもしれません。
LangChainと比べてPydantic AIが明らかに優れているのは 型安全性とテスタビリティ の部分です。ただ、LangChainの方がエコシステムが大きく、実装済みのインテグレーションは豊富です。どちらを選ぶかは目的次第。
- 型安全さとテスタビリティを重視するなら → Pydantic AI
- 既存の豊富なコネクタ・インテグレーションが必要なら → LangChain/LangGraph
- グラフベースの複雑なマルチエージェントなら → LangGraph
今後のPydantic AIのロードマップには、マルチエージェント協調とより高度なグラフベースのワークフローが含まれています。FastAPIがWebフレームワークのデファクトになったように、Pydantic AIがAIエージェントフレームワークのデファクトになる日が来るかもしれません。
まずは pip install pydantic-ai して、このガイドのコードを動かしてみてください。型安全なエージェント開発の感覚を、手で触れて理解してみることをおすすめします。
参考資料
- Pydantic AI公式ドキュメント (ai.pydantic.dev)
- Pydantic AI Tutorial: Build Type-Safe AI Agents (2026) (myengineeringpath.dev)
- Pydantic AI: Build Type-Safe LLM Agents in Python – Real Python (realpython.com, 2026-02-11)
- Mastering Python Async Patterns: A Complete Guide to asyncio in 2026 (dev.to, 2026-02-17)