TECH BRIEF · Vol.1 No.03 2026.05.26
FRAMEWORK ANATOMY
技术深度 · Agent 框架 / Python · pydantic-ai

减法打赢
加法。

pydantic-ai 不提供 Memory 类、不做自动 context 截断、不自动重试 HTTP、不预设 Planner-Executor。这些克制不是缺陷,而是它能跑生产的原因 — 因为 agent 框架真正难的从来不是"做更多",而是"不做错"。

系列 / Agent 框架深拆 · Vol.1 No.03 受众 / 后端工程师 · Agent 系统设计者 · 面试者 关键词 / pydantic-ai · ReAct · pydantic_graph · LangChain · LangGraph
2026 年的 Agent 框架战国 — 谁靠"少做"赢了"多做"

LangChain 1300+ 个抽象、CrewAI 把"角色"做成一等公民、AutoGen 在 0.4 重写了三次。pydantic-ai 在 2024.11 进场,2025 跨过 1.0,2026 年成为唯一一个 agent loop 本身就用自己 graph 库实现的框架 — 4 节点状态机 · 0 个 Memory 类 · 1 个 list[ModelMessage] · retry 按 tool 名隔离。它没有发明新概念,它把"什么不该做"想清楚了。

框架不提供
0 个
Memory / Session / Thread 类
ReAct loop 节点数
4
状态机,非 while 循环
Demo→生产必改
5 处
默认能跑,不能扛
默认 retry 上限
retries=1
生产偏紧 · 建议改 3
Q1pydantic-ai 和 LangGraph 怎么选?它们在解决同一个问题吗?
Q2agent-as-tool vs pydantic_graph,什么时候用哪个?
Q3tool 调用失败时框架兜不兜底?业务异常会发生什么?
Q4长对话怎么避免 context window 爆炸?框架自动截断吗?
Q5它默认能跑生产吗?如果不能,我至少要改哪些配置?
Q6哪些 agent 方法适合生产、哪些只适合 demo?有没有清单?
ACT I · 2024 的 Agent 框架战国 When everyone built their own framework

01FastAPI feeling, for GenAI

2022 年底 LangChain 出生时,Agent 框架还是个稀缺品。三年后,这个赛道挤满了名字 — LangChain、LangGraph、CrewAI、AutoGen、Haystack、LlamaIndex、Semantic Kernel、Phidata。每家都在卖一套不同的"抽象哲学":有的把 Agent 等同于 Chain,有的把它建模成会议室里的角色扮演,有的干脆把它升格成状态机的特化。然后在 2024 年 11 月,Pydantic 团队从一个新的角度切入这个市场 — 不是发明新概念,而是把 FastAPI 的设计语言搬过来

Pydantic 不是一个新名字。它是 OpenAI SDK、Google ADK、Anthropic SDK、LangChain、LlamaIndex、AutoGPT、Transformers、CrewAI、Instructor 共同依赖的数据校验层。"全行业都在用我们的校验,为什么不直接做一个真正用得舒服的 agent 框架?" — pydantic-ai 的 README 第一句话就是这个反问。

但这份 brief 不打算重复 README。它要回答一个更尖锐的问题: 当所有 agent 框架都在'做更多'的时候,pydantic-ai 凭'做更少'怎么能赢?

2024.11 至今 · 七个坐标事件

