PydanticAI
Pydantic 团队维护的 Python AI agent 框架,以端到端类型安全、现代惯用 Python 为核心;本篇记录其目录结构、核心抽象(Agent/Dependencies/Tool/Model)与对照 BodySense AI 层的阅读重点。
[!info] related notes
PydanticAI
这是什么
Pydantic 团队维护的 Python AI agent 框架。它的核心主张不是”功能最多”,而是:
- 现代、惯用、简洁的 Python;
- 端到端类型安全,
Agent[Dependencies, Output]把依赖、工具、模型请求、结构化输出串成一条类型链; - 尽量避免
Any和不必要的cast; - 谨慎设计公共 API 与抽象;
- 完整测试,倾向真实集成、cassette 录制(VCR)与 snapshot。
这些不是我的主观判断,而是仓库 AGENTS.md 白纸黑字规定的协作质量标准。它和 BodySense 的 AI 层高度相关,但它是”框架”不是”完整 Web 产品”——不含数据库、任务队列、API 路由、React 集成。
[!tip] 理解它的关键 不要先啃整个框架。它的价值集中在”Python 应该怎样写 AI 代码”这件事上:依赖注入怎么类型安全、Tool 的 schema 怎么从签名生成、结构化输出怎么在运行时校验。
在你三层参考架构里的位置
用户定位:学习「Python 本身怎样写得现代、类型安全、优雅」的首选。直接对照 BodySense 当前 AI 服务里”松散字典、隐式约定、跨模块重复类型”的痛点。
版本快照
| 项 | 值 |
|---|---|
| 分支 | main |
| commit | d995cfee9fa4(2026-08-10) |
| 抓取日期 | 2026-08-11 |
| 语言 | Python >=3.10 |
| 包管理 | uv(仓库根 uv.lock) |
| 测试 | pytest + 真实集成 + cassette 录制(VCR)+ snapshot(tests/cassettes/) |
仓库鸟瞰:顶层目录结构
pydantic-ai/
├── pydantic_ai_slim/ # 框架主体(实际包 pydantic_ai 在此)
│ └── pydantic_ai/ # 核心源码
├── pydantic_evals/ # 评估子包
├── pydantic_graph/ # graph workflow 子包
├── examples/ # 可运行示例(bank_support / rag / weather_agent …)
├── tests/ # 测试 + cassettes 录制
├── docs/ # mkdocs 文档站(api/ capabilities/ evals/ models/ …)
├── agent_docs/ # agent 设计规范(api-design / code-simplification / documentation)
├── .agents/ .claude/ .gemini/ # 多 AI 客户端协作规则
├── pyproject.toml Makefile mkdocs.yml
pydantic_ai_slim/pydantic_ai/(核心,depth 1):
pydantic_ai/
├── __init__.py # 公共 API 出口
├── _agent_graph.py # Agent 执行图(run 的内部状态机)
├── agent/ # Agent 抽象:abstract / spec / wrapper
├── capabilities/ # 能力插件:tool-search / deferred / thinking / web_fetch …
├── common_tools/ # 内置工具:duckduckgo / exa / tavily / web_fetch
├── models/ # 模型 provider 抽象(openai / anthropic / google …)
├── _function_schema.py # 从函数签名生成 JSON schema
├── _output.py # 结构化输出与运行时校验
├── _tool_execution.py # 工具调用执行
├── _run_context.py # 运行期上下文(含 Dependencies)
├── direct.py # 直达式 agent
└── durable_exec/ # 持久化执行(airflow / temporal / prefect / dbos / restate 适配)
顶层边界职责
| 顶层目录 | 回答什么问题 | 备注 |
|---|---|---|
pydantic_ai_slim/pydantic_ai/ | Agent / Tool / Model / Output 怎么实现 | 框架真正的核心 |
pydantic_evals/ | 评估怎么写、怎么跑 | 与框架解耦的独立子包 |
pydantic_graph/ | graph workflow 怎么定义与执行 | 另一独立子包 |
examples/ | 真实可跑的最小用法 | 读文档前的入口 |
tests/ | 行为如何被锁定 | cassette 录制是关键,避免 mock 失真 |
docs/ + agent_docs/ | 设计意图与使用约定 | agent_docs/ 是给 contributor 看的规范 |
分层与依赖方向
flowchart LR
DEP[Dependencies 类型参数] --> AGENT[Agent 运行]
AGENT --> TOOL[Tool 注册 / 参数 schema]
TOOL --> MODEL[Model provider 抽象]
MODEL --> OUT[结构化 Output + 运行时校验]
OUT --> CALLER[调用方:强类型返回值]
AGENT -.-> CAP[capabilities 插件]
AGENT -.-> EVAL[pydantic_evals]
核心就这一个类型参数贯穿全链路:
dependency → tool → model request → structured output → caller
关键入口与调用链
| 入口 | 路径 | 说明 |
|---|---|---|
| 公共 API | pydantic_ai_slim/pydantic_ai/__init__.py | Agent、Tool、run 等导出 |
| Agent 抽象 | agent/abstract.py + agent/spec.py | Agent[Deps, Output] 的定义与契约 |
| 执行图 | _agent_graph.py | 一次 run 的内部状态机 |
| Tool 定义 | tools.py + _function_schema.py | 从 Python 签名生成 JSON schema |
| 模型抽象 | models/ | provider 统一接口 |
| 消息流 | messages.py | 请求/响应消息模型 |
| 评估 | pydantic_evals/ | Eval / Case / Dataset |
主线:一次 Agent.run 的类型链
选最小例子(README 的 dependency injection)作为主线:
Agent[Deps, Output]
├─ deps: 类型安全的依赖注入(DB / config 等,不走全局单例)
├─ tool: 用 @agent.tool 注册,参数 schema 从签名自动生成
├─ model: 通过 models/ 抽象发请求,消息流见 messages.py
├─ output: 结构化返回,_output.py 在运行时校验
└─ caller: 拿到强类型 Output,无 Any
重点观察 Agent[Dependencies, Output] 这个类型参数怎样从 dependency 一路贯穿到 caller——这正是 BodySense 当前 AI 层(松散 dict)最该借鉴的地方。
阅读路线(用户建议顺序)
不要先啃整个框架,按此路径读:
- README 里的 dependency injection 示例(建立”类型安全注入”直觉)
pydantic_ai_slim/pydantic_ai/tools.py(Tool 注册与参数 schema)pydantic_ai_slim/pydantic_ai/models/(多模型 provider 抽象)pydantic_ai_slim/pydantic_ai/messages.py(消息模型)pydantic_ai_slim/pydantic_ai/_agent_graph.py(一次 run 的执行图)pydantic_evals/(评估怎么写)- 对应测试(
tests/test_tools.py等,配 cassette 看真实 IO)
深挖一条线:跟着 Agent[Dependencies, Output] 走一遍 run
主线讲了类型参数如何贯穿,这里给一个「在编辑器里跟着类型走」的具体路径。以 README 的 dependency injection 示例为样本。
examples/<di_example>.py
→ agent = Agent(Deps, Output) # agent/abstract.py + agent/spec.py:类型契约
→ @agent.tool def ... # tools.py + _function_schema.py:签名 → JSON schema
→ agent.run("...") # _agent_graph.py:一次 run 的执行图/状态机
→ 组装 messages # messages.py:请求消息模型
→ 调 model # models/:provider 抽象(openai/anthropic/...)
→ 工具调用 # _tool_execution.py
→ 结构化输出 # _output.py:运行时用 Pydantic 校验 Output
→ 拿到强类型 Output,无 Any # 调用方
跟读顺序(带断点):
examples/里最小 DI 示例,先建立直觉pydantic_ai_slim/pydantic_ai/tools.py+_function_schema.py—— 断在 schema 生成处,看函数签名如何变成 JSON schema(对照 BodySense 手写 schema 的漂移)models/—— 断在generate调用,看消息如何被序列化给 providermessages.py—— 看请求/响应消息模型_agent_graph.py—— 断在节点执行,看一次 run 怎么被切成图节点_output.py—— 断在validate处,看结构化输出如何在边界被校验
自检:Dependencies 类型从注入点一路到 model 调用、再到 Output 返回,全程是否没有 Any?这正是 BodySense AI 层「松散 dict」最该借鉴的。
值得偷师 / 不建议照抄
| 做法 | 评价 | 我的判断 |
|---|---|---|
Agent[Dependencies, Output] 类型参数贯穿全链路 | 强 | 直接对照 BodySense 的松散 dict |
| 从函数签名自动生成 Tool 参数 schema | 强 | 减少手写 schema 与漂移 |
| 结构化输出运行时校验(Pydantic 模型) | 强 | 边界处强制校验,而非约定 |
| cassette 录制真实集成测试 | 强 | 比纯 mock 更可信 |
| 多 AI 客户端协作规则(.agents/.claude/.gemini) | 中 | 工程化规范值得学 |
| durable_exec / graph workflow / human-in-the-loop | 待评估 | 高级特性,先确认是否如文档所说类型安全 |
我的疑问与待验证
durable_exec(airflow/temporal/prefect 适配)、pydantic_graph、human-in-the-loop tool approval这些高级特性,实际落地是否真的端到端类型安全?还是只在主路径上严格、边缘有Any?- BodySense 已有
runtime/checkpointing.py与runtime/governance.py,和这里的durable_exec/capabilities在抽象层级上如何对应?
沉淀出的笔记
- BodySense Diagnosis 的 PydanticAI 执行边界 — 用真实 Diagnosis 重构串起 constructor DI、RunContext、Tool Calling、structured output 与 targeted evidence trail。
相关链接 / 官方入口
| 入口 | 地址 |
|---|---|
| 仓库 | https://github.com/pydantic/pydantic-ai |
| 工程规范 | https://raw.githubusercontent.com/pydantic/pydantic-ai/main/AGENTS.md |
| 文档 | https://ai.pydantic.dev/ |