pydantic-ai-common-pitfalls について
PydanticAI を使う開発者向けのデバッグ資料です。ツール定義、依存関係の受け渡し、出力検証、モデル設定、ストリーミングの誤りと、実行メッセージやトレースによる調査方法を扱います。
主な機能
- 01ツールデコレーターの使い方
- 02依存関係と型チェックの確認
- 03構造化出力のトラブルシューティング
- 04モデル設定とストリーミングの注意点
- 05メッセージ取得とトレースの例
活用シーン
- 01RunContext 引数の誤りを診断
- 02依存関係の渡し忘れを発見
- 03出力検証エラーを調査
- 04ストリーム結果の完全性を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill pydantic-ai-common-pitfallsインストール後、Claude Code で/pydantic-ai-common-pitfallsを入力して読み込まれたか確認します。
詳細
PydanticAI でよくある落とし穴とデバッグ
ツールデコレーターのエラー
誤り:tool_plain での RunContext
# ERROR: RunContext not allowed in tool_plain
@agent.tool_plain
async def bad_tool(ctx: RunContext[MyDeps]) -> str:
return "oops"
# UserError: RunContext annotations can only be used with tools that take context
修正方法:コンテキストが必要な場合は、@agent.tool を使用します。
@agent.tool
async def good_tool(ctx: RunContext[MyDeps]) -> str:
return "works"
誤り:tool での RunContext の指定漏れ
# ERROR: First param must be RunContext
@agent.tool
def bad_tool(user_id: int) -> str:
return "oops"
# UserError: First parameter of tools that take context must be annotated with RunContext[...]
修正方法:最初のパラメーターとして RunContext を追加します。
@agent.tool
def good_tool(ctx: RunContext[MyDeps], user_id: int) -> str:
return "works"
誤り:RunContext が最初のパラメーターではない
# ERROR: RunContext must be first parameter
@agent.tool
def bad_tool(user_id: int, ctx: RunContext[MyDeps]) -> str:
return "oops"
修正方法:RunContext は必ず最初のパラメーターにします。
有効なパターン(エラーではありません)
生の関数をツールとして登録する
次のパターンは pydantic-ai で有効であり、サポートされています。
from pydantic_ai import Agent, RunContext
async def search_db(ctx: RunContext[MyDeps], query: str) -> list[dict]:
"""Search the database."""
return await ctx.deps.db.search(query)
async def get_user(ctx: RunContext[MyDeps], user_id: int) -> dict:
"""Get user by ID."""
return await ctx.deps.db.get_user(user_id)
# Valid: Pass raw functions to Agent(tools=[...])
agent = Agent(
'openai:gpt-4o',
deps_type=MyDeps,
tools=[search_db, get_user] # RunContext detected from signature
)
このパターンが機能する理由: PydanticAI は関数シグネチャを調べます。最初のパラメーターが RunContext[T] の場合、コンテキスト対応のツールとして扱われます。デコレーターは不要です。
参考資料: https://ai.pydantic.dev/agents/#registering-tools-via-the-tools-argument
RunContext シグネチャを持つ関数を Agent(tools=[...]) に渡すコードを、エラーとして指摘しないでください。これは @agent.tool を使用するのと同等であり、公式ドキュメントにも明記されています。
依存関係の型の不一致
誤り:実行時に deps がない
agent = Agent('openai:gpt-4o', deps_type=MyDeps)
# ERROR: deps required but not provided
result = agent.run_sync('Hello') # Missing deps!
修正方法:deps_type が設定されている場合は、必ず deps を渡します。
result = agent.run_sync('Hello', deps=MyDeps(...))
誤り:deps の型が違う
@dataclass
class AppDeps:
db: Database
@dataclass
class WrongDeps:
api: ApiClient
agent = Agent('openai:gpt-4o', deps_type=AppDeps)
# Type error: WrongDeps != AppDeps
result = agent.run_sync('Hello', deps=WrongDeps(...))
出力型の問題
Pydantic の検証に失敗する
class Response(BaseModel):
count: int
items: list[str]
agent = Agent('openai:gpt-4o', output_type=Response)
result = agent.run_sync('List items')
# May fail if LLM returns wrong structure
修正方法:リトライ回数を増やすか、プロンプトを改善します。
agent = Agent(
'openai:gpt-4o',
output_type=Response,
retries=3, # More attempts
instructions='Return JSON with count (int) and items (list of strings).'
)
複雑なネスト型
# May cause schema issues with some models
class Complex(BaseModel):
nested: dict[str, list[tuple[int, str]]]
修正方法:単純化するか、中間モデルを使用します。
class Item(BaseModel):
id: int
name: str
class Simple(BaseModel):
items: list[Item]
非同期と同期の使い分けの誤り
誤り:同期コンテキストで非同期処理を呼び出す
# ERROR: Can't await in sync function
def handler():
result = await agent.run('Hello') # SyntaxError!
修正方法:run_sync を使用するか、ハンドラーを非同期にします。
def handler():
result = agent.run_sync('Hello')
# Or
async def handler():
result = await agent.run('Hello')
誤り:非同期ツール内でブロッキング処理を行う
@agent.tool
async def slow_tool(ctx: RunContext[Deps]) -> str:
time.sleep(5) # WRONG: Blocks event loop!
return "done"
修正方法:非同期 I/O を使用します。
@agent.tool
async def slow_tool(ctx: RunContext[Deps]) -> str:
await asyncio.sleep(5) # Correct
return "done"
モデル設定のエラー
API キーがない
# ERROR: OPENAI_API_KEY not set
agent = Agent('openai:gpt-4o')
result = agent.run_sync('Hello')
# ModelAPIError: Authentication failed
修正方法:環境変数を設定するか、defer_model_check を使用します。
# For testing
agent = Agent('openai:gpt-4o', defer_model_check=True)
with agent.override(model=TestModel()):
result = agent.run_sync('Hello')
無効なモデル文字列
# ERROR: Unknown provider
agent = Agent('unknown:model')
# ValueError: Unknown model provider
修正方法:有効な provider:model 形式を使用します。
ストリーミングの問題
誤り:ストリームが完了する前に結果を使用する
async with agent.run_stream('Hello') as response:
# DON'T access .output before streaming completes
print(response.output) # May be incomplete!
# Correct: access after context manager
print(response.output) # Complete result
誤り:ストリームを反復処理しない
async with agent.run_stream('Hello') as response:
pass # Never consumed!
# Stream was never read - output may be incomplete
修正方法:必ずストリームを最後まで読み取ります。
async with agent.run_stream('Hello') as response:
async for chunk in response.stream_output():
print(chunk, end='')
ツールの戻り値に関する問題
誤り:シリアライズできない値を返す
@agent.tool_plain
def bad_return() -> object:
return CustomObject() # Can't serialize!
修正方法:シリアライズ可能な型(str、dict、Pydantic モデル)を返します。
@agent.tool_plain
def good_return() -> dict:
return {"key": "value"}
デバッグのヒント
ゲート(原因が曖昧な失敗)
エージェントが想定どおりに動作しないものの、スタックトレースやエラー文字列から原因がわからない場合は、次の手順を順番に実施し、先に進んで手順を飛ばさないでください。
- 証拠を取得する —
capture_run_messages()を使って再実行するか、run/run_syncの実行後にresult.all_messages()を調べます(またはメッセージ型を順番に出力します)。合格条件: 失敗を説明するメッセージパートの型と内容を1行で示せること(例:RetryPromptPart、ツールの戻り値、モデルのテキスト)。 - モデルとスキーマを切り分ける — 検証エラーまたは
RetryPromptPartが現れた場合、最後のモデルメッセージとoutput_typeのフィールドおよび型を比較します。合格条件:retriesだけを増やしたりモデルを変更したりする前に、具体的な不一致(フィールドの欠落、型違い、拒否)を特定すること。 - すべての経路で deps を確認する — ツールまたは deps で問題が発生する場合は、各呼び出し箇所(
run、run_sync、run_stream)で deps_type が設定されているときにdeps=...が渡されていることを確認します。合格条件: deps を明示した最小限の再現コードで、deps の受け渡しの不具合を確認するか、原因から除外できること。
トレースを有効にする
import logfire
logfire.configure()
logfire.instrument_pydantic_ai()
# Or per-agent
agent = Agent('openai:gpt-4o', instrument=True)
メッセージを取得する
from pydantic_ai import capture_run_messages
with capture_run_messages() as messages:
result = agent.run_sync('Hello')
for msg in messages:
print(type(msg).__name__, msg)
モデルの応答を確認する
result = agent.run_sync('Hello')
print(result.all_messages()) # Full message history
print(result.response) # Last model response
print(result.usage()) # Token usage
よくあるエラーメッセージ
| エラー | 原因 | 修正方法 |
|---|---|---|
First parameter... RunContext | @agent.tool で ctx が指定されていない | ctx: RunContext[...] を追加する |
RunContext... only... context | @agent.tool_plain に ctx がある | ctx を削除するか、@agent.tool を使用する |
Unknown model provider | 無効なモデル文字列 | 有効な provider:model を使用する |
ModelAPIError | API 認証/クォータ | API キーと上限を確認する |
RetryPromptPart in messages | 検証に失敗した | output_type を確認し、リトライ回数を増やす |