2024.11
pydantic-ai 0.0.1 发布Slack 发布会一句话: "We built it because we couldn't find anything that gave us the same FastAPI feeling." 同期 LangChain 已经累计 1300+ 个 Python 类。
2025.03
pydantic_graph 拆出独立子包Agent loop 重写,内部用 type-hint-driven 的 graph 库实现 — agent 不再是特殊抽象,它就是 graph 的一个实例。LangGraph 的 agent 和 graph 还是两个分裂概念。
2025.06
1.0 release · API 冻结不像 LangChain v0.1→v0.3 那样反复 breaking change。冻结意味着可以放心写在生产系统里 — pydantic-ai 是少数明确给出 backwards-compat 承诺的 agent 框架。
2025.09
durable_exec 集成 Temporal / DBOS / Prefect / Restate不是自己实现工作流引擎,而是把 capability hook 暴露给四家成熟的 durable execution 提供商。这是"不重新发明轮子"的设计哲学最干净的体现。
2025.12
MCP / A2A / Vercel AI / AG-UI 全面接入四个外部标准都被建模成 capability 或独立子包,而不是塞进核心。pydantic-ai 自己只负责 agent loop,边界协议留给开放规范。
2026.02
Capability 系统稳定 · 第三方包生态开始出现把 tools + hooks + instructions + model settings 打包成可发布单元,YAML/JSON 也能定义 agent(agent_spec)。这是 LangChain 没解决的"如何复用 agent 装配"问题。
2026.05
GraphBuilder 新版 API · Fork/Join + Dominator Treepydantic_graph 加入命令式 builder,但并发用 anyio task group 不用 asyncio.gather,Join 节点用 dominator-tree 算法防 cycle 死锁 — LangGraph 通过强约束 DAG 回避的工程难题,这里正面解了。
第一眼印象

用一句话概括 pydantic-ai 的崛起: 当其他框架在卷"抽象数量"时,它选择卷"抽象密度"。整个核心库少于 30 个公开类,但每个类背后都有 3-5 个具体的工程问题被解到位 — 比如 RunContext.retries: dict[str, int] 这一个字段同时回答了"retry 怎么计数"、"按什么粒度隔离"、"output validator 该不该共享配额"三个问题。

ACT II · 强 primitives vs battery-included The minimal-vs-maximal divide

020 个 Memory 类,1 条消息列表

LangChain 在 2023 年最被夸的设计是它的 Memory 子类家族 — ConversationBufferMemoryConversationBufferWindowMemoryConversationSummaryMemoryVectorStoreRetrieverMemoryEntityMemory。每个类对应一种"对话记忆"策略,开箱即用。结果两年后呢?大部分生产团队都用自己的 Memory 包了一层,因为内置的 Memory 类要么太死板,要么对 tool call 的 message pairing 处理不对

pydantic-ai 的回答是: 我们不做 Memory。会话状态压成list[ModelMessage] — 一个 Python list,带强类型 schema。整个框架只有这一条"状态主线"。要做记忆,你自己拿这条 list 去做你想要的事。

两种哲学的对照

设计维度LangChain (Battery-Included)pydantic-ai (Strong Primitives)
会话状态容器~7 种 Memory 类 + Session1 个 list[ModelMessage]
消息序列化Memory 子类各自实现 save/loadTypeAdapter(list[ModelMessage]) · 一行
context window 截断5 种内置策略(window/token/summary...)0 内置 · 1 个 ProcessHistory 钩子
动态 system prompt每次重渲染 LCEL template持久化为 SystemPromptPart(dynamic_ref) · 历史自带反射
业务依赖注入塞进 Memory 或全局 chain configAgent[Deps, Output] · IDE 跳转 · 不可变
State schema 长期演化字段膨胀 · 团队规约难统一永远是消息列表 · schema 不外溢
tool 失败时OutputParserException / 通用 ExceptionUserError / AgentRunError / UnexpectedModelBehavior / ModelHTTPError 严格四类
并行 tool 失败asyncio.gather · fail-fast · 一个挂全挂asyncio.wait(FIRST_COMPLETED) · partial failure tolerant
retry 计数全局 · RunnableRetry 黑盒重跑按 tool 名隔离 · 错误结构化喂回 LLM
多 Agent 编排AgentExecutor / Chain 组合 / Plan-Execute 工具包3 种原语: tool delegation · programmatic handoff · pydantic_graph

