AI

PydanticAIとは|型安全なPythonエージェントの作り方を実装コードで解説

PydanticAIは、データ検証ライブラリPydanticの作者チームが開発したPython製のAIエージェントフレームワークです。LLMの入出力やツールの引数をPydanticの型で検証し、FastAPIで馴染みのある「型ヒント+依存性注入」の書き味でエージェントを組めるのが最大の特徴です。ネット上の解説には @tool デコレーターや OpenAIAgent クラス、型で自動注入される Context クラスといった記述が見られますが、これらはいずれも実在しません。この記事では、2026年7月時点の公式ドキュメントに照合した正しいAPIで、インストールから最小エージェント、ツール定義、依存性注入、構造化出力、モデル非依存、Pydantic AI Gatewayまで、そのまま動くコードで解説します。

まとめ:PydanticAIの要点

  • 正体:Pydanticチーム製の型安全なエージェントフレームワーク。現行はv2系(2026年7月時点で2.10.0)、必要Pythonは3.10以上です。
  • インストールpip install pydantic-ai。プロバイダを絞るなら軽量版 pydantic-ai-slim[openai] を使います。
  • エージェント作成Agent("openai:gpt-5.6") のようにモデル文字列を渡し、run_sync / run / run_stream で実行。結果は .output(旧 .data)で取り出します。
  • ツール@agent.tool(文脈あり)と @agent.tool_plain(文脈なし)で登録。@tool という素のデコレーターは存在しません。
  • 依存性注入deps_typeRunContext[Deps] を使い、ツール内から ctx.deps で参照。型で勝手に注入される「Contextクラス」はありません。
  • 構造化出力output_type にPydanticモデルを渡すと、検証済みの型付きオブジェクトが返ります。
  • モデル非依存:文字列を差し替えるだけでOpenAI・Anthropic・Googleなど30以上のモデルを切り替え可能。Pydantic AI Gatewayで1つのキーに集約もできます。

PydanticAIとは何か|定義・開発元・現行バージョン

PydanticAIは、LLMを使ったエージェントやツール呼び出しのアプリを、Pythonの型ヒントとPydanticモデルを軸に構築するフレームワークです。狙いは明快で、LLMという「出力が予測しづらい処理系」に対して、入力・出力・ツール引数を実行時に型で検証し、失敗したら再試行させることで、堅牢性と保守性を両立させることにあります。現行はv2系(2026年7月時点の最新は2.10.0)で、動作にはPython 3.10以上が必要です。

開発元とPydantic本体との関係

開発元は、FastAPIやLangChainなど多くのライブラリが依存するデータ検証ライブラリPydanticを手がけるチームです。PydanticAIはPydantic本体の「別モード」ではなく、Pydanticを土台にした別パッケージです。Pydanticがデータ構造の定義と検証を担い、PydanticAIがその上でエージェントの実行ループ・ツール呼び出し・依存性注入・構造化出力を提供します。既存のPydanticモデルをそのままツールの引数や出力スキーマに使えるため、FastAPI経験者は学習コストが低いのが利点です。

LangChain・LangGraphとの違いと選びどころ

PydanticAIの差別化点は、型安全性が最初から通っている点にあります。ツールの引数・依存・出力すべてに型が付き、IDEの補完や静的解析がそのまま効きます。LangChainのようなRunnable/DSLの抽象レイヤを重ねるのではなく、素のPython関数と型ヒントで完結させる設計です。状態機械的な分岐フローが必要な場合は、姉妹ライブラリ pydantic-graph がLangGraphに相当する役割を担います。判断の目安は単純で、既存のPython/型ヒント資産を活かして小さく堅く作りたいならPydanticAI、エコシステムの部品数と実績を優先するならLangChain系です。両者の立ち位置はLangChainとLangGraphの違いとv1.0で逆転した関係と併読すると整理しやすくなります。

インストールと最小構成のエージェント

PydanticAIは全部入りの pydantic-ai と、依存を絞った pydantic-ai-slim の2系統で配布されています。使うプロバイダが決まっているなら軽量版を選ぶと不要な依存を持ち込みません。

pip install pydantic-ai
pip install "pydantic-ai-slim[openai]"
pip install "pydantic-ai-slim[openai,anthropic,logfire]"

pydantic-ai と pydantic-ai-slim の使い分け

pydantic-ai は主要プロバイダやツールを一式含む「まず動かす」向けです。本番やCIでは、pydantic-ai-slim にextrasで必要な部分だけを足すのが実務的です。extrasにはプロバイダ(openai anthropic google groq mistral bedrock など)に加え、観測用の logfire、評価用の evals、MCP連携の mcp、耐障害実行の temporal などが揃います。Python 3.10未満では動かない点に注意してください。

