PydanticAIで型安全なAIエージェントを構築する実践ガイド

PydanticAI v1.54を使って型安全なAIエージェントを構築する方法を、動くPythonコード付きで実践解説。構造化出力・依存性注入・ツール定義・MCP連携まで一貫してカバーします。

AIエージェント開発が急速に進化する2026年、プロダクションレベルのエージェントを本気で構築しようとすると、「型安全性」と「信頼性」が避けて通れない課題になります。正直なところ、LLMの出力って予測不可能なことが多いですよね。そこで注目したいのがPydanticAIです。

PydanticAIは、Pythonのデータバリデーションライブラリ「Pydantic」の開発チームが手がけたAIエージェントフレームワークで、構造化出力・依存性注入・MCP連携といった、プロダクション向けの機能をしっかり備えています。

この記事では、PydanticAI v1.54(2026年2月リリース)を使って、型安全なAIエージェントをゼロから構築する方法を実際に動くコード例とともに解説していきます。日本語の既存記事だと基本的な導入で終わっているものが多いので、構造化出力・依存性注入・ツール定義・MCP統合までを一貫してカバーする実践ガイドとしてまとめました。

PydanticAIとは ─ FastAPIのようなAIエージェント開発

PydanticAIは、生成AIを用いたプロダクショングレードのアプリケーションを迅速かつ安全に構築するために設計されたPythonエージェントフレームワークです。

イメージとしては、FastAPIがWebフレームワーク開発に革命をもたらしたのと同じような感覚です。PydanticAIはAIエージェント開発に「構造化」と「型安全性」を持ち込んでくれます。FastAPIを使ったことがある方なら、そのDXの良さにピンとくるはずです。

主な特徴をざっと紹介します。

  • モデル非依存(Model-Agnostic):OpenAI、Anthropic(Claude)、Gemini、DeepSeek、Mistral、Grokなど主要LLMをすべてサポート
  • 型安全な構造化出力:Pydanticモデルによるレスポンスの検証と型チェック
  • 依存性注入システム:エージェントにデータベース接続やAPIクライアントを安全に渡す仕組み
  • MCP・A2Aプロトコル対応:外部ツールや他エージェントとの標準的な連携
  • Human-in-the-Loop:重要な操作前にユーザー承認を求める仕組み
  • Durable Execution:一時的なAPI障害やアプリ再起動を跨いで進捗を保持

環境構築とインストール

PydanticAIはPython 3.10以上が必要です。インストール自体はとてもシンプルです。

pip install pydantic-ai

特定のLLMプロバイダーだけ使うなら、スリム版でインストールを軽くできます。

# OpenAI のみ使用する場合
pip install pydantic-ai-slim[openai]

# Anthropic(Claude)のみ使用する場合
pip install pydantic-ai-slim[anthropic]

# 複数プロバイダーを使用する場合
pip install pydantic-ai-slim[openai,anthropic,google]

APIキーは環境変数で設定します。

export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."

基本的なエージェントの作成

では、まず最もシンプルなエージェントから作ってみましょう。

from pydantic_ai import Agent

# エージェントの作成(モデルを指定)
agent = Agent(
    "openai:gpt-4o",
    system_prompt="あなたは親切な日本語アシスタントです。簡潔に回答してください。"
)

# 同期実行
result = agent.run_sync("Pythonの主な用途を3つ教えてください")
print(result.output)

AgentクラスがPydanticAIの中心的なインターフェースです。run_sync()で同期実行、run()で非同期実行ができます。たった数行でエージェントが動くのは、なかなか気持ちいいですね。

モデルの切り替え

PydanticAIのモデル非依存設計のおかげで、モデルの変更はたった1行で済みます。これは地味にありがたい。

# Claude を使用
agent = Agent("anthropic:claude-sonnet-4-20250514")

# Gemini を使用
agent = Agent("google-gla:gemini-2.0-flash")

# ローカルモデル(Ollama経由)を使用
agent = Agent("ollama:llama3.2")

構造化出力 ─ LLMの応答を型安全にする