这张表里每一行,LangChain 都给了"更多",pydantic-ai 都给了"更少"。看起来 pydantic-ai 在偷懒。但当你写过一个生产系统,你会发现每一项 pydantic-ai 的"少",都是它把某个 LangChain 的"多"想清楚之后,主动删掉的。比如 retry — LangChain 的 RunnableRetry 是黑盒重试(同一个 chain 重跑,LLM 看不到错误信息),根本构不成 self-correcting loop。pydantic-ai 把错误结构化喂回去,LLM 真能从错误里学会下一次该传什么参数。

pydantic-ai 自己的设计哲学(写在仓库 CLAUDE.md 里)

"我们偏好 strong primitives、powerful abstractions、general solutions and extension points,而不是狭窄的特定方案、未经时间检验的固执意见、或'什么都塞'的臃肿。" — pydantic-ai CLAUDE.md · 仓库根目录

"做更多容易。
想清楚不做什么 — 那才难。"

ACT III · 三大根问题 The three questions every agent framework must answer

03状态 · 工具 · 编排

把 AI Agent 工程师 JD 的三个问题翻译成系统设计语言,本质上是 agent 框架必须回答的三个根问题:

状态与上下文管理 = "对话的事实"放在哪里?谁拥有它?谁能改它?长了怎么办?
Tool Calling 稳定性 = LLM 是不可靠的执行者,工具调用是脆弱的桥梁,框架在中间承担多少容错责任?
多 Agent 流程 = 当问题超出单 LLM 一次推理的边界,框架提供什么编排原语?

下面三段,每段用一张表回答 pydantic-ai 对该问题的具体答案。

① 状态 — message_history 完全外置

子问题pydantic-ai 的答案代码位置
会话状态在哪?GraphAgentState.message_history · 一个 Python list_agent_graph.py:117
消息结构?ModelMessage = Annotated[ModelRequest|ModelResponse, Discriminator('kind')]messages.py:2359
序列化?ModelMessagesTypeAdapter = TypeAdapter(list[ModelMessage])messages.py:2363
怎么截断 context?框架不做 · ProcessHistory capability 是用户写的 hookcapabilities/process_history.py:28
多轮 trace 关联?conversation_id / run_id 戳在每条消息上 · 无需外置 session 表messages.py:1564-1572
业务依赖怎么注入?Agent[Deps, Output] · build_run_context 每节点重建 RunContext[Deps]_agent_graph.py:1387
动态 system prompt?SystemPromptPart(dynamic_ref=fn.__qualname__) · 持久化在历史里 · resume 时按 ref 重算_agent_graph.py:402
token / 调用次数?UsageLimits 三检查点 · check_before_request / check_tokens / check_before_tool_callusage.py:262, 378

关键观察: pydantic-ai 把"业务依赖(deps)"和"会话状态(state)"严格分离。LangGraph 把所有东西塞 TypedDict 让 reducer 合并,pydantic-ai 把业务数据放在 deps 里(不可变服务句柄),state 永远是消息列表 — schema 不会因为业务字段膨胀而失控。代价是没有 LangGraph 那种"任意 state 字段自动 checkpoint"的开箱即用;收益是 deps 永远类型安全,state schema 不会爆炸。

② Tool — 四层失败,各走各路

失败层触发条件处理路径是否回喂 LLM?
L1 协议LLM 给的 args JSON 过不了 schemaToolRetryError → RetryPromptPart(ValidationError.errors())✓ 完整错误列表
L1 协议LLM 幻觉的 tool 名raise ModelRetry(f'Unknown tool name: ... Available: ...')✓ 连可用工具都告诉它
L1 协议tool 主动 raise ModelRetry("...")包成 ToolRetryError(RetryPromptPart(content=message))✓ 开发者自定义
L2 业务tool 抛 ValueError 等业务异常框架不 catch · 穿透 except BaseException · cancel 兄弟任务 · 终结 run✗ 业务方必须自己 try/except
L3 传输@tool(timeout=N) 超时anyio.fail_after → ModelRetry('Timed out after N seconds.')✓ 自动转 retry
L4 模型provider 4xx/5xxModelHTTPError · 不进 retry · 立刻终结✗ 要重试自装 retries.py transport
L4 模型空响应 / content filterUnexpectedModelBehavior / ContentFilterError / 消耗 output_retries 重试部分
L2 业务异常的陷阱

