跳到主要内容

Pydantic AI — 架构与原理

30 秒导读: Pydantic AI 是 Pydantic 团队做的 Python agent 框架。它把「让 LLM 反复调工具直到给出答案」这件事,建模成一张只有三个节点的状态图;并复用 Pydantic 的杀手锏——把你的类型注解自动变成「工具的 JSON schema」和「输出校验器」,让 agent 开发有 FastAPI 那种「类型对了基本就跑通」的手感。

本项目较大(核心包 2 万余行 + 30 个 provider + 持久化执行 + UI 流协议),所以拆成多文件。本页是 Layer 0/1:先讲「这是什么」,再给「顶层全景」,最后是阅读地图。深入机制见各章节。


1. 这是什么(零基础也能懂)

一句话定义: Pydantic AI 是一个 Python 库,让你用普通 Python 函数和类型注解,就能搭出「会调用工具、会返回结构化数据、可流式输出」的 LLM agent。

解决什么问题 / 给谁用。 假设你要做一个客服 agent:它得能查数据库、能调外部 API、最后还要返回一个结构清晰的对象(而不是一坨自由文本)。手写这套循环很烦——要拼 prompt、解析模型吐的工具调用、校验参数、把结果塞回去、再问一遍模型……Pydantic AI 把这套循环和「类型↔schema」的翻译都包好了,给的是后端工程师 / agent 开发者。

它能做什么(功能):

  • 把带类型注解的 Python 函数注册成「工具」,schema 自动生成。
  • 让模型返回结构化输出(一个 Pydantic 模型 / dataclass),并自动校验。
  • 一个统一接口跑 30+ 家模型 provider(OpenAI / Anthropic / Google / …)。
  • 流式输出、人类审批(HITL)、可中断/可恢复的运行、持久化执行(Temporal 等)。
  • OpenTelemetry 可观测、依赖注入(deps)。

用起来什么样。 最小例子(来自 README.md 的 Hello World):

from pydantic_ai import Agent

agent = Agent(
'anthropic:claude-sonnet-4-6',
instructions='Be concise, reply with one sentence.',
)

result = agent.run_sync('Where does "hello world" come from?')
print(result.output)
#> The first known use of "hello, world" was in a 1974 textbook ...

加一个工具也只是「装饰一个函数」:

# 示意,非源码:演示工具注册的手感
from pydantic_ai import Agent, RunContext

agent = Agent('openai:gpt-5.2', deps_type=str)

@agent.tool # 把普通函数变成 agent 可调用的工具
async def get_balance(ctx: RunContext[str], # 第一个参数是 RunContext → 自动识别为「带上下文」工具
account: str) -> float: # account/返回类型 → 自动变成工具 schema
"""查某个账户余额。""" # docstring → 工具描述
return await db.lookup(ctx.deps, account)

你没写任何 JSON schema——account: str 这个注解被 Pydantic 翻成了工具入参的 schema(机制见 02 章)。

一句话直觉 / 类比。 把它想成 「带类型系统的 while 循环」:循环体是「问模型 → 它要么给最终答案、要么要求调工具 → 调完把结果喂回去再问」,而 Pydantic 在每个进出口做「Python 类型 ↔ JSON」的双向翻译和校验。

2. 顶层全景(它大概怎么转)

核心洞察:一次 agent 运行 = 跑一张状态图。这张图只有三个「干活的节点」,加一个收尾节点。定义在 _agent_graph.py:1598build_agent_graph

怎么读下图: 从左到右是一次运行的主干;CallToolsNode 是分岔点——有最终答案就走 End,只有工具调用就回到 ModelRequestNode 再来一轮。

部件一句话职责:

