【型安全】Pydantic AI超入門!Pythonで堅牢なマルチエージェント・RAGを構築する実践ガイド

1. はじめに:なぜLLM開発に「Pydantic AI」が必要なのか?

AIエージェントやRAG(Retrieval-Augmented Generation)のシステム開発において、開発者を最も悩ませるのが「LLMの出力の不安定さ」です。プロンプトで「JSON形式で返却してください」と指示しても、時として余計なテキストが混ざったり、キーの名前が変わったりして、システムがクラッシュすることがあります。

この課題を解決するために登場したのが、Pythonのデータバリデーションライブラリとして絶大な人気を誇るPydanticの公式開発チームが手がけた Pydantic AI です。

Pydantic AIは、LLMの入出力をPythonの「静的型付け」によって厳密に管理し、型安全なAIエージェント開発を実現します。本記事では、Pydantic AIの基本的な使い方から、実務に役立つコンテキスト注入、マルチエージェントへの応用、そして開発時によく遭遇するエラーの対策まで徹底的に解説します。


2. Pydantic AIのコアコンセプトと特徴

Pydantic AIは、LangChainやLlamaIndexなどの既存フレームワークに比べ、非常にシンプルで直感的な設計になっています。その特徴は以下の3点に集約されます。

  1. 型安全な構造化出力 (Structured Outputs)」 LLMからのレスポンスをPydanticのモデル(BaseModel)として直接受け取れます。パースエラーが発生した場合は、自動的にLLMへ再試行(リトライ)を促す仕組みが内蔵されています。
  2. 依存関係の注入 (Dependency Injection)」 テストや本番環境でデータベース接続、外部APIクライアントなどを動的に切り替える仕組み(Deps)が標準提供されています。
  3. コントロールの容易さ」 過度に抽象化されたマジック(魔法)が少なく、通常のPythonコードと同じ感覚でデバッグやカスタマイズが可能です。最新のLLMフレームワークのトレンドについては、smolagents入門記事 でも紹介されていますが、Pydantic AIは特にプロダクション環境における堅牢性に強みを持っています。

ソースコードは Pydantic AI GitHubリポジトリ で公開されており、急速にコミュニティが拡大しています。


3. 環境構築とクイックスタート

まずは、Pydantic AIをインストールしましょう。今回はOpenAIのAPIを利用する前提でセットアップを進めます。

pip install pydantic-ai openai python-dotenv

環境変数にOpenAIのAPIキーを設定します。

OPENAI_API_KEY=your-api-key-here

シンプルな型安全エージェントの実装

まずは、ユーザーの入力から「ユーザー情報」を構造化データとして抽出する簡単なコードを書いてみましょう。

import os
from pydantic import BaseModel, Field
from pydantic_ai import Agent
from dotenv import load_dotenv

load_dotenv()

# 1. 期待する出力のスキーマをPydanticで定義
class UserProfile(BaseModel):
    name: str = Field(description="ユーザーの名前")
    age: int = Field(description="ユーザーの年齢(推定も含む)")
    skills: list[str] = Field(default=[], description="プログラミングスキルや得意技術")

# 2. エージェントの初期化
# result_typeにPydanticモデルを指定することで、戻り値の型が固定されます
agent = Agent(
    'openai:gpt-4o-mini',
    result_type=UserProfile,
    system_prompt="ユーザーの自己紹介文からプロフィール情報を正確に抽出してください。"
)

# 3. エージェントの実行
result = agent.run_sync("私の名前は田中です。32歳で、PythonとGo言語を普段書いています。")

# 結果の取得(型安全にアクセス可能)
profile: UserProfile = result.data
print(f"名前: {profile.name}")
print(f"年齢: {profile.age}")
print(f"スキル: {', '.join(profile.skills)}")

このコードを実行すると、LLMが返したテキストが自動的に UserProfile のインスタンスにマッピングされます。IDEの型補完(IntelliSense)が効くため、エディタ上で profile. と入力するだけでプロパティが候補に現れます。


4. 【応用】依存関係(Deps)の注入とRAGの実装

実務におけるAIエージェントでは、データベースのクエリ結果や、外部APIから取得した情報をプロンプトに組み込む必要があります。Pydantic AIでは、Deps(Dependencies)オブジェクトを使用して、これらを安全にエージェント内へ注入できます。

以下は、ナレッジベース(疑似的なデータベース)から情報を検索し、それをもとに回答するシンプルなRAGシステムの例です。