这是 pydantic-ai 最容易让新人踩坑的设计 — tool 函数体里抛 ValueError 不会被框架 catch,会直接穿透到 _agent_graph.py:1906except BaseException,触发 cancel_and_drain(*tasks) 把同一轮所有兄弟 tool 任务取消,然后 re-raise 终结整个 run。生产环境里 每一个 tool body 必须自己 try/except,把业务异常转成 ModelRetry,否则一次 KeyError 能让 multi-tool 并行的整轮全挂 — 包括成功的那些。

self-correcting loop 的核心机制: RunContext.retries: dict[str, int] — 按 tool 名分别计数,不是全局。一个不稳定的 tool 不会偷走整个 run 的 retry 预算。Output validator 走完全独立的 output_retries_used 配额,与 tool retry 隔离。这种"细颗粒度配额隔离"是 LangChain 的 RunnableRetry 全局黑盒模式根本做不到的。

③ 编排 — 三种模式,官方排序就是优先级

模式什么时候用机制核心限制
① Agent-as-toolLLM 自主决定调谁(动态分派)@agent.tool 里 await other_agent.run(usage=ctx.usage, deps=ctx.deps)嵌套层数过深会 token 爆炸
② Programmatic handoffapplication 层确定的多步流程普通 Python 函数调用 + structured output 类型对齐无专门 API · 全靠类型系统
③ pydantic_graph需要循环 · 分支 · checkpoint · resumeBaseNode + return type annotation 即边 + StatePersistence学习曲线陡 · 不适合简单场景

关键洞察 — agent-as-tool 的 usage 累加机制: parent agent 把 ctx.usage 这个 RunUsage 对象引用传给 child agent,child 的 ModelRequestNode._append_response 直接 incr 同一个对象。所以 parent 的 UsageLimits 自动覆盖整个 sub-tree — 不需要手动累加。LangChain 的多 agent 串联里,token 计数是个噩梦,因为没有这个引用共享设计。

官方决策树

docs/graph.md 原话: "Don't use a nail gun unless you need a nail gun." 翻译成中文: "graph 是钉枪 — 没必要时别用。" pydantic_graph 是为了"必经的多步 + 循环判断 + 持久化恢复"准备的,不是为了让你把简单的 ReAct loop 也画成图。简单场景用 agent.tool,中等用 programmatic handoff,复杂才上 graph。

ACT IV · 源码里的设计语言 What the source code says when no one's watching

04八个不在文档里说,但写在源码里的决定

读 pydantic-ai 官方文档,你看到的是"How to use"。读源码,你看到的是"Why we built it this way"。下面八个设计决策没有写在显眼的地方,但每一个都解决了 LangChain/LangGraph 用其他方式回避或妥协的工程难题。这是面试时拿出来讲最有杀伤力的内容。

1 · message_history 三方共享同一份引用

GraphAgentState.message_history 这条 list 同时被 capture_run_messages(用户 API)、RunContext(tool/system_prompt 内部)、graph 各节点(UserPromptNode/ModelRequestNode/CallToolsNode)共享同一份引用。任何节点 mutate(append、history processor replace)立刻对所有视图生效,整个框架不需要 message bus。一行 Python 引用语义解决了 LangGraph 用 reducer 解的问题。

2 · ProcessHistory 是个 hook,不是 strategy