部件干什么在哪个文件
Agent用户门面:注册工具/输出类型/系统提示,提供 run/run_sync/run_stream/iteragent/__init__.py:187
build_agent_graph把三节点组装成一张 pydantic_graph.Graph_agent_graph.py:1598
UserPromptNode拼系统提示、实例化用户输入为一个 ModelRequest_agent_graph.py:264
ModelRequestNode真正调模型(含流式 + capability 中间件包裹)_agent_graph.py:597
CallToolsNode解析模型响应:是最终输出还是工具调用?分发执行_agent_graph.py:1077
ToolManager / AbstractToolset列工具、校验参数、调工具tool_manager.py / toolsets/abstract.py:74
Model各 provider 的统一抽象(request / request_streammodels/__init__.py:192
AbstractCapability中间件钩子链(包裹 run/请求/工具/输出)capabilities/abstract.py

主线走一遍(高层,不进代码):

  1. 你调 agent.run_sync('...')Agent 解析出本次用的模型、工具集、输出 schema,构图,从 UserPromptNode 喂入。
  2. UserPromptNode 把系统提示 + 你的输入拼成第一个 ModelRequest,转交 ModelRequestNode
  3. ModelRequestNode 调模型,拿回一个 ModelResponse,转交 CallToolsNode
  4. CallToolsNode 看响应:
    • 最终输出(纯文本满足、或 output 工具命中)→ 走 End,运行结束。
    • 工具调用 → 执行这些工具,把返回拼成新的 ModelRequest,回到第 3 步。
  5. 直到出现最终输出或触发限制(重试预算、token 限制)。

这就是全部主干。复杂度都藏在「每个节点内部怎么处理边界情况」里——这正是各章节要展开的。

3. 阅读地图(建议顺序)

先读 01(主干怎么转),再按兴趣挑:

  1. 01-agent-graph.md — 三节点状态图的端到端走读。理解这一章 = 理解了 Pydantic AI 的骨架。
  2. 02-tools-and-toolsets.md — 「类型注解 → 工具 schema」的魔法、toolset 如何分层组合、call_tool 怎么路由。
  3. 03-output-and-end-strategy.md — 结构化输出的四种模式,以及一轮里多个工具调用时 end_strategy 如何裁决「谁是最终答案」。
  4. 04-capabilities-and-models.md — capability 中间件钩子链(这是它做可观测/审批/持久化的统一机制),以及 Model 抽象与多 provider。

4. 边界与局限(先知道它不做什么)

  • 不是低代码平台:没有可视化拖拽,核心是代码 + 类型。
  • 图不是任意 DAG:agent 主图固定是这三节点;要写复杂多步流程,用底层的 pydantic_graph 自己定义节点。
  • 持久化执行靠适配:Temporal / DBOS / Prefect 在 durable_exec/ 下作为适配层存在,本组文档只在边界层描述,不深入其内部。
  • provider 行为差异由 profile 吸收:不同模型对 schema / 工具 / 思考模式的怪癖,靠 profiles/ 里的 ModelProfile 抹平,但仍可能有未覆盖的边角。

5. 代码地图(导航索引)

主题文件关键符号
用户门面 / 入口pydantic_ai_slim/pydantic_ai/agent/__init__.pyAgent, Agent.iter, Agent.run
状态图组装pydantic_ai_slim/pydantic_ai/_agent_graph.pybuild_agent_graph
三节点pydantic_ai_slim/pydantic_ai/_agent_graph.pyUserPromptNode, ModelRequestNode, CallToolsNode
运行驱动pydantic_ai_slim/pydantic_ai/run.pyAgentRun, AgentRun.next, AgentRun.__anext__
图引擎pydantic_graph/pydantic_graph/basenode.pyBaseNode, End, GraphRunContext
工具/工具集pydantic_ai_slim/pydantic_ai/toolsets/abstract.pyAbstractToolset, ToolsetTool
模型抽象pydantic_ai_slim/pydantic_ai/models/__init__.pyModel, StreamedResponse, ModelRequestParameters
中间件钩子pydantic_ai_slim/pydantic_ai/capabilities/abstract.pyAbstractCapability