from dataclasses import dataclass
from pydantic_ai import Agent, RunContext

# 1. 依存関係のコンテキストを定義
@dataclass
class DatabaseConnection:
    knowledge_base: dict[str, str]

    def query(self, topic: str) -> str:
        return self.knowledge_base.get(topic, "該当する情報が見つかりませんでした。")

# 2. エージェントの作成。deps_typeで注入する型を明示
rag_agent = Agent(
    'openai:gpt-4o-mini',
    deps_type=DatabaseConnection,
    system_prompt="提供されたコンテキスト情報のみを使用して、ユーザーの質問に回答してください。"
)

# 3. システムを補助する「システムツール(Tool)」の定義
@rag_agent.tool
def search_knowledge_base(ctx: RunContext[DatabaseConnection], topic: str) -> str:
    """ナレッジベースから特定のトピックに関する情報を検索します。"""
    # 引数 ctx から安全にデータベース接続を取り出す
    return ctx.deps.query(topic)

# 4. 実行環境のセットアップと実行
db = DatabaseConnection(
    knowledge_base={
        "pydantic-ai": "Pydantic AIは、PythonのPydanticチームが開発した型安全なLLMエージェント構築フレームワークです。",
        "o3-mini": "o3-miniはOpenAIが開発した最新の推論(Reasoning)モデルです。"
    }
)

# 実行時にdepsを渡す
response = rag_agent.run_sync(
    "Pydantic AIとは何ですか?詳しく教えてください。",
    deps=db
)

print(response.data)

このアプローチの素晴らしい点は、テストの際に DatabaseConnection のモック(Mock)を簡単に渡せる点です。ユニットテストが極めて書きやすくなり、プロダクション環境のコード品質が向上します。 (なお、OpenAIのReasoningモデルを活用したい場合は、OpenAI「o3-mini」APIの実装ガイド も参考になります。)


5. よくあるエラーとトラブルシューティング

Pydantic AIの導入時に直面しやすいエラーと、その原因および解決策を解説します。

エラー例1: ValidationError (LLMの出力フォーマット崩れ)

【現象】 LLMが期待通りのJSONフォーマットを返さず、Pydanticがパースを試みた際に pydantic_core._pydantic_core.ValidationError が発生する。

【原因】 使用しているLLMのモデルが構造化出力(Structured Outputs)に完全に対応していない、またはプロンプトが複雑すぎてパースに失敗している。

【解決方法】

  1. APIの構造化出力機能を有効化する: Pydantic AIは、OpenAIなどの response_format={"type": "json_schema", ...} を自動で利用します。可能であれば、構造化出力にネイティブ対応しているモデル(例: gpt-4o, gpt-4o-mini)を使用してください。

  2. リトライ回数を増やす: エージェント定義時に retries パラメータを設定することで、パースエラー発生時に自動でエラーメッセージをLLMへフィードバックし、再生成させることができます。

    agent = Agent(
        'openai:gpt-4o-mini',
        result_type=UserProfile,
        retries=3  # パースエラー時に最大3回自動リトライ
    )
    

エラー例2: RunContext の型不一致エラー

【現象】 ツール(@agent.tool)内で ctx.deps にアクセスした際、AttributeError が発生する、または静的解析ツール(Mypy / Pyright)に警告される。

【原因】 ツールの第一引数である ctx: RunContext[DepsType] の型注釈が、Agent(deps_type=DepsType) で指定した型と一致していない。

【解決方法】 ツールの型定義を厳密に揃えてください。

# 誤り
@agent.tool
def my_tool(ctx: RunContext, query: str): ...

# 正しい
@agent.tool
def my_tool(ctx: RunContext[MyDatabaseType], query: str): ...

6. まとめ:堅牢なAIエージェントの未来へ

Pydantic AIは、これまで「ブラックボックスで不安定」とされてきたLLMアプリケーションに、「静的型付け」という強力な盾をもたらします。

  • 期待する出力を Pydantic で宣言する
  • result_type で出力を完全に保証する
  • Deps を使ってモックや外部依存を安全に注入する

これらのアプローチにより、複数人のチーム開発や、ミッションクリティカルなシステムへのAIエージェント導入が劇的に容易になります。

LLMの能力が向上する現代だからこそ、アプリケーションの基盤には信頼性の高い「型」が必要です。ぜひ本記事を参考に、あなたのPythonプロジェクトにPydantic AIを取り入れ、堅牢なAIアプリケーションを構築してみてください!


参考文献