capabilities/process_history.py:28 全部代码不超过 80 行,核心就是 before_model_request 钩子的薄包装。processor 签名 (list[ModelMessage]) → list[ModelMessage]。要做 token-aware 截断、PII 脱敏、用小模型 summarize 旧消息 — 全是用户自己写 processor。框架给的承诺只有两条: 调用时机(在每次 model request 前)、约束(tool-call/return 不能拆散)。这种"给协议、不给实现"的设计,等于把 Memory 子类的复杂度全部移到了边界外。

3 · 动态 system prompt 持久化在历史里

@agent.system_prompt(dynamic=True) 不是每次重拼 prompt,而是生成 SystemPromptPart(dynamic_ref=fn.__qualname__) 持久化在 message_history 里。UserPromptNode._reevaluate_dynamic_prompts(_agent_graph.py:402)在每次 resume 时按 ref 找到原 runner 重算后替换。动态性被 encode 进消息本身,让历史自带反射能力。LangChain 的 LCEL template 是每次重渲染,resume 时如果换了机器、原来的 closure 没了 — 就废了。

4 · ToolRetryError 把 ValidationError 原文回喂

tool_manager.py:184-191_wrap_error_as_retry 直接调用 err.errors(include_url=False, include_context=False) 把 Pydantic 完整错误列表(含字段路径、input value、error type)打包进 RetryPromptPart.content,作为下一轮 ModelRequest 喂回 LLM。LLM 看到的不是 "tool failed",而是"参数 customer_id 类型应为 int 但收到 string '12a3'"。这是 self-correcting loop 真正的样子 — LangChain 的 RunnableRetry 黑盒重试根本做不到。

5 · retry budget 按 tool 名隔离

RunContext.retries: dict[str, int](tool_manager.py:177-181)— 一个不稳定的 tool 不会偷走整个 run 的 retry 预算。output_retries_used(_agent_graph.py:158-175)又是完全独立的配额,与 tool retry 隔离。这种细颗粒度配额隔离是默认就有的,不需要任何配置。LangChain 的全局 retry 计数下,一个坏 tool 能把整个 run 给"饿死"。

6 · 并发用 asyncio.wait 不用 TaskGroup,故意的

_agent_graph.py:1872-1901: 同一轮多个 tool call 用 asyncio.create_task + asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)故意不用 asyncio.TaskGroup — 因为 TaskGroup 的"一个失败全部取消"与"工具失败也算 retry 信号、要喂回 LLM"语义直接冲突。每个 _call_tool 内部 catch ToolRetryErrorRetryPromptPart 作为正常返回,单个工具失败不取消并行兄弟任务。LangChain 的 parallel_tool_callsasyncio.gather 是 fail-fast,生产 partial-failure 容忍度差很多。

7 · Agent loop 本身就是 pydantic_graph 实例

_agent_graph.py:2066-2095build_agent_graph() 返回 Graph[GraphAgentState, ...]ReAct loop 不是 while 循环,是 4 节点状态机 — UserPromptNode → ModelRequestNode → CallToolsNode → (ModelRequestNode | End)。用户在 graph 节点里调 Agent.run 等于在 graph 里嵌套 graph。LangGraph 的 agent 抽象和 graph 抽象是两个分裂的东西 — pydantic-ai 是真正的"自吃狗粮"。

8 · 拓扑由 return type annotation 定义

BaseNode.get_node_def(basenode.py:104-136)用 get_type_hints(cls.run)run 方法的 return annotation,拆 union 作为出边。async def run(self, ctx) → AnotherNode | End[int] 这一行就定义了拓扑的两条出边。没有 add_edge 调用。LangGraph 是动态的,pydantic_graph 是声明式的 — 代价是更难写运行时动态图,收益是 graph 在 build 时就 fully validate,IDE 跳转能力强,wrong return type 在 Pyright 阶段就报错。

