工具系统:从 Function Calling 到多类型编排
AI-02: 工具系统:从 Function Calling 到多类型编排
学习目标
- 掌握 12 种工具类型的分类体系(本地 vs 托管)
- 理解
FunctionTool的自动类型推导与 strict JSON schema 流程 - 理解工具规划 → 并行执行 → 结果归一化的三阶段流程
- 掌握 ToolSearchTool 与 deferred loading 模式
前置知识
本章涉及工具调用协议的通用原理,建议先阅读:
下文直接聚焦 OpenAI Agents SDK 的具体实现。
项目实践
12 种工具类型的分类
SDK 将 Tool 定义为一个联合类型,包含 12 个具体实现。核心区分维度是执行位置:
本地工具:在 Python 进程中执行,结果直接返回。FunctionTool 是最常用的类型——通过 @function_tool 装饰器从普通 Python 函数自动生成。
托管工具:配置被序列化到 Responses API,由 OpenAI 服务端执行(如文件搜索、网页搜索、代码解释器)。SDK 不需要执行这些工具,只需传递配置。
FunctionTool 自动类型推导
@function_tool 装饰器的核心流程:
关键步骤:
- 参数推断:
inspect.signature提取函数签名,get_type_hints获取类型标注 - Docstring 解析:
griffe库自动检测 Google/Numpy/Sphinx 风格,提取参数描述 - Pydantic 模型生成:用
pydantic.create_model()动态创建校验模型 - Strict JSON Schema:通过
ensure_strict_json_schema()转换——additionalProperties: False、所有属性变为 required、$ref展开、oneOf→anyOf
调用时:JSON 参数 → Pydantic 校验 → schema.to_call_args() → 调用函数。
三阶段工具执行流程
- 规划阶段:
_build_plan_for_fresh_turn()从模型响应中提取所有待执行工具,分类到ToolExecutionPlan的不同字段 - 执行阶段:
_execute_tool_plan()默认使用asyncio.gather()并行执行所有工具类别。FunctionTool 批次内部支持并发上限控制与故障仲裁 - 归一化阶段:每个工具类型的结果被包装为
RunItem子类型(ToolCallOutputItem),以 OpenAI Responses API 兼容格式添加到对话中
ToolSearchTool 与 deferred loading
ToolSearchTool 是一种托管工具,让模型按需搜索其他工具。配合 defer_loading=True 和 tool_namespace() 使用:
# 工具延迟加载——模型初始不可见@function_tool(defer_loading=True)def complex_analysis(): ...
# 工具命名空间——模型可搜索此命名空间ns = tool_namespace("data_tools", description="数据分析工具", tools=[tool1, tool2])
agent = Agent(tools=[ToolSearchTool(), ns])验证规则:
- 每个 Agent 仅允许一个
ToolSearchTool - 延迟加载的工具必须有
ToolSearchTool可达 ToolSearchTool至少需要一个可搜索表面(命名空间工具 / 延迟工具 / 延迟 MCP 服务器)
问题与规避
| 问题 | 规避方案 |
|---|---|
| Pydantic 类型不支持的函数参数 | 使用 str 参数 + 函数内部手动解析 |
| 工具调用超时 | 配置 timeout_seconds,选择 error_as_result(返回错误给模型)或 raise_exception(中断运行) |
| 多个 handoff 同时触发 | 仅第一个执行,其余收到 “Multiple handoffs detected, ignoring” 提示 |
| 严格 JSON schema 拒绝可选参数 | 确保类型标注正确,nullable 类型用 `str |
设计取舍
为什么工具默认并行执行
大多数工具调用彼此独立(查天气 ≠ 查邮件),并行执行最大化吞吐。但 SDK 提供了 parallel=False 选项用于顺序执行(功能工具先执行,其余类别顺序执行)。
优势:默认并行减少用户等待时间,无需手动配置。 代价:一个工具失败时,兄弟工具被取消,executor 需要 drain cancelled tasks 来优雅关闭。
为什么需要 strict JSON schema
OpenAI 的 strict mode 要求 additionalProperties: False 且所有属性 required。这保证了模型生成的 JSON 严格符合 schema,减少解析错误。SDK 自动将 Pydantic 模型转换为 strict schema,用户无需手动编写。
代价:某些 Pydantic 特性(如 oneOf)需要转换为 anyOf,可能影响模型对选项的理解。