PydanticAI 生产实践:类型驱动的 Agent 设计模式
聚焦结构化输出、工具调用和错误恢复,介绍 PydanticAI 在生产环境中的实用设计模式。
很多 Agent 项目后期都会遇到同一个问题:模型回答“看起来对”,但系统无法稳定消费。
PydanticAI 的优势是把输出约束前置到类型系统,让 Agent 不只是会说,还能稳定“交付可执行结果”。
核心思路:先定义结果,再让模型生成
与其先写 Prompt 再猜结果,不如先定义:
- 任务输入结构
- 任务输出结构
- 错误分支结构
这样可以把大量运行时问题提前暴露到开发阶段。
模式一:结构化输出优先
典型做法:
- 输出对象拆成小字段
- 枚举字段用有限值
- 不允许自由文本承载关键决策
当你接入下游服务(工单系统、CRM、告警平台)时,这个策略能显著降低解析失败率。
模式二:工具调用结果也要类型化
很多人只约束模型输出,却放任工具返回 dict[str, Any]。这会把混乱转移到链路后半段。
建议:
- 每个工具定义输入输出模型
- 异常结果返回可判定状态,而不是抛裸异常
- 对外部 API 增加超时和重试策略
模式三:错误恢复分层
推荐把恢复机制分成三层:
- 模型内重试(小改提示)
- 工具级降级(切换备选工具)
- 任务级回退(人工接管)
这比“统一重试三次”更稳,也更易分析失败原因。
模式四:把评估嵌入开发流程
每次改提示或工具前,至少跑一组固定样例:
- 正常输入
- 边界输入
- 对抗输入
对比输出对象差异,记录回归风险。长期看,这比仅靠人工 spot check 更可靠。
总结
PydanticAI 的真正价值,不在于“又一个 Agent 框架”,而在于它强迫我们用工程化方式组织 Agent 逻辑。类型是约束,也是协作语言。
如果你的 Agent 需要与多个业务系统集成,类型驱动设计通常会在 1-2 个迭代内体现收益。
工具调用:把"看起来对"变成"校验得过"
PydanticAI 真正的杀手锏不是模型包装,而是它把工具调用也变成 schema 校验的一环。常见错误模式是模型返回 "call tool X with args Y",但 args 实际是自由文本。强制做法:
- 在 tool 注册时声明 input schema(Pydantic 模型)
- 校验失败时不抛裸异常,而是返回结构化 ErrorResult
- 工具结果也用 Output 模型封装,下游不需要 try/except 解析未知 dict
这种"两端都约束"的设计,让模型幻觉的影响面降到最小。某金融客户上线后,从原本每周 3 次数据脏导致工单,变成每季度 1 次。
多 Agent 协作:把"角色"做成 typed protocol
在多 Agent 系统里,最大的可维护性问题是"角色边界模糊"——A 说它查了订单,B 也查了一遍,谁的结果为准?PydanticAI 提供依赖注入 + Result 模型,可以约束:
- 每个角色只能看到允许的上下文切片
- 角色输出必须符合本角色专属 schema
- 跨角色通信走 typed 消息总线,不传字符串
实践中,这种 typed protocol 让一个 6 个角色的客服 Agent 系统从"靠日志调试"变成"看类型签名就能定位问题"。
部署前必须做的三件事
- schema 版本化:所有 Output 模型加 semver。Agent 升级和消费者升级解耦。
- 校验失败可观测:每条失败记 span + 上下文,不要只打 log。Langfuse 这类平台能直接看 schema drift 趋势。
- 回滚到上一个 schema:模型升级或 prompt 改动时,保留旧 schema 的 fallback 路径至少 2 周。
常见反模式
- "模型是黑盒,框架帮我们兜底"——实际上 PydanticAI 的兜底是明确的,框架不能替你做 schema 决策。
- "全部用 Any 类型,灵活"——短期看快,三个月后改一个字段就崩。
- "Eval 跑一次够了"——schema 演进必然带来行为漂移,必须每次改动后跑回归样例。