"FastAPI revolutionized web development by offering an innovative and ergonomic design, built on the foundation of Pydantic Validation and modern Python features like type hints. We built Pydantic AI with one simple aim: to bring that FastAPI feeling to GenAI app and agent development." — pydantic-ai README · 设计宣言
ACT V · Demo vs 生产分界线 The 5 defaults you must change before shipping

05哪些默认能跑生产,哪些只是 demo 配

这是 JD 加分项里"对哪些方法适合生产、哪些只适合 demo 有清晰判断"的直接答案。不是泛泛而谈,是 pydantic-ai 在源码里、文档里、issue 里反复出现的具体边界。

生产默认就行
8 项
默认 ≥ 生产线

不改任何配置就能上线的能力

  • schema 校验 + 错误结构化回喂(self-correcting loop)
  • tool 粒度 timeout(@tool(timeout=N))
  • 并行 partial failure tolerant
  • 按 tool 名隔离的 retry budget
  • 类型安全 deps 注入
  • UsageLimits 三检查点
  • conversation_id 自带 trace
  • StatePersistence 抽象(graph)
默认能跑,生产必改
5 项
demo → prod gap

默认值偏 demo,生产前必须显式改

  • retries=1 偏紧 → Agent(retries={'tools': 3})
  • HTTP 无自动 retry → 装 retries.py transport
  • SimpleStatePersistence 只留最后 1 → FullStatePersistence
  • tool body 默认无 try/except → 业务异常必须自己 catch
  • 长对话无截断 → 挂 ProcessHistory + processor
框架不管,业务自己做
4 项
scope: out

无论怎么配,框架都不解决的问题

  • 语义 Memory(向量检索 / 实体记忆)
  • 跨进程 rate limiting
  • OTel trace 上报(Logfire 是 opt-in)
  • Provider failover(FallbackModel 太基础)

三个篮子的具体演算

① 适合直接用 pydantic-ai 起项目

单 Agent · 中小规模 tool 集 · 团队有 Python/Pydantic 背景 · 需要 production 但不需要 Temporal 级别的 durable execution

→ 开箱可用率 ~85%,改 5 处默认上生产
→ Agent[Deps, SupportOutput] 这种类型签名直接给团队带来 IDE 体验
最快 1 天上线,长期维护成本最低

② 适合用 pydantic-ai 但要叠加自建

多 Agent · 复杂工作流 · 需要 RAG/Memory · 需要 human-in-the-loop · 需要分布式

→ pydantic-ai 作为单 agent 的"内核",外层用 pydantic_graph 编排或接入 Temporal
→ Memory 用自建 vector store + ProcessHistory hook 注入
→ Deferred tools 做 human-in-the-loop 审批
中等学习曲线,长期可扩展性最强

③ 不适合用 pydantic-ai 的场景

团队不熟 Python/类型系统 · 严重依赖现有 LangChain 生态(eg. 一堆 LangChain 自定义 Tool)· 需要可视化拖拽 agent builder

→ 学习曲线在"理解 pydantic + RunContext + capabilities"这层有非零成本
→ 迁移现有 LangChain 工具需要重写 schema 包装
这些场景里 LangGraph / LangChain 反而更顺手
demo → prod 的五处必改 · 复制清单

Agent(retries={'tools': 3}) · 默认 1 偏紧
pip install 'pydantic-ai-slim[retries]' + 挂 AsyncTenacityTransport(wait=wait_retry_after(max_wait=300), stop=stop_after_attempt(5))
③ graph 持久化用 FullStatePersistence 或自实现 DB-backed StatePersistence
④ 每个 tool body 加 try: ... except BusinessError as e: raise ModelRetry(str(e))
⑤ 长对话挂 capabilities=[ProcessHistory(token_aware_truncate)] · 自己写 processor

底色判断 — 强 primitives 打赢 battery

这份 brief 的核心结论很简单: pydantic-ai 不是"功能更少的 LangChain",它是"想得更清楚的 LangChain"。每一个看似 missing 的功能(Memory / 自动截断 / 自动 HTTP retry / Planner-Executor),都不是 pydantic-ai 团队没想到,而是他们想清楚之后决定不做的。