個人的に、PydanticAIの最大の魅力はここだと思っています。LLMの応答をPydanticモデルで厳密に検証できる。テキスト出力ではなく、型チェック済みのデータオブジェクトとして応答を受け取れるんです。

LLMにJSON出力を頼んで、帰ってきたデータが微妙に形式が違う…という経験、ありませんか? PydanticAIならその悩みが解消されます。

基本的な構造化出力

from pydantic import BaseModel
from pydantic_ai import Agent


class CodeReview(BaseModel):
    """コードレビューの結果"""
    severity: str  # "low", "medium", "high"
    issues: list[str]
    suggestions: list[str]
    overall_score: int  # 1-10


agent = Agent(
    "openai:gpt-4o",
    output_type=CodeReview,
    system_prompt="あなたはシニアPython開発者です。提供されたコードをレビューしてください。"
)

result = agent.run_sync("def add(a, b): return a + b")

# result.output は CodeReview 型(型安全)
print(f"重要度: {result.output.severity}")
print(f"スコア: {result.output.overall_score}/10")
for issue in result.output.issues:
    print(f"  - {issue}")

output_typeにPydanticモデルを指定するだけで、LLMの応答が自動的にそのスキーマに従って検証されます。バリデーションに失敗した場合は、PydanticAIがエラー内容をモデルにフィードバックして自動リトライしてくれます(このリトライ機能がかなり便利)。

Union型による複数の出力パターン

状況に応じて異なる型を返したいケースもありますよね。PydanticAIならUnion型でスマートに対応できます。

from pydantic import BaseModel
from pydantic_ai import Agent


class Success(BaseModel):
    result: str
    confidence: float


class NeedMoreInfo(BaseModel):
    missing_fields: list[str]
    question: str


agent = Agent(
    "openai:gpt-4o",
    output_type=Success | NeedMoreInfo,  # Union型
    system_prompt="ユーザーの質問に回答してください。情報が不足している場合はNeedMoreInfoを返してください。"
)

result = agent.run_sync("東京の天気は?")

match result.output:
    case Success(result=r, confidence=c):
        print(f"回答: {r} (確信度: {c})")
    case NeedMoreInfo(missing_fields=fields, question=q):
        print(f"追加情報が必要です: {q}")
        print(f"不足フィールド: {fields}")

依存性注入 ─ 外部サービスを安全にエージェントへ渡す

実際のアプリケーションでは、エージェントがデータベースやAPIなどの外部サービスにアクセスする必要がほぼ確実に出てきます。PydanticAIの依存性注入システムを使えば、これらを型安全にエージェントへ渡せます。

FastAPIの依存性注入を使ったことがある方なら、すぐに馴染めるはずです。

from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext
import httpx


@dataclass
class AppDependencies:
    """エージェントが使用する外部依存"""
    http_client: httpx.AsyncClient
    api_key: str
    user_id: str


class ProductInfo(BaseModel):
    name: str
    price: float
    availability: str


agent = Agent(
    "openai:gpt-4o",
    deps_type=AppDependencies,
    output_type=ProductInfo,
    system_prompt="あなたは商品検索アシスタントです。"
)


@agent.tool
async def search_product(ctx: RunContext[AppDependencies], query: str) -> str:
    """商品データベースを検索する"""
    response = await ctx.deps.http_client.get(
        "https://api.example.com/products",
        params={"q": query, "user_id": ctx.deps.user_id},
        headers={"Authorization": f"Bearer {ctx.deps.api_key}"}
    )
    return response.text


# 実行時に依存関係のインスタンスを渡す
async def main():
    async with httpx.AsyncClient() as client:
        deps = AppDependencies(
            http_client=client,
            api_key="your-api-key",
            user_id="user-123"
        )
        result = await agent.run(
            "ワイヤレスイヤホンのおすすめを教えて",
            deps=deps
        )
        print(result.output)

押さえておきたいポイントは以下です。

  • deps_typeにはデータクラスのを渡す(インスタンスではなく型そのもの)
  • ツール関数ではRunContext[AppDependencies]で依存関係にアクセスできる
  • 実行時にdeps=でインスタンスを注入する
  • 型が一致しない場合、静的型チェッカーがちゃんとエラーを出してくれる