最小構成のエージェントを動かす

エージェントは Agent を生成し、run_sync(同期)・run(非同期)・run_stream(ストリーミング)のいずれかで実行します。モデルは "プロバイダ:モデル名" の文字列で指定し、結果は result.output で取り出します(旧APIの .data は改称済み)。

from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-5.6",                 # "プロバイダ:モデル名" 形式
    instructions="1文で簡潔に答えて。",
)

result = agent.run_sync("PydanticAIとは何ですか?")
print(result.output)                  # 結果は .data ではなく .output

ここで重要なのは、OpenAIAgentLocalAgent のようなプロバイダ別クラスは存在しないという点です。プロバイダは常に汎用の Agent にモデル文字列(またはモデルオブジェクト)で指定します。

ツールの定義とツール呼び出し

ツールは、LLMが必要に応じて呼び出すPython関数です。PydanticAIは関数のシグネチャからJSONスキーマを自動生成し、モデルが正しい引数で関数を呼べるようにします。ChatGPTでいうFunction Callingの仕組みとOpenAI APIでの実装と同じ考え方を、型付きで安全に扱えるのがPydanticAIの強みです。

@agent.tool と @agent.tool_plain の違い

登録方法は2つで、違いは実行文脈(RunContext)を受け取るかどうかだけです。文脈や依存を使うなら @agent.tool、純粋な関数なら @agent.tool_plain を使います。@tool という単体のデコレーターは存在しないので、古い解説を真似しないでください。

import random
from pydantic_ai import Agent, RunContext

agent = Agent("openai:gpt-5.6", deps_type=str)

@agent.tool_plain               # 文脈を受け取らない素の関数
def roll_dice() -> str:
    """6面ダイスを1回振る。"""
    return str(random.randint(1, 6))

@agent.tool                     # 第1引数で RunContext を受け取る
def get_player_name(ctx: RunContext[str]) -> str:
    """プレイヤー名を返す。"""
    return ctx.deps             # 実行時に渡した deps を参照

print(agent.run_sync("賽の目を4と予想します", deps="Anne").output)

tools= 引数でまとめて登録する

デコレーターの代わりに、関数のリストを Agenttools= に渡す形でも登録できます。ツール群を別モジュールで定義して束ねたいときはこちらが便利です。

agent = Agent("openai:gpt-5.6", tools=[roll_dice, get_player_name])

引数と戻り値にPydanticモデルを使えば、ツール呼び出し時の型不一致をその場で検出できます。LangGraphのToolNodeによるTool Callingの実装と比べると、PydanticAIはデコレーター1つで関数をツール化できるぶん記述量が少なく済みます。

依存性注入(deps)とRunContext

PydanticAIの依存性注入は、DBハンドルやAPIキー、HTTPクライアントといった「ツールが必要とするリソース」を型安全に受け渡す仕組みです。エージェント定義をクリーンに保ち、テスト時にモックへ差し替えやすくします。

deps_type と ctx.deps の使い方

手順は3つです。(1) Agent(..., deps_type=MyDeps) で依存の型を宣言する、(2) ツールの第1引数を RunContext[MyDeps] にする、(3) 実行時に agent.run(..., deps=deps) で実体を渡す。ツール内からは ctx.deps で参照します。

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

@dataclass
class MyDeps:                      # 依存(DB接続・APIキー・HTTPクライアント等)を型で束ねる
    api_key: str
    http_client: httpx.AsyncClient

agent = Agent("openai:gpt-5.6", deps_type=MyDeps)

@agent.tool
async def fetch_profile(ctx: RunContext[MyDeps], user_id: str) -> str:
    r = await ctx.deps.http_client.get(
        "https://api.example.com/users",
        params={"id": user_id},
        headers={"Authorization": f"Bearer {ctx.deps.api_key}"},
    )
    r.raise_for_status()
    return r.text

async def main():
    async with httpx.AsyncClient() as client:
        deps = MyDeps(api_key="sk-...", http_client=client)
        result = await agent.run("ユーザー42を要約して", deps=deps)
        print(result.output)

「Contextクラスの自動注入」は存在しない

誤解が多いポイントなので明示します。PydanticAIには、関数の引数に特定の型を書くと、グローバルな文脈から一致するインスタンスが勝手に注入されるような仕組みはありません。依存は必ず deps_type で型を宣言し、実行時に deps= で渡し、RunContext.deps 経由で取り出します。したがって、Contextが解決できなかったときに投げられるとされる NoMatchingContextError という例外も存在しません。この「自動注入されるContext」像は古い解説の創作なので、設計の前提にしないでください。会話をまたいで状態を保つには、後述の message_history(会話履歴)や、依存に持たせたストア(DB・辞書など)を使います。