原因有两个: 第一,这些功能大多数情况下需要业务方根据自己的语义来定 — 框架默认实现要么太死板(命中场景窄),要么默认错(比如 ConversationBufferWindowMemory 默认不知道你的 tool-call/return 必须配对)。第二,这些"battery"会让 API 表面积膨胀,长期来看团队规约和 backwards-compat 都难维护 — 这就是为什么 LangChain 在 v0.1→v0.3 之间反复 breaking change,而 pydantic-ai 在 1.0 之后冻结 API 还能保持简单。

"做更多容易。想清楚不做什么 — 那才是 production-grade 的开始。"

Q1 答案: 不在同一层。pydantic-ai 是 agent 框架 + 一个 type-hint-driven 的 graph 子库(pydantic_graph);LangGraph 是 graph 框架 + 一个 agent 抽象。pydantic-ai 的 agent loop 本身就用自己的 graph 库实现。简单 ReAct 场景选 pydantic-ai,需要可视化复杂工作流选 LangGraph。

Q2 答案: LLM 自主决定调谁(动态分派)→ agent-as-tool(共享 RunUsage)。application 层确定的多步流程 → programmatic handoff。需要循环/分支/checkpoint/resume → pydantic_graph。官方文档原话: graph 是钉枪,没必要时别用。

Q3 答案: 四层失败各走各路。L1(参数错/工具名错/主动 ModelRetry)框架结构化喂回 LLM 形成 self-correcting loop。L2 业务异常(ValueError 等)框架不 catch,直接终结 run + cancel 兄弟任务。L3 timeout 自动转 ModelRetry。L4 provider HTTP 错误不重试,要自装 retries.py。生产里 tool body 必须自己 try/except。

Q4 答案: 框架不做自动截断。挂 capabilities=[ProcessHistory(my_processor)],processor 签名是 list[ModelMessage] → list[ModelMessage]。要 token-aware 截断、PII 脱敏、用小模型 summarize 旧消息都在 processor 里写。约束是必须保证 tool-call/return 配对。

Q5 答案: 默认能跑,默认不能扛生产。至少改 5 处: retries 调到 3,装 retries.py 的 httpx transport,graph 持久化换 FullStatePersistence,每个 tool body 加 try/except 转 ModelRetry,长对话挂 ProcessHistory + 自写 processor。

Q6 答案: 适合生产 — schema 校验回喂、tool timeout、partial failure tolerant、retry budget 按 tool 名隔离、UsageLimits、conversation_id 自带 trace。只适合 demo — 默认 retries=1、HTTP 无自动 retry、SimpleStatePersistence、tool 默认无 try/except、无自动 context 截断。框架不管 — 语义 Memory、跨进程 rate limit、OTel 上报、provider failover。

06三类工程师的对照建议

① 准备面试的工程师 · 应对"AI Agent 工程师"JD

这份 brief 的金句、表格、file:line 引用,都是为面试准备的"弹药"。重点记三组对比 — pydantic-ai vs LangChain(state schema 不外溢)、asyncio.wait vs gather(partial failure)、agent loop 是 graph 实例(vs LangGraph 两个分裂抽象)。

关键纪律: 不要背"功能列表",要讲"为什么不做"的设计决策。面试官能立刻分辨"你读过文档"还是"你读过源码"。

② 后端工程师 · Python/FastAPI 背景 · 第一次做 Agent

pydantic-ai 是为你设计的。Pydantic 校验你熟,dataclass 你熟,async/await 你熟,deps 注入概念就是 FastAPI 的 Depends 翻版。从 Hello World 到生产可能就 2 天 — Day 1 跑通 Agent + tool + UsageLimits + structured output;Day 2 改 5 处默认配置上生产。

