
Pydantic AI:本番環境向けガイド(Hello Worldを卒業する)
生のLLM出力はアプリケーションを壊します。JSONを求めるとマークダウンが返され、1から10までの数値を求めると「Sure! Here's a number: seven.」と返ってきます。LLM APIを使って何か実用的なものを作ったことがあるなら、自分のキャリア選択を疑いたくなるような防御的なパースコードを書いた経験があるはずです。Pydantic AIはこの問題を解決します。これはPydanticとFastAPIを生み出した同じチームによって構築された、型安全なエージェントフレームワークです。「AIエージェントのためのFastAPI」と考えてください。Pythonの型ヒントで欲しいものを定義すれば、フレームワークが検証、リトライ、ツール呼び出しを処理してくれます。
このPydantic AIガイドは、すでに最初のLLM呼び出しを実行済みで、本番環境向けのパターンを求めている開発者向けです。壊れない構造化出力、テスト可能なエージェントのための依存性注入、天気予報APIを超えた実世界でのツール活用などを扱います。最後まで読み進めれば、ツール、DI、ストリーミング、テストを備えた動作するエージェントを手に入れることができます。
<!-- IMAGE: Pydantic AI agent architecture, Agent receives prompt, calls tools via RunContext, validates output through Pydantic model -->Pydantic AIの概要
| 属性 | 詳細 |
|---|---|
| 何であるか | Python用の型安全なAIエージェントフレームワーク |
| 開発元 | Pydanticチーム(Samuel Colvin他) |
| 哲学 | 「AIエージェントのためのFastAPI」、すべてを型ヒントが駆動する |
| ライセンス | MIT(オープンソース) |
| 現在のバージョン | v1.74.0(2026年3月時点) |
| Pythonバージョン | 3.9以上 |
| サポートモデル | OpenAI, Anthropic, Google Gemini, Groq, Mistral, Ollamaなど多数 |
| 主要機能 | 構造化出力、ツール呼び出し、依存性注入、ストリーミング、TestModel |
| GitHubスター数 | 16,000以上 |
| 本番環境対応 | はい、v1.0は2025年9月にリリース |
| 観測可能性 | ネイティブLogfire統合(OpenTelemetryベース) |
| 学習曲線 | Pydantic/FastAPIを知っていれば低、そうでなければ中程度 |
際立つ特徴は、構造化出力(Pydanticモデルで検証)、依存性注入(FastAPIのDependsのような仕組み)、そしてTestModel(API呼び出しなしでテストするためのモックLLM)です。LangChainから移行して「もっとクリーンなものはあるか?」と考えているなら、これがその答えでしょう。
インストールと最初のエージェント
# Install with OpenAI support (swap openai for anthropic, google, etc.)
pip install "pydantic-ai[openai]"
# Set your API key
export OPENAI_API_KEY="sk-..."5行で書く最初のエージェント:
from pydantic_ai import Agent
agent = Agent("openai:gpt-4o", system_prompt="You are a helpful assistant.")
result = agent.run_sync("What's the capital of France?")
print(result.output) # "Paris"これだけです。Agentがモデルをラップし、run_syncがプロンプトを送信して結果を返します。ここでのresult.outputは単なる文字列ですが、これはすぐに変わります。
構造化出力:Pydantic AIが存在する理由
これがコア機能です。LLMから文字列を受け取り、それが有効なJSONであることを祈るのではなく、Pydanticモデルを定義することで、エージェントは検証済みのPythonオブジェクトを返します。
Before:生のLLM出力
# The old way -- hope for the best
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Review the movie Inception. Return JSON with title, rating (1-10), summary."}]
)
# response.choices[0].message.content is a string
# Maybe it's JSON. Maybe it has markdown code fences. Maybe rating is "eight".
# You're on your own.After:Pydantic AIによる構造化
from pydantic import BaseModel
from pydantic_ai import Agent
class MovieReview(BaseModel):
title: str
rating: int # Guaranteed to be an int, not "eight"
summary: str
recommended: bool
agent = Agent("openai:gpt-4o", result_type=MovieReview)
result = agent.run_sync("Review the movie Inception")
review = result.output # This is a MovieReview instance, not a string
print(f"{review.title}: {review.rating}/10")
print(f"Recommended: {review.recommended}")
print(review.summary)その違いは歴然です。result.outputは実際のMovieReviewオブジェクトになります。もしLLMがrating: 8ではなくrating: "eight"を返した場合、Pydanticの検証機能がそれを捕捉します。異なるプロバイダー間でこれがどのように機能するかについて詳しく知りたい場合は、LLMプロバイダー間での構造化出力に関するガイドをご覧ください。
検証が失敗した場合に起こること
他のチュートリアルでは示されない部分があります。LLMがミスをした場合に何が起こるかです。
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class StrictReview(BaseModel):
title: str
rating: int = Field(ge=1, le=10) # Must be 1-10
pros: list[str] = Field(min_length=2) # At least 2 pros
agent = Agent("openai:gpt-4o", result_type=StrictReview)
# If the LLM returns rating=15 or only 1 pro:
# 1. Pydantic validation fails
# 2. The error message is sent BACK to the LLM
# 3. The LLM tries again with the corrected output
# 4. This repeats up to the retry limit
result = agent.run_sync("Review the movie Inception")このフィードバック付きのリトライループは、Pydantic AIのキラー機能です。LLMは自身の検証エラーから学習します。リトライロジックを書く必要はなく、フレームワークが処理してくれます。
結論:生API呼び出しよりもPydantic AIを使用する最大の理由は、構造化出力です。 もし手動でLLMのJSONをパースしているなら、今すぐやめましょう。
ツールと関数呼び出し
ツールを使用すると、エージェントがPython関数を呼び出して実データを取得できます。LLMが事実を捏造する代わりに、データベースをクエリしたり、ドキュメントを検索したり、APIを呼び出したりすることができます。
ツールの登録
from pydantic_ai import Agent
agent = Agent("openai:gpt-4o")
@agent.tool
async def search_docs(query: str) -> str:
"""Search the documentation for relevant articles."""
# Your actual search logic here
results = await doc_search_engine.search(query, limit=5)
return "\n".join(r.title + ": " + r.snippet for r in results)@agent.toolデコレータが関数を登録します。Pydantic AIは関数の型ヒントとdocstringを読み取り、LLMに対してツールが何を行うか、どのような引数を取るか、何を返すかを伝えます。手動でスキーマを書く必要はありません。型ヒントこそがスキーマなのです。LLM関数呼び出しの内部動作についての背景知識については、専用のガイドを用意しています。
RunContext:ツールへのデータ受け渡し
ここでPydantic AIは他のフレームワークとは異なります。RunContextを使用すると、グローバル状態なしでランタイムデータ(データベース接続、ユーザー情報、APIクライアントなど)をツールに渡すことができます。
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
@dataclass
class SupportDeps:
customer_id: str
db_connection: DatabaseConnection
agent = Agent("openai:gpt-4o", deps_type=SupportDeps)
@agent.tool
async def get_order_history(ctx: RunContext[SupportDeps], limit: int = 5) -> str:
"""Fetch recent orders for the current customer."""
orders = await ctx.deps.db_connection.query(
"SELECT * FROM orders WHERE customer_id = $1 ORDER BY date DESC LIMIT $2",
ctx.deps.customer_id, limit
)
return format_orders(orders)ctx.depsにより、ツールはランタイム時に渡されたあらゆるものにアクセスできます。ツールはグローバルなデータベース接続をインポートするのではなく、それを受け取ります。これが依存性注入であり、エージェントをテスト可能にする要因です。
実世界でのツール例
@agent.tool
async def run_sql_query(ctx: RunContext[SupportDeps], sql: str) -> str:
"""Run a read-only SQL query against the analytics database.
Only SELECT queries are allowed."""
if not sql.strip().upper().startswith("SELECT"):
return "Error: only SELECT queries are allowed"
results = await ctx.deps.db_connection.fetch(sql)
return json.dumps(results, default=str)結論:型ヒントが重労働を引き受けるため、Pydantic AIのツール呼び出しは他のどのフレームワークよりもクリーンです。 型注釈付きの通常のPython関数を書くだけで、残りはフレームワークが処理します。
依存性注入:LangGraphが憧れる機能
FastAPIのDependsを使ったことがあれば、Pydantic AIのDIシステムはすでに理解できているでしょう。使ったことがない場合の要点は次の通りです。エージェントが必要なもの(グローバルなデータベース接続、APIクライアント、設定など)を自ら取りに行くのではなく、ランタイム時にすべてを手渡します。
依存関係の定義
from dataclasses import dataclass
from pydantic_ai import Agent
@dataclass
class AppDeps:
db: AsyncDatabasePool
search_client: SearchAPIClient
current_user: User
agent = Agent(
"openai:gpt-4o",
deps_type=AppDeps,
system_prompt="You are a customer support agent."
)ツールでの依存関係の使用
@agent.tool
async def lookup_account(ctx: RunContext[AppDeps]) -> str:
"""Look up the current user's account details."""
account = await ctx.deps.db.fetchrow(
"SELECT * FROM accounts WHERE user_id = $1",
ctx.deps.current_user.id
)
return json.dumps(account, default=str)
# Run with real dependencies
result = await agent.run(
"What's my account status?",
deps=AppDeps(db=real_db, search_client=real_search, current_user=user)
)DIがエージェントをテスト可能にする理由
これが真の成果です。LangChainでは、コンテキストをチェーンのkwargsやクロージャを通じて渡す必要があり、標準的なパターンが存在しません。Pydantic AIでは、実際の依存関係をテスト用ダブルスに置き換えることが容易です。
# In your test file
from pydantic_ai import Agent
from your_app import agent, AppDeps
async def test_account_lookup():
mock_deps = AppDeps(
db=MockDatabase({"user_123": {"status": "active", "plan": "pro"}}),
search_client=MockSearch(),
current_user=User(id="user_123")
)
result = await agent.run("What's my account status?", deps=mock_deps)
assert "active" in result.output
assert "pro" in result.outputモンキーパッチング不要。グローバルインポートのモック化不要。単に異なるdepsを渡すだけです。
結論:依存性注入こそが、経験豊富なPython開発者がPydantic AIを好む理由です。FastAPIの影響が色濃く現れています。
モデルプロバイダー:OpenAI, Anthropic, Gemini, Ollama
Pydantic AIはモデル非依存です。プロバイダーの切り替えは1行の変更で済みます。
# OpenAI
agent = Agent("openai:gpt-4o")
# Anthropic
agent = Agent("anthropic:claude-sonnet-4-20250514")
# Google Gemini
agent = Agent("google-gla:gemini-2.0-flash")
# Local Ollama
agent = Agent("ollama:llama3.1")その他すべて、ツール、構造化出力、DIは同一のままです。モデルを切り替えてもビジネスロジックは変更されません。
| プロバイダー | モデル | 無料枠 | 設定の複雑さ |
|---|---|---|---|
| OpenAI | GPT-4o, GPT-4o mini, o1 | $5クレジット(新規アカウント) | 低、APIキーのみ |
| Anthropic | Claude Sonnet, Haiku, Opus | 無料枠なし | 低、APIキーのみ |
| Google Gemini | Gemini 2.0 Flash, Pro | 充実した無料枠 | 中、プロジェクト設定必要 |
| Groq | Llama, Mixtral | 無料枠あり | 低、APIキーのみ |
| Ollama (ローカル) | Llama, Mistral, Phi等 | 完全無料 | 中、Ollamaインストール必要 |
結論:モデル非依存の設計により、特定のプロバイダーにロックインされることはありません。 利便性のためにOpenAIから始め、Anthropicでベンチマークを取り、ローカル開発にはOllamaを使用しましょう。
ストリーミングレスポンス
チャットUIやリアルタイムアプリケーションにとって、ストリーミングは不可欠です。Pydantic AIは型安全性を維持しながらこれをサポートします。
from pydantic_ai import Agent
from pydantic import BaseModel
class AnalysisResult(BaseModel):
summary: str
sentiment: str
confidence: float
agent = Agent("openai:gpt-4o", result_type=AnalysisResult)
async def stream_analysis(text: str):
async with agent.run_stream(f"Analyze this text: {text}") as stream:
async for partial in stream.stream_structured():
# partial is a partially-validated AnalysisResult
print(f"Streaming: {partial}")
# Final result is fully validated
result = await stream.get_output()
print(f"Final: {result.summary} ({result.confidence:.0%} confident)")これはFastAPIのStreamingResponseと美しく連携します。同じエコシステム、同じパターンです。Pydantic AIエージェントドキュメントでは、stream_text()を使用したテキスト専用ストリーミングを含む高度なストリーミングオプションについても説明されています。
Pydantic AI vs LangGraph vs OpenAI Agents SDK
あなたは今ここにいます。おそらく「Pydantic AIとLangGraph、どちらを使うべきか?」と問っているのでしょう。率直な答えは、これらは異なる問題を解決しており、両方使用する可能性があるということです。
機能比較表
| 機能 | Pydantic AI | LangGraph | OpenAI Agents SDK |
|---|---|---|---|
| 型安全性 | 完全(Pydanticモデル) | 部分的(TypedDict) | 最小限 |
| 依存性注入 | 組み込み(FastAPIスタイル) | なし | なし |
| 構造化出力 | リトライ機能付きネイティブ対応 | 出力パーサー経由 | JSONモード経由 |
| ツール呼び出し | @agent.toolデコレータ | @toolデコレータ | 関数定義 |
| マルチエージェント | 基本的なハンドオフ | 高度(ステートマシン) | ハンドオフ+ガードレール |
| ストリーミング | 型付きストリーミング | ストリーミングイベント | ストリーミング |
| モデルサポート | 10以上のプロバイダー | 主にLangChainモデル | OpenAIのみ |
| テスト | TestModel組み込み | 組み込みテストなし | 組み込みテストなし |
| 学習曲線 | 低(Pydanticを知っていれば) | 高(グラフ概念) | 低(シンプルなAPI) |
| コミュニティ規模 | 成長中(16Kスター) | 大(LangChainエコシステム) | 成長中(OpenAI支援) |
| 最適な用途 | クリーンでテスト可能なエージェント | 複雑なステートワークフロー | OpenAI限定プロジェクト |
各ツールの使い分け
Pydantic AIを選ぶ場合:クリーンで型安全なエージェントコードが必要なときです。ツールを持つ単一エージェントタスク(顧客サポートボット、データ抽出、コードレビューエージェント)や、テスト性が重要な状況に理想的です。チームがすでにFastAPIとPydanticを使用している場合、学習曲線はほぼ平坦です。
LangGraphを選ぶ場合:条件分岐、人間による承認ループ、洗練されたステート管理を伴う複雑なマルチステップワークフローが必要なときです。LangGraphは個々のエージェントの品質よりも、複数のステップをオーケストレーションすることに優れています。詳細については、LangGraph vs CrewAI vs OpenAI Agents SDKの完全比較をご覧ください。
OpenAI Agents SDKを選ぶ場合:100% OpenAI環境で、可能な限りシンプルなセットアップを望み、マルチプロバイダーサポートやDIが必要ないときです。
組み合わせパターン
経験豊富なチームが実際に行っていることは次の通りです。個々のエージェントにはPydantic AI(クリーンなコード、テスト可能、型付き出力)を使用し、エージェント間のオーケストレーション(ルーティング、ステートマシン、条件ロジック)にはLangGraphを使用します。これらは競合するものではなく、補完的な層です。
# Pydantic AI agent -- clean, testable, type-safe
support_agent = Agent("openai:gpt-4o", result_type=SupportResponse, deps_type=SupportDeps)
# LangGraph graph -- orchestrates when to call which agent
graph = StateGraph(SupportState)
graph.add_node("classify", classify_intent)
graph.add_node("support", lambda state: support_agent.run_sync(state["query"]))
graph.add_node("escalate", escalate_to_human)結論:クリーンでテスト可能なエージェントコードにはPydantic AIを選択してください。複雑なマルチステップワークフローにはLangGraphを選択してください。これらは相互排他的ではありません。
TestModelを使用したエージェントのテスト
ここからが初心者ガイドと本番環境向けガイドを分ける部分です。すべての実用的なコードベースにはテストが必要ですが、エージェントのテストは notoriously 困難です。LLM呼び出しは遅く、高価で、非決定的だからです。Pydantic AIはその解決策を提供します:TestModel。
from pydantic_ai import Agent
from pydantic_ai.models.test import TestModel
from pydantic import BaseModel
class SupportResponse(BaseModel):
answer: str
confidence: float
escalate: bool
agent = Agent("openai:gpt-4o", result_type=SupportResponse)
# In tests: swap the real model for TestModel
def test_support_agent():
with agent.override(model=TestModel()):
result = agent.run_sync("I need help with billing")
# TestModel returns valid structured data matching your result_type
assert isinstance(result.output, SupportResponse)
assert isinstance(result.output.confidence, float)
assert isinstance(result.output.escalate, bool)TestModelは、API呼び出しを行わずにresult_typeに一致する有効なデータを生成します。コストゼロ、決定的、高速です。Pydantic AIテストドキュメントでは、カスタムレスポンス用のFunctionModelやツール呼び出しを検査するためのcapture_run_messagesなどの高度なパターンについても説明されています。
ツールとDIを一緒にテストする
def test_order_lookup_tool():
# Mock dependencies
mock_deps = SupportDeps(
customer_id="test-123",
db_connection=MockDB(orders=[{"id": "ord-1", "status": "shipped"}])
)
with agent.override(model=TestModel()):
result = agent.run_sync(
"Where is my order?",
deps=mock_deps
)
assert isinstance(result.output, SupportResponse)API呼び出しなし。不安定なテストなし。コストなし。これをCI/CDパイプラインで残りのテストスイートと一緒に実行しましょう。
これはSERP全体における最大のコンテンツギャップです。 他のPydantic AIガイドはいずれもテストについて触れていません。本番環境向けにエージェントを構築しているなら、这正是に必要なものです。
観測可能性:5分でLogfire統合
本番環境のエージェントにはAI観測可能性が必要です。すべてのLLM呼び出し、ツール起動、レイテンシ、トークン数、コストを確認したいはずです。Pydantic AIは、Pydanticチームの観測可能性プラットフォーム(OpenTelemetryベース)であるLogfireとネイティブに統合されています。
import logfire
from pydantic_ai import Agent
logfire.configure() # Uses LOGFIRE_TOKEN env var
logfire.instrument_pydantic_ai()
agent = Agent("openai:gpt-4o", result_type=MovieReview)
# Every run is now traced automatically
result = agent.run_sync("Review Inception")3行だけです。送信されたプロンプト、モデルレスポンス、ツール呼び出し(あれば)、検証の成功/失敗、リトライ、レイテンシ、推定コストを示す完全なトレースが得られます。Logfireが好みでない場合、Langfuseはプロンプトの進化を追跡するためのコンテキストエンジニアリングサポートを備えた堅実なオープンソースの代替手段です。
FAQ
Pydantic AIとは何ですか?また、LangChainとの違いは何ですか?
Pydantic AIは、Pythonの型ヒントが検証、ツールスキーマ、依存性注入を駆動する型安全なエージェントフレームワークです。LangChainは、LLM呼び出しを連鎖させることに焦点を当てたより大きなフレームワークです。主な違いは、Pydantic AIはフレームワークレベルで出力を検証し、テスト可能性のための組み込み依存性注入を提供しますが、LangChainはデフォルトではどちらも提供しないことです。
Pydantic AIで型安全なAIエージェントを構築するにはどうすればよいですか?
出力用のPydantic BaseModelを定義し、それをAgentのresult_typeとして渡し、run_sync()またはrun()を呼び出します。エージェントは生の文字列ではなく、モデルの検証済みインスタンスを返します。完全な例については「構造化出力」セクションをご覧ください。
本番環境向けエージェントにはPydantic AIとLangGraphのどちらを使うべきですか?
型安全性、テスト可能性、クリーンなコードが重要な個々のエージェントにはPydantic AIを使用してください。条件付きルーティングを伴う複雑なマルチステップワークフローのオーケストレーションにはLangGraphを使用してください。多くのチームは、LangGraphオーケストレーション層内でPydantic AIエージェントを使用するなど、両方を併用しています。
Pydantic AIはツール呼び出しと依存性注入をどのように処理しますか?
関数を@agent.toolでデコレートすると、Pydantic AIはその型ヒントを読み取ってツールスキーマを生成します。DIの場合、Agentにdeps_typeを設定し、ツールでRunContext[YourDeps]を受け入れます。ランタイム依存関係(DB接続、APIクライアント)はグローバル状態なしで流れます。
Pydantic AIエージェントにストリーミングを追加するにはどうすればよいですか?
agent.run()の代わりにagent.run_stream()を使用します。これは、stream_structured()またはstream_text()を通じて部分的な結果をyieldする非同期コンテキストマネージャーを返します。最終結果は依然としてresult_typeに対して完全に検証されます。
Pydantic AIは2026年に本番環境対応ですか?
はい。バージョン1.0は2025年9月にリリースされ、APIの安定性に関するコミットメントとともに提供されました。これはデータ検証で最もダウンロードされているPythonライブラリであるPydanticチームによって支援されており、現在v1.74.0で定期的な更新が行われています。
Pydantic AIをOllamaやローカルモデルで使用できますか?
はい。Agent("ollama:llama3.1")を使用し、Ollamaがローカルで実行されていることを確認してください。Ollamaプロバイダーのエクストラをインストールします:pip install "pydantic-ai[ollama]"。構造化出力とツールはクラウドプロバイダーと同じように動作します。
Pydantic AIエージェントをテストするにはどうすればよいですか?
API呼び出しなしでresult_typeに一致する有効な構造化データを生成するモックモデルであるTestModelを使用します。テストをagent.override(model=TestModel())で囲み、出力に対してアサーションを実行します。完全なpytestの例については「テスト」セクションをご覧ください。
Pydantic AIはFastAPIと連携しますか?
完璧に連携します。これらは同じ依存性注入の哲学を共有し、同じチームによって構築されています。FastAPIエンドポイント内でPydantic AIエージェントを使用し、それらの間で依存関係の型を共有し、StreamingResponseを通じてエージェントレスポンスをストリーミングすることができます。
Pydantic AIとOpenAI Agents SDKの違いは何ですか?
Pydantic AIはモデル非依存(OpenAI、Anthropic、Gemini、Ollamaなどで動作)で、依存性注入、テスト用TestModel、Pydantic検証を備えています。OpenAI Agents SDKはよりシンプルですが、OpenAIモデルに限定されており、DIや組み込みテストがありません。柔軟性が必要な場合はPydantic AIを選び、可能な限りシンプルなOpenAI限定セットアップが必要な場合はOpenAI Agents SDKを選びます。
主要なポイントと次のステップ
| 概念 | 主要な洞察 | 次のステップ |
|---|---|---|
| 構造化出力 | result_typeは自動的に検証およびリトライされる | すべてのエージェント出力に対してPydanticモデルを定義する |
| ツール | 型ヒントこそがスキーマであり、手動定義は不要 | @agent.toolとRunContextを使用してツールを構築する |
| 依存性注入 | テスト可能性のためにランタイムdepsを明示的に渡す | エージェントごとにdeps_typeデータクラスを定義する |
| テスト | TestModelによりCI/CDでのAPIコストを排除 | テストスイートにagent.override(model=TestModel())を追加する |
| モデルプロバイダー | コード変更なしで1行でモデル切り替え | OpenAIから始め、後で代替案をベンチマークする |
| 観測可能性 | 完全なトレースのための3行Logfireセットアップ | 本番環境にlogfire.instrument_pydantic_ai()を追加する |
構造化出力を持つ小さなエージェントから始めてください。ツールを追加し、依存関係を追加し、TestModelでテストを書きます。それが本番環境への道であり、今あなたはその道を歩むために必要なすべてを持っています。
さらに深く学ぶためには、公式Pydantic AIドキュメントとGitHubリポジトリが優れています。フレームワークは急速に進化するため、チェンジログをブックマークしておきましょう。