跳转到内容

工具系统:从 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 装饰器的核心流程:

关键步骤:

  1. 参数推断inspect.signature 提取函数签名,get_type_hints 获取类型标注
  2. Docstring 解析griffe 库自动检测 Google/Numpy/Sphinx 风格,提取参数描述
  3. Pydantic 模型生成:用 pydantic.create_model() 动态创建校验模型
  4. Strict JSON Schema:通过 ensure_strict_json_schema() 转换——additionalProperties: False、所有属性变为 required、$ref 展开、oneOfanyOf

调用时:JSON 参数 → Pydantic 校验 → schema.to_call_args() → 调用函数。

三阶段工具执行流程

  1. 规划阶段_build_plan_for_fresh_turn() 从模型响应中提取所有待执行工具,分类到 ToolExecutionPlan 的不同字段
  2. 执行阶段_execute_tool_plan() 默认使用 asyncio.gather() 并行执行所有工具类别。FunctionTool 批次内部支持并发上限控制与故障仲裁
  3. 归一化阶段:每个工具类型的结果被包装为 RunItem 子类型(ToolCallOutputItem),以 OpenAI Responses API 兼容格式添加到对话中

ToolSearchTool 与 deferred loading

ToolSearchTool 是一种托管工具,让模型按需搜索其他工具。配合 defer_loading=Truetool_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,可能影响模型对选项的理解。

参考来源