PydanticAI 的工具调用系统实践
PydanticAI 的工具调用系统实践
学习目标
补充理解:
- PydanticAI 的两阶段工具处理(验证与执行分离)
ToolDefinition的unless_native和with_native机制- Toolset 的可组合包装模式
前置知识
- 工具调用协议与执行模型 — 通用工具调用协议
1. 两阶段工具处理
PydanticAI 将工具处理分为两个独立阶段:
阶段 1: validate_tool_call() ├── 解析工具名称 ├── 构建 RunContext ├── 运行 before_tool_validate → wrap_tool_validate → after_tool_validate ├── Pydantic schema 验证 + 自定义 args_validator └── 返回 ValidatedToolCall (成功或失败)
阶段 2: execute_tool_call() ├── 运行 before_tool_execute → wrap_tool_execute → after_tool_execute ├── 调用 toolset.call_tool() └── 返回工具结果为什么分离?
- 允许提前知道工具调用是否有效,支持更精确的事件状态报告
- 验证失败和调用失败的错误路径不同——前者产生
ToolRetryError,后者通过on_tool_execute_errorhook 处理 - 支持工具参数的前置校验(在调用工具之前就报错)
2. ToolDefinition 的本地/原生回退
ToolDefinition 包含两个关键字段:
-
unless_native:当指定名称的原生工具被支持时,丢弃此本地工具定义- 例:本地 DuckDuckGo 搜索工具的
unless_native='web_search'——当模型支持原生 WebSearchTool 时,本地工具不会出现在 wire format 中
- 例:本地 DuckDuckGo 搜索工具的
-
with_native:当指定名称的原生工具被支持时,保留此工具定义(作为语料库成员)- 例:延迟加载工具的
with_native='tool_search'——当模型支持原生 ToolSearchTool 时,这些工具作为语料库成员保留
- 例:延迟加载工具的
这种机制实现了透明回退:用户无需手动判断应该使用原生工具还是本地工具。
3. Toolset 可组合包装模式
AbstractToolset 是所有工具集的基类,通过 WrapperToolset 子类实现横切行为:
AbstractToolset ├── FunctionToolset — Python 函数注册为工具 ├── WrapperToolset — 基类,委托给内部 toolset │ ├── ApprovalRequiredToolset — 工具调用前检查审批 │ ├── DeferredLoadingToolset — 工具延迟加载,按需发现 │ ├── FilteredToolset — 过滤工具子集 │ ├── PrefixedToolset — 工具名称添加前缀 │ ├── RenamedToolset — 工具名称重映射 │ ├── PreparedToolset — 预定义 defer_loading 标志 │ └── ExternalToolset — 外部 MCP 工具 └── CombinedToolset — 组合多个 toolset优势:通过组合而非继承添加行为——可以在任何工具集上添加审批、延迟加载、前缀命名等功能,无需修改基础类。
4. ToolSelector 灵活匹配
工具过滤支持四种匹配策略:
| 策略 | 说明 |
|---|---|
'all' | 匹配所有工具 |
Sequence[str] | 精确名称匹配 |
dict[str, Any] | 深度元数据匹配(检查 metadata 字段) |
Callable | 谓词函数 (ctx, tool_def) -> bool |
这使得 capability 可以精确控制哪些工具在哪些步骤中可用。