構造化出力とバリデーション再試行

LLMの出力をそのまま文字列で受けると、後段のパースで崩れがちです。PydanticAIでは output_type にPydanticモデルを渡すことで、モデルの応答を検証済みの型付きオブジェクトとして受け取れます。

from pydantic import BaseModel
from pydantic_ai import Agent

class CityLocation(BaseModel):
    city: str
    country: str

agent = Agent("openai:gpt-5.6", output_type=CityLocation)
result = agent.run_sync("2012年のオリンピック開催地は?")
print(result.output)              # city='London' country='United Kingdom'
print(result.output.city)         # 型付きで属性アクセスできる

出力やツール引数の検証に失敗したとき、単なるエラーで止めるのではなくモデルに修正を促して再試行させられるのも実務で効きます。ツールやバリデータの中で ModelRetry を投げると、その内容がモデルに伝わり、もう一度呼び出しが行われます。

from pydantic_ai import Agent, ModelRetry, RunContext

@agent.tool
def lookup_order(ctx: RunContext[MyDeps], order_id: int) -> str:
    row = ctx.deps.db.get(order_id)   # deps に DB ハンドル db を持たせている前提
    if row is None:
        # 例外でなく ModelRetry を投げると、モデルに修正を促して再試行させられる
        raise ModelRetry(f"注文 {order_id} は存在しません。IDの確認を求めてください。")
    return row

ポイントは、業務ロジックのエラー(存在しないID、権限不足など)を ModelRetry で「モデルへのフィードバック」に変換できることです。無限ループを避けるため、再試行回数には内部で上限があります。

モデル非依存とプロバイダ切り替え

PydanticAIはツールや依存のロジックを特定のLLMに縛りません。Agent がプロバイダとのやり取りを抽象化しているため、処理の本体を作ってしまえば、あとはモデル文字列を差し替えるだけで出力先を変えられます。OpenAI・Anthropic・Google(Gemini)・Groq・Mistral・Bedrock・Cohereなど、30以上のモデルに対応します。

from pydantic_ai import Agent

# モデル文字列を差し替えるだけでプロバイダを切り替えられる
agent = Agent("openai:gpt-5.6")
agent = Agent("anthropic:claude-sonnet-5")
agent = Agent("google:gemini-3-flash")

# モデルオブジェクトを渡す形式(細かい設定が要るとき)
from pydantic_ai.models.anthropic import AnthropicModel
agent = Agent(AnthropicModel("claude-sonnet-5"))

開発中は安価なモデル、本番は高精度なモデル、といった使い分けや、リクエスト内容に応じた動的なモデル選択も、ツール・依存の記述を変えずに実現できます。モデルIDは頻繁に更新されるので、実装時に各プロバイダの最新IDへ読み替えてください(本記事のコードは執筆時点の例です)。

Pydantic AI Gateway|1つのキーで複数プロバイダに集約

「pydantic ai gateway」は、フレームワーク本体とは別に提供されるモデルゲートウェイ(プロキシ)製品です。1本のAPIキーで複数プロバイダへアクセスでき、リクエストは各プロバイダのネイティブ形式のまま通す(変換を挟まない)方式を取ります。加えて、リアルタイムのコスト監視、プロジェクト・ユーザー・キー単位の予算上限、フェイルオーバーやロードバランスのルーティングを備えます。認証と可観測性はPydantic Logfireから管理する構成です。

PydanticAIから使うときは、環境変数にゲートウェイのキーを設定し、モデル文字列の頭に gateway/ を付けるだけです。

export PYDANTIC_AI_GATEWAY_API_KEY="<ゲートウェイのキー>"
from pydantic_ai import Agent

# モデル文字列の頭に gateway/ を付けるとゲートウェイ経由になる
agent = Agent("gateway/openai:gpt-5.6")
result = agent.run_sync("こんにちは")
print(result.output)

複数プロバイダを併用してコストと可用性を一元管理したいチームに向く仕組みで、キー管理やレート対策をアプリ側に散らさずに済みます。個人開発の段階では必須ではなく、まずは素のプロバイダ直結で十分です。

観測・ストリーミング・会話履歴・マルチエージェント

実運用で必要になる機能も一通り揃っています。まず観測性は、同チームのPydantic Logfireと統合しており、1行の計装でエージェント実行・モデル要求・ツール呼び出しがOpenTelemetryのトレースとして可視化されます。商用プラットフォームを使わず任意のOTelバックエンドへ送ることもできます。

