第二十一章:PydanticAI 的类型安全范式与三者适用边界
21.1 第三种路线:把「协作」问题换成「正确性」问题
第二十章的 AutoGen 和 CrewAI 都在回答「多个 Agent 怎么协作」。PydanticAI 关注的是另一类问题:单个 Agent 的输入输出,能不能像普通函数调用一样接受类型系统和运行时校验。它建立在 Pydantic——Python 生态里最常用的数据校验库——之上,把同一套「用类型注解声明数据形状、运行时自动校验」的做法带到了 Agent 开发里。
PydanticAI 官方将其定位为「Python 的 AI SDK:一个类型化、可扩展的 Agent 循环」,文档反复强调「typed end to end」(端到端类型化),这也是它和本主题其他框架最明显的差异。
21.2 核心设计:Agent、output_type 与依赖注入
PydanticAI 的 Agent 对象接受一个 output_type(通常是 Pydantic BaseModel),运行结果会被自动校验并转换成对应类型,而不是返回一段需要自己解析的原始字符串:
from typing import Literal
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
class Sentiment(BaseModel):
label: Literal["positive", "negative", "neutral"]
score: float = Field(ge=-1, le=1)
agent = Agent("openai:gpt-5.6-sol", output_type=Sentiment)
@agent.tool
def recent_reviews(ctx: RunContext[None], product: str) -> list[str]:
"""获取某个产品的近期评论片段。"""
return review_service.fetch(product)
result = agent.run_sync("最近大家对这款产品的评价怎么样?")
print(result.output.label, result.output.score)
这里有两个工程上直接相关的点:
@agent.tool装饰的函数签名和 docstring 直接生成工具 Schema——这和 Tools 主题 中 Function Calling 的 Schema 设计原则完全一致,PydanticAI 没有发明新协议,只是让 Schema 生成过程和 Python 类型注解无缝衔接;RunContext是依赖注入的入口——工具函数通过ctx.deps访问运行时注入的依赖(数据库连接、当前用户身份等),这些依赖在测试时可以被替换成 mock 对象,不需要真的连接外部系统就能验证 Agent 的调用逻辑。
21.3 类型安全带来的工程收益
flowchart LR
A["模型输出的原始文本"] --> B{"output_type 校验"}
B -->|"通过"| C["强类型对象
可直接用于业务逻辑"]
B -->|"不通过"| D["自动重试
把校验错误反馈给模型"]
当模型的输出不满足 output_type 声明的约束(比如 score 超出了 [-1, 1] 范围),PydanticAI 会把校验错误反馈给模型并触发重试,这个反馈闭环本身发生在框架内部,不需要开发者手写「解析失败就重新提示模型」的样板代码。这与 LangChain 生态 · 第四章 中结构化输出的处理方式目标一致,区别在于 PydanticAI 把这层校验做得更贴近 Python 静态类型工具链(配合 mypy/pyright 可以在编写阶段就发现类型不匹配问题)。
21.4 决策矩阵:AutoGen、CrewAI、PydanticAI 与本主题其他框架的适用边界
把本模块两章和前几个模块放在一起,可以按六个工程维度画出一张对照表(更完整的跨全部框架对照见 框架选型与可移植架构 · 第二十二章):
| 维度 | AutoGen | CrewAI | PydanticAI | Semantic Kernel | LangGraph |
|---|---|---|---|---|---|
| 核心问题 | 分布式多智能体协作 | 角色化团队协作 + 确定性 Flow | 单 Agent 的类型安全与工具契约 | 企业级流程与多智能体编排 | 通用状态图编排 |
| 状态模型 | Actor 间异步消息 | Crew 内隐式、Flow 内显式状态 | 单次 Run 的依赖注入上下文 | Process 的显式状态转移 | 显式共享 State |
| 持久化 | 需要外部方案 | Flow 状态可持久化,Crew 内部有限 | 需要外部方案(框架本身偏无状态单次调用) | Process 原生支持持久化与恢复 | Checkpointer 原生支持 |
| 工具契约 | 消息驱动的函数调用 | 标准 Function Calling | 类型注解直接生成 Schema,校验最严格 | Plugin 统一 Semantic/Native Function | 标准 Function Calling |
| 评测/可观测性 | 依赖外部 Tracing 集成 | 内置 Trace,但生态工具相对年轻 | 与 Pydantic Logfire 等工具集成较紧密 | 与 Application Insights 等企业遥测集成 | LangSmith 原生集成最成熟 |
| Lock-in 风险 | 中等:Actor 消息格式有一定绑定 | 中等:YAML 配置和角色隐喻绑定较深 | 较低:核心是标准 Python 类型和函数 | 较高:企业治理能力换来生态绑定 | 中等:State/Checkpointer 格式有一定绑定 |
这张表反映的是取舍,而不是单一排名。需要长期持久化和恢复能力时,LangGraph 或 Semantic Kernel Process Framework 更合适;需要严格类型安全和更低框架绑定时,PydanticAI 更合适;需要快速验证角色化协作时,CrewAI 更合适;需要真正的分布式部署时,AutoGen 更合适。选型时更有效的做法,是先明确项目最看重的两三个维度,再对照矩阵筛选。
21.5 常见错误
21.5.1 认为类型校验能替代模型能力评测
output_type 校验能保证「格式正确」,不能保证「内容正确」——一个格式完全合法但语义错误的 Sentiment 对象照样能通过校验,仍然需要独立的评测流程判断内容质量。
21.5.2 把依赖注入当作可选的代码风格
不使用 RunContext 注入依赖,直接在工具函数里硬编码数据库连接或全局变量,会让单元测试必须依赖真实外部系统,失去类型安全设计本来要解决的可测试性收益。
21.5.3 只看决策矩阵的单一维度就下结论
比如只看到「Lock-in 风险较低」就认定 PydanticAI 全面适合所有场景,忽视了它在长期持久化和多智能体协作上需要额外自建方案的事实。
21.5.4 把角色化框架的「团队隐喻」当作技术架构本身
CrewAI 的 role/goal/backstory 是 Prompt 工程的组织方式,不代表底层有类似人类团队的组织架构或权限体系,不能替代真实的权限与审批设计。
21.6 本章总结
- PydanticAI 把「Agent 开发」重新定义为「类型安全的函数调用」:
output_type保证输出可被自动校验并重试,RunContext提供可测试的依赖注入入口; - 它的工具 Schema 生成方式与 Function Calling 协议完全兼容,没有发明新协议,只是让类型注解和 Schema 生成无缝衔接;
- 类型校验解决的是「格式正确性」,不是「内容正确性」,仍然需要独立的评测体系判断语义质量;
- AutoGen、CrewAI、PydanticAI 在状态模型、持久化、工具契约、可观测性和 lock-in 风险上呈现出明显不同的取舍,没有一个框架在全部维度上都最优;
- 框架选型应该先明确项目最看重的两三个维度,再对照决策矩阵找最匹配的框架,而不是寻找一个「全能」选项。
如果说 AutoGen 和 CrewAI 主要回答「多个 Agent 怎么协作」,那么 PydanticAI 处理的是另一层问题:单个 Agent 的输入输出能否获得和普通 Python 函数类似的类型安全保障。三者对应的是不同优化方向,而不是同一赛道上的直接替代关系。