ツール定義 ─ エージェントに「手足」を与える

ここからが楽しいところです。ツールを定義することで、エージェントは外部APIの呼び出し、データベースクエリ、ファイル操作などを実行できるようになります。

PydanticAIでは3つの方法でツールを登録できます。

デコレータによるツール定義

from pydantic_ai import Agent, RunContext

agent = Agent("openai:gpt-4o")


@agent.tool
async def get_weather(ctx: RunContext, city: str) -> str:
    """指定した都市の天気情報を取得する

    Args:
        city: 天気を調べたい都市名(日本語)
    """
    # 実際のAPI呼び出し
    return f"{city}の天気: 晴れ、気温22℃"


@agent.tool_plain
def calculate_bmi(weight_kg: float, height_cm: float) -> str:
    """BMIを計算する(コンテキスト不要の場合はtool_plainを使用)"""
    height_m = height_cm / 100
    bmi = weight_kg / (height_m ** 2)
    return f"BMI: {bmi:.1f}"

@agent.toolはRunContextにアクセスする必要がある場合に、@agent.tool_plainはコンテキスト不要な場合に使います。ちなみに、関数のdocstringがそのままツールの説明としてLLMに渡されるので、わかりやすい説明を書くことが思った以上に重要です。

エラーハンドリングとリトライ

from pydantic_ai import ModelRetry

@agent.tool
async def fetch_data(ctx: RunContext, query: str) -> str:
    """データを取得する"""
    try:
        result = await external_api_call(query)
        return result
    except ValueError as e:
        # ModelRetryでエージェントにリトライを要求
        raise ModelRetry(f"クエリを修正してください: {e}")

ModelRetryをraiseすると、PydanticAIがエラーメッセージをLLMに送り返して、改善されたパラメータでの再呼び出しを促してくれます。単純なリトライではなく、LLMが「考え直して」再挑戦してくれるのがポイントです。

MCP連携 ─ 外部ツールとの標準接続

Model Context Protocol(MCP)は、AIと外部ツールを標準化された方法で接続するオープンプロトコルです。2026年に入ってから対応フレームワークが一気に増えました。PydanticAIはMCPクライアントとしてもMCPサーバーとしても動作できます。

MCPサーバーへの接続

from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio, MCPServerStreamableHTTP

# stdio トランスポート(ローカルプロセス)
file_server = MCPServerStdio(
    "npx", "-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"
)

# Streamable HTTP トランスポート(リモートサーバー)
remote_server = MCPServerStreamableHTTP("https://mcp.example.com/sse")

agent = Agent(
    "openai:gpt-4o",
    toolsets=[file_server, remote_server]  # ツールセットとして登録
)


async def main():
    # コンテキストマネージャでMCP接続を管理
    async with agent:
        result = await agent.run("プロジェクトのREADME.mdの内容を要約して")
        print(result.output)

MCPサーバーをtoolsetsに渡すだけで、そのサーバーが提供するすべてのツールがエージェントから使えるようになります。接続のライフサイクル管理はasync with agentに任せればOKです。

Human-in-the-Loop ─ 重要操作の承認フロー

本番環境でエージェントを動かすとき、メール送信やデータ更新のような「取り消しが難しい操作」を勝手にやられたら困りますよね。そこで必要になるのがHuman-in-the-Loopです。

from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-4o",
    system_prompt="あなたはメール送信アシスタントです。"
)


@agent.tool(require_approval=True)
async def send_email(ctx, to: str, subject: str, body: str) -> str:
    """メールを送信する(承認が必要)"""
    # 承認後にのみ実行される
    await actually_send_email(to, subject, body)
    return f"{to}にメールを送信しました"

require_approval=Trueを設定するだけで、ツール呼び出し前にアプリケーション側で承認・拒否を挟めます。承認ロジックはツールの引数や会話履歴に基づいてカスタマイズできるので、柔軟性も十分です。

プロダクション運用のベストプラクティス

Logfireによるオブザーバビリティ

PydanticAIはPydantic Logfireと統合されており、エージェントの実行をリアルタイムで監視・デバッグできます。セットアップもかなり簡単です。