import logfire
from pydantic_ai import Agent

logfire.configure()
logfire.instrument_pydantic_ai()   # 全エージェントの実行・モデル要求・ツール呼び出しを計装

agent = Agent("openai:gpt-5.6")
print(agent.run_sync("hello").output)

逐次表示が必要なチャットUIでは run_stream でトークンを流し込めます。

async with agent.run_stream("長い物語を書いて") as response:
    async for text in response.stream_text():
        print(text, end="")

会話を継続するには、前ターンの結果を message_history に渡します。状態は依存(deps)やこの履歴で持ち回るのが基本で、前述のとおり「自動注入されるContext」で暗黙的に共有されるわけではありません。

result1 = agent.run_sync("私の名前はアリスです。")
result2 = agent.run_sync(
    "私の名前は?",
    message_history=result1.new_messages(),   # 直前の会話を引き継ぐ
)
print(result2.output)                         # アリスを覚えている

このほか、あるエージェントのツールから別のエージェントを呼ぶマルチエージェント(委譲)、外部ツールを標準化して繋ぐMCP対応、Temporalなどによる耐障害実行の統合も用意されています。単発のチャットから複数エージェントの協調まで、同じ型安全な土台の上で段階的に拡張できます。

よくあるエラーと原因・対処

開発中に遭遇しやすいエラーは、実在する例外クラスで表現されます。旧来の解説にある捏造された例外名に振り回されないよう、実物を押さえておきましょう。

状況 実在する例外・機構 対処
ツール引数・出力の型不一致 ValidationError(Pydantic) 関数に正しい型注釈を付ける。メッセージで不一致フィールドを特定
モデルに修正を促したい ModelRetry ツール/バリデータ内で送出。内容がモデルに渡り再試行される
モデルが想定外の挙動 UnexpectedModelBehavior プロンプト・出力スキーマを見直す。応答/ステータス異常を確認
プロバイダからの4xx/5xx ModelHTTPError APIキー・レート・課金状態を確認。リトライ設計を入れる
使用量の上限超過 UsageLimitExceeded UsageLimitsの上限や入力サイズを見直す

逆に、ネット上で見かける NoMatchingContextErrorOpenAIAgentLocalAgent・素の @tool・型で自動注入される Context クラスはいずれも存在しません。これらを前提にしたコードは動かないので、公式ドキュメントの実APIに置き換えてください。APIキー未設定による認証エラーやタイムアウトは、環境変数(例:OPENAI_API_KEY)の設定と、HTTPクライアント側のタイムアウト・リトライで対処します。

PydanticAIに関するよくある質問

PydanticAIのインストールは pip でどう書きますか

基本は pip install pydantic-ai です。依存を絞りたい場合は軽量版に必要なプロバイダをextrasで足し、pip install "pydantic-ai-slim[openai]" のように書きます。Python 3.10以上が前提で、それ未満では動きません。仮想環境(venvなど)でプロジェクトごとに分離するのがおすすめです。

ツール(tools)はどう定義しますか。@tool は使えますか

@tool という単体デコレーターは存在しません。実際には @agent.tool(第1引数で RunContext を受け取る)と @agent.tool_plain(文脈を受け取らない)を使うか、Agent(..., tools=[...]) に関数リストを渡します。引数・戻り値にPydanticモデルを使うと型安全にツール呼び出しを扱えます。

pydantic ai の context(依存)はどう渡しますか

Agent(..., deps_type=MyDeps) で依存の型を宣言し、ツールの第1引数を RunContext[MyDeps] にして、実行時に agent.run(..., deps=deps) で実体を渡します。ツール内では ctx.deps で参照します。型を書くだけで勝手に注入される「Contextクラス」はありません。

PydanticAIとLangChainはどう違いますか

PydanticAIは、ツール・依存・出力すべてに型が通る型安全設計で、素のPython関数と型ヒントで完結します。LangChainはRunnable/DSLの抽象と広いエコシステムが強みです。状態機械的なフローが要るなら姉妹の pydantic-graph がLangGraphに相当します。既存のPython資産を活かして小さく堅く作るならPydanticAIが向きます。

Pydantic AI Gatewayとは何ですか

1本のAPIキーで複数プロバイダへアクセスできるモデルゲートウェイ製品です。コスト監視・予算上限・フェイルオーバーを備え、認証と可観測性はLogfireから管理します。PydanticAIからはモデル文字列の頭に gateway/ を付けて利用します。個人開発では必須ではなく、まずはプロバイダ直結で十分です。

関連記事

資料請求

RELATED POSTS 関連記事