工具使用与函数调用
Toolformer(Schick 等,2023)开启了自监督工具标注。Berkeley Function Calling Leaderboard V4(Patil 等,2025)则设定了 2026 年的标准:40% 智能体型、30% 多轮、10% 在线、10% 离线、10% 幻觉。单轮调用已经基本解决。记忆、动态决策和长时程工具链还没有。
类型: 构建 语言: Python(标准库) 先修要求: 第 14 阶段 · 01(智能体循环),第 13 阶段 · 01(函数调用深度解析) 时间: 约 60 分钟
学习目标
- 解释 Toolformer 的自监督训练信号:只有当执行结果降低下一令牌损失(next-token loss)时,才保留工具标注。
- 说出 BFCL V4 的五类评估维度,以及每一类衡量的内容。
- 仅用标准库实现一个带模式(schema)校验、参数强制转换和执行沙箱化的工具注册表。
- 诊断 2026 年的三个开放问题:长时程工具链、动态决策与记忆。
问题
早期的工具使用问题是:模型能否预测出一个正确的函数调用?现代的工具使用问题则是:模型能否在 40 步中串联工具,带着记忆,在部分可观测环境下,在工具失败后恢复,并且不去凭空编造根本不存在的工具?
Toolformer 建立了基线:模型可以通过自监督学习何时调用工具。BFCL V4 定义了 2026 年的评估目标。两者之间的差距,就是生产级智能体真正生存的空间。
概念
Toolformer(Schick 等,NeurIPS 2023)
核心思路:让模型给自己的预训练语料打上候选 API 调用标注。对每个候选标注,先执行它。只有当引入该工具结果能降低下一令牌损失(next-token loss)时,才保留这条标注。然后用筛选后的语料进行微调。
覆盖的工具包括:计算器、问答系统、搜索引擎、翻译器、日历。这个自监督信号完全基于工具是否有助于预测文本——没有人工标注。
规模化结果是:工具使用能力会随着规模自然涌现。较小模型会被工具标注拖累;较大模型则会从中获益。这也是为什么 2026 年的前沿模型往往原生具备很强的工具使用能力,而大多数 7B 模型若想可靠,仍需要显式的工具使用微调。
Berkeley Function Calling Leaderboard V4(Patil 等,ICML 2025)
BFCL 是 2026 年事实上的评估标准。V4 的组成如下:
- 智能体型(Agentic,40%) —— 完整的智能体轨迹:记忆、多轮交互、动态决策。
- 多轮(Multi-Turn,30%) —— 带工具链的交互式对话。
- 在线(Live,10%) —— 用户提交的真实提示(分布更难)。
- 离线(Non-Live,10%) —— 合成测试用例。
- 幻觉(Hallucination,10%) —— 检测在不该调用工具时是否仍然调用。
V3 引入了基于状态的评估:在一串工具调用后,检查 API 的真实状态(例如“文件是否真的创建了?”),而不是去匹配工具调用的 AST。V4 又新增了网页搜索、记忆以及格式敏感性等类别。
2026 年的关键发现是:单轮函数调用已接近解决。失败主要集中在记忆(跨轮次保留上下文)、动态决策(根据先前结果选择工具)、长时程链条(20 多步后开始漂移)以及幻觉检测(当没有合适工具时能否拒绝调用)。
工具模式
每个提供商都有自己的模式(schema)。细节各不相同,但结构相同:
name: string
description: string (what it does, when to use it)
input_schema: JSON Schema (properties, required, types, enums)Anthropic 直接使用 input_schema。OpenAI 使用 function.parameters。两者都接受 JSON Schema。description(描述)是承重件——模型会读取它来选择正确的工具。糟糕的工具描述,是“选错工具”失败的头号根因。
参数校验
不要信任任何工具调用。请校验:
- 类型强制转换。 模型可能返回字符串
"5",而模式要求的是整数。如果语义明确,就做转换;否则拒绝。 - 枚举校验。 如果模式规定
status in {"open", "closed"},而模型输出了"in_progress",就要返回带描述的错误。 - 必填字段。 缺失必填字段时,应立刻把错误观察返回给模型,而不是让系统崩溃。
- 格式校验。 日期、邮箱、URL——请用具体解析器校验,而不是正则表达式。
每一次校验失败都应返回结构化观察,让模型可以按正确形状重试。
并行工具调用
现代提供商支持在一次助手轮次(assistant turn)中并行调用多个工具。循环如下:
- 模型输出 3 个工具调用,每个都有不同的
tool_use_id。 - 运行时执行它们(如果彼此独立就并行执行)。
- 每个结果都作为
tool_result块,按tool_use_id关联回去。
工程规则:把关联 ID(correlation ID)当成承重件。若把它们配错了,你就会把错误的结果路由给错误的工具。
沙箱化
工具执行就是沙箱边界。详见第 09 课。简而言之:每个工具都应明确声明读/写范围、网络访问、超时和内存上限。通用的 run_shell(cmd) 是危险信号;更具体的 git_status() 则安全得多。
动手构建
code/main.py 实现了一个接近生产形态的工具注册表:
- JSON Schema 子集校验器(仅标准库)。
- 带描述、输入模式、超时和执行器的工具注册。
- 参数强制转换与枚举校验。
- 带关联 ID 的并行工具分发。
- 以结构化字符串返回的错误观察。
运行:
python3 code/main.py输出轨迹会展示一个迷你智能体在一轮中调用三个工具,其中一个调用故意构造成错误格式,并被以模型可处理的描述性错误拒绝。
使用它
每个提供商都有自己的工具模式——Anthropic、OpenAI、Gemini、Bedrock。如果你需要多提供商支持,就使用一层翻译层(如 OpenAI Agents SDK、Vercel AI SDK、LangChain 的工具适配层)。BFCL 是参考基准——如果工具使用是产品核心功能,在上线前先用它测试你的智能体。
交付上线
outputs/skill-tool-registry.md 会为给定任务域生成工具目录、模式与注册表。它还包含描述质量检查(每个工具的描述是否明确告诉模型“什么时候该用它”?)。
练习
- 添加一个“空操作”工具,让模型可以显式拒绝使用其他任何工具。然后在类似 BFCL 的幻觉测试上做衡量。
- 实现针对 int-as-string 和 float-as-string 的参数强制转换。强制转换从什么时候开始会掩盖真实缺陷(bug)?
- 为每个工具增加超时和熔断器(连续 3 次失败后 60 秒内拒绝该工具)。这会如何改变模型的恢复方式?
- 阅读 BFCL V4 的说明。选择一个类别(例如“多轮(multi-turn)”),用你的智能体跑 10 个示例提示。报告通过率。
- 把这个标准库校验器迁移到 Pydantic 或 Zod。Pydantic/Zod 抓到了哪些这个玩具实现遗漏的问题?
关键术语
| 术语 | 人们常说 | 实际含义 |
|---|---|---|
| 函数调用 | “工具使用” | 带校验模式的结构化工具调用 |
| Toolformer | “自监督工具标注” | Schick 2023——保留那些其结果能降低下一令牌损失的工具调用 |
| BFCL | “Berkeley 函数调用排行榜” | 2026 基准:40% 智能体型、30% 多轮、10% 在线、10% 离线、10% 幻觉 |
| 工具模式 | “给模型看的函数签名” | 名称、描述、参数的 JSON Schema |
| tool_use_id | “关联 ID” | 将工具调用与其结果绑定;并行分发时至关重要 |
| 幻觉检测 | “知道什么时候不该调用” | V4 类别之一:当没有合适工具时拒绝调用 |
| 参数强制转换 | “字符串转整数修复” | 对可预测的模式不匹配做窄修复;歧义时拒绝 |
| 沙箱隔离 | “工具执行边界” | 按工具定义读/写范围、网络、超时和内存上限 |
延伸阅读
- Schick et al., Toolformer (arXiv:2302.04761) —— 自监督工具标注
- Berkeley Function Calling Leaderboard (V4) —— 2026 评估基准
- Anthropic, Tool use documentation —— Claude Agent SDK 中的生产级工具模式(schema)
- OpenAI Agents SDK docs —— function tool 类型与 Guardrails