不要把 Pydantic AI 当成 Agent 魔法层:先写清工具权限和输出合同
不要把 Pydantic AI 当成 Agent 魔法层:先写清工具权限和输出合同
Pydantic AI 最容易被误读成“又一个 Python Agent 框架”。这个理解不算错,但太粗了。它真正适合的场景不是把一个 prompt 包成 Agent(...),而是把模型、工具、依赖注入、结构化输出、trace、eval 和人工审批边界放进同一个工程化合同里。
Doramagic 的 pydantic-ai 项目说明书把它归到 Agent SDK 与运行时:适合正在构建可观测、可测试、多工具 Agent 应用的开发者;不适合只需要一个 prompt、简单 API 调用,或不能隔离工具权限的环境。这个判断很关键。Pydantic AI 能帮你把 Agent 写得更像工程代码,但它不会替你决定哪些工具可以执行、哪些数据可以出站、哪些 trace 可以被记录。
我的建议是:第一次接入 Pydantic AI,不要从“让它完成一个复杂任务”开始,而是从“让一个最小 Agent 在假工具、假凭据、假数据里跑通,并证明它没有越界”开始。
先确定你要解决的不是聊天,而是可验证的工作流
如果只是把用户问题发给模型,再拿到一段自然语言,Pydantic AI 可能有点重。它的价值主要出现在这些场景:
- 需要把模型输出校验成一个 Pydantic
BaseModel; - 需要把数据库连接、用户身份或配置作为
deps注入工具; - 需要多个工具,并且每个工具的参数 schema 必须可检查;
- 需要 trace 记录工具选择、重试、失败和分支;
- 需要在真实副作用前加入人工审批或策略闸门;
- 需要把 eval 变成回归测试,而不是上线后看平均分。
换句话说,Pydantic AI 的入口不是“更会聊天”,而是“让 Agent 的输入、输出、工具和路径可以被审查”。
第一条边界:结构化输出不是格式美化
很多人看到 output_type=SupportOutput 会以为它只是让模型输出 JSON。这个理解会低估它的价值。
结构化输出真正解决的是:模型返回的结果必须落在一个明确的业务对象里。比如客服场景里,输出可以不是一段建议,而是:
class SupportOutput(BaseModel):
support_advice: str
block_card: bool
risk: int = Field(ge=0, le=10)
这意味着调用方可以把 block_card 当成一个可审查字段,而不是从一段话里猜“它是不是建议冻结银行卡”。如果校验失败,框架可以把错误回传给模型重试。这里的重点不是 JSON 漂亮,而是把错误尽量提前暴露。
但这也有边界:结构化输出不能替代业务审核。risk=8 仍然需要你定义为什么是 8、谁能触发后续动作、是否需要人工确认。Pydantic AI 可以帮你建合同,不能替你写政策。
第二条边界:工具调用必须从最小权限开始
Pydantic AI 的工具通常通过函数签名和 @agent.tool 注册。函数参数会被转换成 schema,运行时通过 Pydantic 校验。这很适合把工具调用变成可检查接口。
但工具一旦能读文件、查数据库、发请求或执行操作,风险就变了。第一次接入时,我会这样做:
- 先写一个只返回固定值的假工具;
- 给工具传入临时
deps,不要用真实用户数据; - 验证模型是否会调用正确工具;
- 验证工具参数是否符合预期;
- 再逐步替换成真实工具。
不要一上来就给 Agent 数据库写权限、生产 API key 或浏览器自动操作权限。Doramagic 的边界卡也明确提示:首次使用应从 least privilege、临时目录、可回滚环境开始。
第三条边界:RunContext 是状态通道,不是杂物箱
Pydantic AI 的 RunContext[DepsType] 很有用,因为它让工具和动态指令能拿到运行时依赖。但这里也容易失控:什么都塞进 deps,最后 Agent 运行时可以看见太多状态。
我会把 deps 分成三类:
- 必需状态:当前用户、当前任务、允许访问的数据范围;
- 只读配置:模型、阈值、环境开关;
- 禁止状态:长期密钥、全量用户表、生产写权限、和当前任务无关的内部资料。
如果某个工具只需要用户 ID,就不要把整个用户对象塞进去。如果某个工具只需要读取,不要把写入客户端也传进去。Agent 框架越强,越需要把可见状态缩小。
第四条边界:trace 要记录决策,不要记录过量敏感数据
Pydantic AI 与 Logfire / OTel 的可观测性结合,是它适合生产工程的原因之一。对 Agent 来说,trace 比最终答案更有价值,因为 trace 能告诉你:
- 模型为什么选择这个工具;
- 哪一步失败或重试;
- 哪些上下文被用来生成答案;
- 结构化输出是否经历过校验失败;
- 是否出现了本不该发生的副作用。
但 trace 也不是越多越好。Doramagic 说明书里提到社区 issue 曾讨论 OTel span 属性可能序列化较大的 ModelRequestParameters。这类问题提醒我们:记录 trace 前要先想清楚哪些字段能进日志、哪些字段需要裁剪、哪些字段必须脱敏。
一个实际规则是:trace 应该帮助复盘决策路径,而不是把用户输入、内部文档、密钥痕迹和大块上下文无脑记录下来。
第五条边界:MCP、toolsets 和 capabilities 需要启用清单
Pydantic AI 的 toolsets、MCP、Thinking、WebSearch、deferred loading 等能力看起来很诱人,因为它们能把很多外部能力打包进 Agent。但对真实团队来说,问题不是“能接多少工具”,而是“每次运行到底暴露了哪些工具”。
我会在启用前写一张小清单:
- 这个 Agent 允许看到哪些 toolsets;
- 哪些工具默认禁用,只有特定任务才启用;
- 哪些工具需要人工审批;
- 工具失败后是重试、降级还是停止;
- 工具输出是否能进入最终答案;
- 工具调用是否会留下审计记录。
如果一个 Agent 每次都能看到所有工具,它迟早会在某个上下文里调用不该调用的东西。
给 AI 宿主的一段接入规则
如果让 Claude Code、Codex、Cursor 或其他 AI coding host 帮你接入 Pydantic AI,我会先给它这段规则:
你可以帮我使用 Pydantic AI 设计 Agent,但必须先说明:
1. 目标是聊天、RAG、工具型 Agent,还是多 Agent 工作流;
2. 输出是否需要 Pydantic BaseModel 校验;
3. deps 里允许出现哪些状态,禁止出现哪些状态;
4. 每个工具的权限、输入 schema、失败处理和审批规则;
5. trace 记录哪些字段,哪些字段必须脱敏或不记录;
6. eval 或 smoke check 如何证明没有越界。
不要声称 Pydantic AI 已经在本机安装或运行,除非有独立运行日志。
不要给 Agent 真实密钥、生产写权限或主目录级文件访问,除非用户明确批准。
不要把 Prompt Preview 当作真实项目运行结果。
这比“帮我写一个 Pydantic AI Agent”更可靠。它把任务从写 demo 改成了建立可复核边界。
我会怎么开始
第一天只做一个最小闭环:
- 建一个临时目录;
- 安装官方 quick start 所需依赖;
- 写一个
Agent,输出一个简单BaseModel; - 加一个只返回固定值的假工具;
- 用
RunContext注入临时 deps; - 记录一次 trace 或至少记录工具调用路径;
- 写一个 smoke check,要求 Agent 说明它调用了什么、为什么调用、输出是否通过校验。
这个闭环不酷,但它能回答最重要的问题:这个框架是否能让你的 Agent 行为变得更可检查。
Pydantic AI 的强项不是让 Agent 更像魔法,而是让 Agent 更像工程对象:有类型、有工具边界、有运行上下文、有 trace、有 eval,也有明确的停止条件。真正值得带给 AI 宿主的,正是这些边界,而不是“又多了一个 Agent 框架”。
资料角色
- 上游项目:pydantic/pydantic-ai,负责真实代码、安装命令、版本行为和 API 事实,https://github.com/pydantic/pydantic-ai
- Doramagic 项目页:把 pydantic-ai 整理成可带走、可装载、可验证的能力资产,https://doramagic.ai/zh/projects/pydantic-ai/
- Doramagic 说明书:适合在接入前阅读 Agent、providers、structured outputs、toolsets、MCP、trace、eval 和 pitfall,https://doramagic.ai/zh/projects/pydantic-ai/manual/

浙公网安备 33010602011771号