import logfire

logfire.configure()
logfire.instrument_pydantic_ai()

# 以降、すべてのエージェント実行が自動的にトレースされる

同時実行制御

v1.54で追加された同時実行制限機能も見逃せません。エージェントやモデルの並列リクエスト数を制御できるので、APIのレート制限対策に役立ちます。

agent = Agent(
    "openai:gpt-4o",
    max_concurrent=5  # 同時実行を5に制限
)

出力バリデーションの強化

from pydantic_ai import Agent, RunContext


@agent.output_validator
async def validate_output(ctx: RunContext, output: CodeReview) -> CodeReview:
    """ビジネスルールに基づく出力検証"""
    if output.overall_score < 1 or output.overall_score > 10:
        raise ModelRetry("overall_scoreは1から10の間で設定してください")
    return output

テスト戦略

テストのしやすさもPydanticAIの強みです。専用のモックモデルが用意されているので、LLM APIを呼ばずにユニットテストが書けます。

from pydantic_ai.models.test import TestModel

agent = Agent(
    "openai:gpt-4o",
    output_type=CodeReview
)

# テスト時はTestModelで置き換え
with agent.override(model=TestModel()):
    result = agent.run_sync("テスト入力")
    # LLM APIを呼ばずにテスト実行可能

CI/CDパイプラインにもそのまま組み込めるので、実用性は高いです。

LangChain・CrewAIとの比較

2026年のAIエージェントフレームワーク選定で迷っている方向けに、PydanticAIの立ち位置を整理しておきます。

  • PydanticAI:型安全性・依存性注入・構造化出力に特化。Pythonの標準的なパターンに沿った設計で、プロダクション運用に強い
  • LangChain / LangGraph:エコシステムが豊富。複雑なマルチエージェントワークフローをグラフ構造で宣言的に定義できる。コミュニティリソースも充実
  • CrewAI:ロールベースのマルチエージェント協調に特化。チーム型のタスク分担を直感的に定義できる

ざっくり言えば、型安全性とプロダクション品質を最優先するならPydanticAI、複雑なグラフ構造のワークフローならLangGraph、チーム型の協調タスクならCrewAIがそれぞれ適しています。もちろん、組み合わせて使うことも可能です。

よくある質問(FAQ)

PydanticAIは無料で使えますか?

はい、PydanticAIフレームワーク自体はMITライセンスのオープンソースで、無料で利用できます。ただし、LLM APIの利用にはOpenAIやAnthropicなど各プロバイダーの料金がかかります。ローカルモデル(Ollama経由など)を使えばAPI料金なしで試すことも可能です。

PydanticAIとLangChainはどちらを使うべきですか?

プロジェクトの性質によります。型安全性と構造化出力を重視して堅牢なプロダクションアプリを作りたいならPydanticAIが向いています。一方、豊富な既存コンポーネントや大規模なコミュニティを活用したい場合はLangChainが有利です。ちなみに、両者は排他的ではなく、PydanticAIのエージェントをLangChainのワークフローに組み込むことも可能です。

PydanticAIでマルチエージェントシステムは構築できますか?

はい、可能です。Graph機能で複数エージェントの連携を型安全に定義できますし、A2A(Agent-to-Agent)プロトコルによって異なるフレームワーク間のエージェント相互運用も実現できます。MCPサーバーとしてエージェントを公開し、他のエージェントから呼び出す構成も取れます。

PydanticAIで日本語のLLMは使えますか?

もちろん使えます。PydanticAIはモデル非依存設計なので、日本語対応のLLMであればどれでもOKです。GPT-4o、Claude、Geminiなど主要モデルはすべて日本語をサポートしていますし、Ollamaを通じて日本語特化のローカルモデルを利用することもできます。

既存のPydanticプロジェクトにPydanticAIを統合できますか?

はい、かなりスムーズに統合できます。PydanticAIはPydanticエコシステムの一部として設計されているので、既存のPydanticモデルをそのままoutput_typeやツールの引数に使えます。FastAPIと組み合わせてAIエンドポイントを構築するパターンも公式に推奨されています。

著者について Editorial Team

Our team of expert writers and editors.