关键纪律: 不要从 LangChain 教程出发学习,从 docs/agent.md → docs/tools.md → docs/multi-agent-applications.md 顺序读,跳过所有"对比 LangChain"的章节,直接学 pydantic-ai 的原语。

③ 从 LangChain 迁移的团队 · 已有生产 Agent 系统

心智迁移要点: ① Memory 子类→自写 ProcessHistory processor(自由度更高但要自己写);② RunnableRetry→ToolRetryError + 按 tool 名 retries;③ Chain 组合→agent-as-tool 或 programmatic handoff;④ State dict→Agent[Deps, Output] 的 deps + structured output;⑤ AgentExecutor.invoke→Agent.run / Agent.iter。最难的迁移是 Memory 那层 — 你的 ConversationSummaryMemory 没有对应实现,要自己用小模型 + ProcessHistory hook 拼。

关键纪律: 不要一次性整体迁移。先把一个独立的 sub-flow 用 pydantic-ai 重写,跑一个月对比可观测性数据(Logfire/OTel),再决定要不要扩。pydantic-ai 1.0 之后冻结 API 这一点对迁移团队是巨大利好 — 不会一年改三次。

0710 个监测信号 · pydantic-ai 是否能成为 agent 框架默认

#信号触发判断 / 动作
1pydantic-ai 1.x → 2.x 是否 breaking如果保持 1.x 长期稳定 → 生产采用率会显著上升
2durable_exec 的 Temporal/DBOS 用户案例第一个公开的"用 pydantic-ai+Temporal 跑了一年"案例出现 → 企业级背书
3MCP server 模式的成熟度越来越多 SaaS 直接发布 MCP server → pydantic-ai 自动获益(不需要写新 integration)
4Capability 第三方包数量>20 个高质量第三方 capability 包 → "extensibility by design"哲学被验证
5pydantic-evals 的 LLM-as-judge 采用评估子库被独立项目引用 → "测试与代码同等重要"的 pydantic 哲学延伸到 agent
6retries.py 是否默认接入如果某天 v1.x 把 AsyncTenacityTransport 默认开启 → demo/prod 差距进一步缩小
7GraphBuilder API 是否稳定新版 Fork/Join/Decision API 是否在 2026 H2 冻结 → graph 用户增长率拐点
8agent_spec (YAML/JSON 定义 agent)无代码定义 agent 普及度 → 低代码 agent 用户进入
9LangChain 是否吸收 pydantic-ai 设计LangChain v0.4 是否引入"自吃狗粮"的 agent-as-graph → 行业共识在形成
10OpenAI Assistants API 等官方 SDK 是否影响 pydantic-ai 地位OpenAI 自带 agent SDK 成熟 → 跨 provider 框架需求是否被压缩

"你不需要更多的 Memory 类。
你需要的是,框架别替你决定。"

主要数据来源 / Data Sources

· pydantic-ai 源码(2026-05 clone)· /Users/epingpong/CodeBuddy/agent-dev/pydantic-ai/

· pydantic-ai 官方文档 · ai.pydantic.dev

· README + CLAUDE.md(仓库根目录)设计哲学陈述 · github.com/pydantic/pydantic-ai

· docs/multi-agent-applications.md · 三种模式官方分类 · ai.pydantic.dev

· docs/graph.md · pydantic_graph 哲学("nail gun"那段)· ai.pydantic.dev

· docs/retries.md + docs/message-history.md · 生产级别细节 · ai.pydantic.dev/retries

· LangChain v0.3 文档(对比基准)· python.langchain.com

· LangGraph 文档(对比基准)· langchain-ai.github.io/langgraph

· 关联调研: langgraph-investigation-v1.md / max-ai-design-v1.md / pydantic-ai-investigation-v1.md(本地 agent-dev 目录)

Tech Brief · Vol.1 No.03 · 2026.05.26
Frameworks that say no, ship better than frameworks that say yes.