关于 pydantic-ai-common-pitfalls
面向使用 PydanticAI 的开发者,整理工具定义、依赖传递、输出校验、模型配置与流式调用中的常见错误及排查步骤。还提供消息捕获和追踪示例,帮助依据运行证据定位问题。
主要功能
- 01工具装饰器使用规范
- 02依赖与类型检查建议
- 03结构化输出故障排查
- 04模型配置与流式调用提示
- 05消息捕获和追踪示例
适用场景
- 01排查 RunContext 参数错误
- 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"}
调试提示
关卡(失败原因不明确)
当 Agent 行为异常,但堆栈跟踪或错误字符串不明确时,请按顺序执行以下步骤;不要跳过。
- 收集证据 — 使用
capture_run_messages()重新运行,或在run/run_sync后检查result.all_messages()(或按顺序打印消息类型)。**通过标准:**你能说出消息部分类型,并指出一行解释失败原因的内容(例如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 | 验证失败 | 检查 output_type,增加重试次数 |