一、先别急着写代码:Agent 这件事,到底谁在做?
2024 年底到 2025 年,LLM Agent 框架爆炸式增长。一个 Python 工程师打开 GitHub,能在一下午刷到 10 个"生产级 Agent 框架"。但真正活跃、背后有稳定团队、能长期维护的,其实就那么几家——而且它们的设计哲学截然不同。
在你决定学 Pydantic AI 之前,先把牌桌看清楚:
| 框架 | 出品方 | 核心哲学 | 上手难度 | 适合场景 |
|---|---|---|---|---|
| LangChain | LangChain Inc. | 万物皆 Chain,胶水式组合 | 中等,但调试痛苦 | 快速原型、复杂 pipeline |
| LangGraph | LangChain Inc. | 状态机驱动的 Agent | 偏高,要学图论 | 多步工作流、人在环路 |
| OpenAI Agents SDK | OpenAI | Assistants API 的生产包装 | 低 | 强绑 OpenAI/Azure 的团队 |
| CrewAI / AutoGen | 社区 | 角色扮演式多 Agent | 低 | 多 Agent 协作演示 |
| Pydantic AI | Pydantic 团队 | 类型即契约,Python 原生 | 极低(会 FastAPI 就会) | 工程化、可测试的生产 Agent |
Pydantic AI 不是最早的,也不是最火的。它在 2024 年底正式发布 v0.0.x,2025 年才走向稳定。但它解决了一个被其他框架长期忽略的问题:
二、Pydantic 团队是谁?凭什么入场?
如果你写过一天 Python 后端,大概率用过这几个库的其中一个——而它们共同的作者是 Samuel Colvin:
logfire.instrument_pydantic_ai(),Agent 的所有调用、token、成本、trace 全都自动上报。也就是说,Pydantic 团队手里握着三张牌:最流行的校验库、Python 最火的后端框架同款设计范式、自家的观测平台。做 Agent 框架,他们是最有资格的"地主"。
三、"类型即契约":这四个字到底什么意思?
这是 Pydantic AI 整本书的核心。我拆开讲:
契约 1:Agent 的输出是类型
传统做法你大概率见过:
# 传统 LLM 调用:字符串进,字符串出
import openai
import json
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "北京现在天气?用 JSON 回,字段 city, temp, condition"}],
)
text = response.choices[0].message.content
data = json.loads(text) # ← 可能爆炸:LLM 漏了个 { 或多了个逗号
city = data["city"] # ← 可能爆炸:LLM 把字段叫成了 "city_name"
temp = data["temp"] # ← 可能是 "22°C" 字符串,不是 int
每一步都是潜在炸点,线上每天都有人被这些坑炸到。Pydantic AI 的做法:
from pydantic import BaseModel
from pydantic_ai import Agent
class Weather(BaseModel):
city: str
temp: int # 必须是 int,LLM 给字符串自动转/重试
condition: str
agent = Agent("openai:gpt-4o", output_type=Weather)
result = agent.run_sync("北京现在天气?")
print(result.output.city) # IDE 会自动补全 .city
print(result.output.temp + 5) # int 直接运算,没有 "22°C" 之类的字符串陷阱
result.output 的类型就是 Weather。你的 mypy/pyright 能检查它,IDE 能补全它,pytest 能断言它。LLM 输出不符合?Pydantic AI 会把错误发回去让模型自动重试——不是你再写 try/except。
契约 2:工具的参数是类型
这里和 FastAPI 几乎一模一样:
@agent.tool_plain
def get_order(order_id: int, include_items: bool = False) -> dict:
"""根据订单 ID 查询订单详情。"""
return db.query_order(order_id, include_items)
Pydantic AI 自动把这个函数转成给 LLM 看的 JSON schema——参数名、类型、默认值、docstring 全都抽出来塞给 function calling。你不写一行 schema,LLM 就知道怎么调。
契约 3:依赖是类型
FastAPI 的 Depends() 用过吧?Pydantic AI 的 deps_type 是一样的思想:
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
@dataclass
class Deps:
db: Database
user_id: int
agent = Agent("openai:gpt-4o", deps_type=Deps)
@agent.tool
def my_orders(ctx: RunContext[Deps]) -> list[dict]:
return ctx.deps.db.list_orders_for(ctx.deps.user_id)
# 调用时注入
result = agent.run_sync("我的订单都有哪些?", deps=Deps(db=real_db, user_id=42))
测试时用 agent.override(deps=Deps(db=mock_db, user_id=1)) 替换——和 FastAPI 的 app.dependency_overrides 一个味道。
四、定位坐标:Pydantic AI 和隔壁四家有什么不一样?
vs LangChain:"拼乐高"与"写代码"
LangChain
- 万物皆
Runnable,|管道风 - 模板抽象多(PromptTemplate / OutputParser / Chain / Retriever / ...)
- IDE 补全几乎失效,堆栈深到崩溃
- 好处:胶水多,拼起来快
- 坏处:出错时你不知道哪一层炸了
Pydantic AI
- 只有
Agent+Tool+Model三个核心概念 - 就是普通 Python 函数 + 装饰器
- IDE 完整补全,栈短到一眼看穿
- 好处:代码就是代码,调试就是调试
- 坏处:生态比 LangChain 小(但你基本也用不到那么多组件)
vs OpenAI Agents SDK:"一家亲"与"provider 中立"
OpenAI 2025 年初推出的 Agents SDK,设计很好——但只支持 OpenAI/Azure OpenAI。如果你哪天要换成 Claude、Gemini、Groq,或者想用 Ollama 本地跑,你得整个重写。
Pydantic AI 从第一天就是 provider-agnostic:
# 切模型就改一个字符串
agent = Agent("openai:gpt-4o")
agent = Agent("anthropic:claude-sonnet-4-5")
agent = Agent("google-gla:gemini-2.5-pro")
agent = Agent("groq:llama-3.3-70b")
agent = Agent("ollama:qwen2.5")
agent = Agent("bedrock:anthropic.claude-sonnet-4-v1:0")
# 剩下所有代码一个字不用改
这点对生产系统巨重要——LLM provider 的定价和能力每季度都在变,锁死一家等于锁死成本。
vs LangGraph:"状态机优先"与"Agent 优先"
LangGraph 是状态机驱动。你先画图(Node + Edge),再把 Agent 当成图里的一个节点。对于多步、有分支、人在环路的复杂工作流,LangGraph 是合理的选择。
但 80% 的场景其实是:一个 Agent + 几个工具 + 一个 structured output。在这种场景用 LangGraph 就是杀鸡用牛刀。Pydantic AI 的哲学是:
pydantic_graph 子包(第 7 章会讲),但它是可选的——需要状态机时才用。默认路径是一段平铺直叙的 Python,不逼你先画图再写代码。
vs CrewAI / AutoGen:"角色扮演"与"工程代码"
CrewAI 之类的框架强调"多 Agent 协作"——你定义 CEO Agent、产品经理 Agent、工程师 Agent,让它们互相对话。演示视频效果很炫,真做业务会发现:
- 每个 Agent 的输出还是字符串,结构化很脆
- 调用链路不透明,出问题不知道哪个 Agent 错了
- token 成本爆炸(一次任务十几个 Agent 对话)
Pydantic AI 也支持多 Agent(第 8 章),但把它视作"一个 Agent 可以把另一个 Agent 当作工具来调"——本质是一个普通函数调用,可以 mock、可以测、可以限成本。
五、Hello World:十行代码看懂它在做什么
装
pip install pydantic-ai
# 或者按 provider 精简安装
pip install "pydantic-ai-slim[openai]"
pip install "pydantic-ai-slim[anthropic]"
设置 API Key(用哪家设哪家):
export OPENAI_API_KEY=sk-...
# 或
export ANTHROPIC_API_KEY=sk-ant-...
写
from pydantic_ai import Agent
agent = Agent(
"openai:gpt-4o-mini",
system_prompt="你是一个凝练的技术答疑助手,回答不超过 3 句话。",
)
result = agent.run_sync("解释一下 Python 的 GIL。")
print(result.output)
运行:
GIL(全局解释器锁)是 CPython 解释器在同一时刻只允许一个线程执行 Python 字节码的机制。
它简化了 CPython 的内存管理,但也导致 CPU 密集任务无法用多线程真正并行。
可以改用多进程或把热点交给 C 扩展(如 NumPy)绕开 GIL。
把"字符串返回"升级成"结构化返回"
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class Concept(BaseModel):
name: str
one_liner: str = Field(description="不超过 30 字的定义")
pitfalls: list[str] = Field(description="最常见的 2-3 个坑")
agent = Agent("openai:gpt-4o-mini", output_type=Concept)
result = agent.run_sync("解释 Python GIL")
print(result.output.name) # "GIL" (str)
print(result.output.one_liner) # "CPython 的线程互斥锁..."
for p in result.output.pitfalls: # list[str]
print("- ", p)
这一下你就体感到了:
- IDE 补全:敲
result.output.立刻提示三个字段 - mypy 检查:把
.one_liner写成.one_linerr静态就爆错 - 字段描述进 prompt:
Field(description=...)会被自动塞给 LLM 作为字段语义提示 - 失败自动重试:LLM 输出不满足 schema,Pydantic AI 把 Pydantic 的校验错误原文发回去让它改
六、运行时看见的东西:Agent 到底发了什么
很多新手觉得 Agent 框架"魔法太多"。Pydantic AI 特别坦诚——你可以把任意一次调用的完整消息流打印出来:
result = agent.run_sync("解释 Python GIL")
print(result.all_messages())
[
ModelRequest(parts=[
SystemPromptPart(content='你是一个凝练的技术答疑助手...'),
UserPromptPart(content='解释 Python GIL'),
]),
ModelResponse(parts=[
ToolCallPart(tool_name='final_result', args={'name': 'GIL', ...}),
]),
ModelRequest(parts=[
ToolReturnPart(tool_name='final_result', content='Final result processed.'),
]),
]
所有看似"魔法"的东西——结构化输出、工具调用、重试——底层都是普通的 ModelRequest / ModelResponse 消息。你能看到每一个字节是怎么发给 LLM 的。出问题时这点就是救命稻草。
七、这门教程的 10 章要带你走完什么
- 本章:搞清楚 Pydantic AI 是谁、和谁不一样、第一段代码跑起来
- 第 2 章:Agent 构造参数全解 / system prompt 动静态 / provider 切换 / run · arun · stream 三条 API
- 第 3 章:output_type 全貌——BaseModel / Union / TypedDict / dataclass / 验证失败重试机制
- 第 4 章:Tool 装饰器、从签名推 schema、RunContext、多工具并行、ModelRetry
- 第 5 章:Dependency Injection 全套——deps_type / RunContext / override / FastAPI 对比
- 第 6 章:流式(文本流 · 结构化流) + 消息历史管理 + 多轮对话模式
- 第 7 章:pydantic_graph 状态机——BaseNode / End / 持久化 checkpoint / 实战客服分流
- 第 8 章:多 Agent 协作——Agent 当工具、programmatic handoff、delegate、成本控制
- 第 9 章:测试与 Eval——TestModel / FunctionModel / capture_run_messages / pytest 集成
- 第 10 章:Logfire 观测、FastAPI 集成、Docker 部署、生产 checklist
八、本章小结
① Pydantic AI 是 Pydantic 团队做的 provider 中立 的 Agent 框架。
② 它的核心设计哲学是类型即契约——Agent 的输入输出、工具参数、依赖,全部 Pydantic 化。
③ 它不替代 LangGraph(复杂状态机)或 LangChain(超大拼乐高生态),但在 需要可测试、可类型检查、provider 可切换 的生产 Agent 上,它是目前最工程化的选择。
延伸阅读
- 官方文档:ai.pydantic.dev(英文,内容非常丰富,下一章起我会配合官方 API 讲解)
- Samuel Colvin 的 AI Agents 演讲(YouTube):搜 "Samuel Colvin Pydantic AI"
- 对比阅读:LangChain 的
Runnable抽象 vs Pydantic AI 的Agent抽象