Toolformer:让模型从数据中学会何时调用工具
原始来源
Timo Schick 等,2023:Toolformer: Language Models Can Teach Themselves to Use Tools,本页按 arXiv v1 阅读。
本页是原创学习导读,不含原文复刻;论文版权与完整内容以原始来源为准。
学习目标
读完后,你应该能够:
- 从普通文本语料出发,完整复述“候选位置与调用采样 → 执行 API → 损失过滤 → 构造增强语料 → 微调 → 推理时调用”的六段流程。
- 解释 Toolformer 为什么同时比较“调用并返回结果”“不调用”“只有调用没有结果”三种上下文。
- 为一个候选调用计算教学版的损失收益,并判断它是否应进入训练集。
- 区分 Toolformer 学到的模型行为、运行时真正执行 API 的职责,以及现代 Tool Calling 平台额外提供的工程能力。
一句话抓住它
Toolformer 用少量 API 示范引导基础语言模型在普通语料中提出大量候选调用,再只保留那些能显著降低后续 token 预测损失的调用,由此自动构造工具使用训练数据。
它真正要解决的问题
语言模型擅长生成文本,却常在几类任务上输给简单工具:精确计算、近期事实、日期换算、外语翻译和长尾知识查询。直接给模型接上工具还不够,因为系统仍要回答四个问题:
- 何时调用? 不是每句话都值得付出一次 API 成本。
- 调用哪个? 数学问题应交给计算器,近期实体信息可能需要搜索。
- 参数是什么? 工具名正确但表达式或查询词错误,结果仍然无用。
- 怎样使用返回值? 模型必须在后续文本里吸收结果,而不是调用后忽略它。
在 Toolformer 之前,一种常见办法是为这些决策制作大量人工标注,另一种是针对某个下游任务写固定调用规则。论文想验证更一般的路线:只给每个 API 几个示范,让模型自己提出训练样本,再用已有的语言建模能力判断哪些样本值得学习。
“自己教自己”不是没有人和工具
人仍要定义 API、准备少量示范、提供普通文本语料、真正执行候选调用,并设定采样与过滤阈值。自动化的是从大语料中发现并筛选有用调用,而不是 API 设计、执行环境或安全治理。
先读懂论文中的对象和符号
| 记号或对象 | 含义 | 在流程中的职责 |
|---|---|---|
| 待训练的语言模型 | 采样候选,也给候选计算语言建模损失,最后在增强语料上微调 | |
| 普通文本语料 | 提供没有工具标注的原始 token 序列 | |
| 某个 API 的少样本提示 | 告诉模型该工具的调用格式与大致用途 | |
| 插在位置 的候选调用 | 包含 API 名 和输入参数 | |
| 实际执行 后得到的文本结果 | 判断调用是否真的为后文提供信息 | |
| 线性化的“调用 + 结果”片段 | 例如 <API> Calculator(18/24) → 0.75 </API> | |
| 经过筛选并插入调用片段的增强语料 | 用标准语言建模目标继续训练 | |
| 采样阈值与过滤阈值 | 分别控制候选位置数量和最低有效收益 |
论文要求工具的输入和输出都能表示成文本序列,并且每个工具要有少量预期用法示范。实验中的五类工具是问答系统、Wikipedia 搜索、计算器、机器翻译和日历。
六段核心机制
flowchart TD C["普通语料 C"] --> P["1. 为每个 API 准备少量示范 P(x)"] P --> S["2. 采样候选插入位置与调用参数"] S --> E["3. 真实执行 API,得到文本结果 r"] E --> L["4. 比较未来 token 损失"] L -->|"收益达到阈值"| K["保留调用与结果"] L -->|"收益不足"| D["丢弃候选"] K --> A["5. 合并为增强语料 C*"] A --> F["用标准 LM 目标微调模型"] F --> I["6. 推理时模型生成调用,运行时插入结果后续写"]
第 1 段:用少量示范定义一个工具的“语言接口”
作者为每个 API 写一个 Prompt,展示如何在普通文本中插入调用。示范告诉模型的不是某个下游任务答案,而是“在什么文本语境中,这种 API 可能提供完成后文所需的信息”。不同 API 分别生成候选,之后才合并。
概念上,调用写成:
<API> API名称(输入) → 返回结果 </API>论文实际复用了已有 token 序列表示边界和箭头,没有要求修改词表。重要的是调用、参数、返回值和结束位置在文本中可被模型学习。
第 2 段:先找可能的插入位置,再采样具体调用
对文本 的每个位置 ,模型计算在该前缀后开始生成 API 标记的概率:
只有 的位置进入候选集合;如果候选太多,只保留概率最高的前 个。随后,模型以该位置之前的文本和 <API> 为前缀,采样最多 个具体调用,直到生成结束标记。没有正确闭合调用的样本会被丢弃。
这一步解决两个不同问题:位置概率回答“现在是否可能需要工具”,调用采样回答“用哪个工具、传什么参数”。此时得到的只是提案,里面会有正确调用、无用调用和格式错误,不能直接当监督数据。
第 3 段:执行候选,取得真实返回值
系统逐个执行候选 API。执行可能是调用另一个神经模型、运行 Python 计算器,或在语料库中检索。论文要求每个响应最终变成一段文本 ,以便插回 token 序列。
这一步不可省略。只看调用字符串,无法知道查询是否命中、计算是否正确,也无法判断返回值是否真的帮助预测后文。
第 4 段:用未来 token 损失过滤
论文在候选位置之后的原始 token 上计算加权交叉熵。把“调用与结果都提供给模型”时的损失记为:
负向基线不是单一条件,而取下面两者中损失更小、也就是更强的那个:
- :完全没有 API 调用。
- :看见调用内容,但没有得到返回结果。
最终只保留满足下式的调用:
直观上,候选不仅要比“不调用”好,还要证明返回结果本身带来了足够的未来预测收益。假如模型只凭调用参数就能猜出后文,或结果与后文无关,收益不会达到阈值。
这个信号优化的是什么
过滤目标是“帮助基础模型预测原始语料的未来 token”,不是直接优化事实正确率、用户任务成功率、安全性或 API 成本。它是一个聪明但有限的代理目标,不能把“低困惑度”自动解释成“生产环境中最好的工具决策”。
第 5 段:构造 并继续做语言建模
各工具中通过过滤的调用会被合并,并在相应位置与原文交错,形成 。除插入的 API 片段外,增强语料保留 中原有文本。模型随后用标准语言建模目标在 上微调,而不是另加一个独立的“工具分类头”。
模型由此在同一种 next-token 训练中学习:普通文本何时继续生成、何时开始调用、调用名称与参数如何写、结果出现后怎样续写。未插入调用的大量普通文本同时提供“不必调用工具”的隐式负例。
第 6 段:推理时由模型发起、运行时负责执行
微调后,模型照常解码。当它生成表示“接下来期待 API 结果”的箭头标记时,外部运行时暂停生成,解析工具与参数,实际调用 API,把返回结果和结束标记插入上下文,再让模型继续生成后文。
所以 Toolformer 从来不是“纯模型独自完成工具调用”。模型学习发出可识别的调用文本;执行器仍然是必须存在的控制边界。论文实验还调整了解码策略,让 API 起始标记进入概率前 时即可触发,并为避免循环把每个输入限制为最多一次 API 调用。这些是该实验的具体运行设置,不是所有工具模型都必须照搬的协议。
从一条普通句子走完数据生成
下面使用原创教学文本和虚构损失值说明流程。原始语料中有一句:
A case contains 24 bottles and costs $18. Each bottle costs $0.75.1. 模型提出候选
在 $0.75 之前,模型提出两个候选:
候选 A:<API> Calculator(18 / 24) → ? </API>
候选 B:<API> Calendar() → ? </API>候选 A 的工具和参数与待预测数字有关;候选 B 格式可能完全合法,却与单价无关。
2. 环境执行
A 的结果:0.75
B 的结果:Today is Sunday, August 9, 2026.3. 计算教学版收益
假设过滤阈值 ,损失如下。这些数字只为帮助理解,不是论文报告值:
| 候选 | 无调用/只有调用中的较优损失 | 有调用和结果的损失 | 收益 | 决策 |
|---|---|---|---|---|
| Calculator | 4.8 | 1.1 | 3.7 | 保留 |
| Calendar | 4.8 | 4.6 | 0.2 | 丢弃 |
于是增强文本可能成为:
A case contains 24 bottles and costs $18. Each bottle costs
<API> Calculator(18 / 24) → 0.75 </API> $0.75.模型以后看到类似语境,就有机会在需要精确算术的地方生成计算器调用;同时,它没有从这个样本学到“看到任何数字都查日历”。
4. 为什么还会留下噪声
未来 token 损失只是代理。有些无意义返回恰好与后文词形相关,也可能通过阈值;有些对真实任务有用的调用,却未必改善紧邻文本预测,因而被丢弃。论文自己的定性分析也展示了过滤分数与人类直觉并非完全一致。因此,自动筛选降低了人工量,不等于生成了无噪声金标数据。
教学版伪代码
def build_augmented_corpus(model, corpus, api_specs,
sample_threshold, filter_threshold):
kept = []
for text in corpus:
annotations = []
for api in api_specs:
positions = sample_positions(
model, text, api.demonstrations, sample_threshold
)
calls = sample_calls(model, text, positions, api)
for position, call in calls:
result = api.execute(call.arguments)
loss_with_result = future_loss(
model, text, position, call=call, result=result
)
loss_without_call = future_loss(
model, text, position, call=None, result=None
)
loss_call_only = future_loss(
model, text, position, call=call, result=None
)
baseline = min(loss_without_call, loss_call_only)
if baseline - loss_with_result >= filter_threshold:
annotations.append((position, call, result))
kept.append(interleave(text, merge_compatible(annotations)))
return kept
def generate_with_tools(model, prompt, runtime):
tokens = []
while not model.is_finished(tokens):
token = model.next_token(prompt, tokens)
tokens.append(token)
if token == "ARROW_EXPECTING_RESULT":
call = parse_open_api_call(tokens)
result = runtime.execute(call.name, call.arguments)
tokens.extend(encode_result_and_close(result))
return decode(tokens)build_augmented_corpus 是离线数据管线;generate_with_tools 是在线推理管线。把它们分开,可以避免最常见的误读:论文的主要创新是自动构造训练数据和学习调用行为,但在线阶段依然需要工具运行时。
原典证据应该怎样读
论文以 6.7B 参数 GPT-J 为主要基础模型,在问答、数学、事实补全和时间相关任务上测试五类工具。值得记住的不是某个单一排行榜数值,而是几组机制证据:
- 启用工具后,经过 Toolformer 训练的模型在多项零样本任务上优于不调用工具的对应设置,并在论文所测若干任务上超过了更大的 GPT-3 基线。
- 当推理时禁用 API,使用带调用的增强语料训练,并没有比在同一普通语料上继续训练带来额外的语言建模困惑度损失;这支持“插入工具样本没有明显毁掉一般文本能力”的局部结论。
- 在论文测试的 GPT-2 尺度系列中,较小模型没有明显利用工具,收益大约从 775M 参数附近才出现。论文把它描述为该设置下的能力尺度现象,不是所有架构的固定参数门槛。
- 解码时提高 API 起始 token 的触发范围会显著增加调用率,但调用更多不一定保持校准;这说明“会调用”和“在必要时才调用”是两个不同指标。
结果边界
这些实验使用 2023 年的固定模型、固定文本 API、特定采样阈值和最多一次调用等约束。它们证明该自监督管线可以教会模型有选择地使用一组工具,不能证明它已经解决多步工具规划、生产可靠性或任意新 API 的零成本迁移。
论文明确暴露的限制
- 不能学习工具链。 各 API 的候选独立生成,训练数据没有把一个工具的输出作为另一个工具的输入。
- 不能交互式浏览。 搜索结果被压成单段文本,模型不能翻页、比较大量结果或根据第一轮结果继续改写查询。
- 对措辞敏感。 输入表述的小变化可能改变是否调用 API。
- 样本效率可能很低。 论文指出,处理超过百万文档,计算器也可能只得到几千条有用调用。
- 过滤目标不含成本。 调用是否值得,只按未来 token 损失衡量,没有纳入延迟、价格或失败风险。
- 运行设置限制调用次数。 论文评测中每个输入最多一次调用,用来避免模型陷入只调用不输出的循环;复杂任务自然超出这个边界。
这些限制解释了为什么 Toolformer 不能替代 ReAct 一类运行时闭环:它可以学会“这里应当查一次”,却没有展示“查完后根据观察规划下一次不同工具调用”的完整交互策略。
与现代 Tool Calling 的边界
| Toolformer 原典直接解决的部分 | 现代生产运行时仍要提供的部分 |
|---|---|
| 从数据中学习调用时机、工具选择、参数文本和结果续写 | JSON Schema、类型校验、权限与用户确认 |
| 用真实 API 结果生成训练样本 | 超时、重试、幂等、速率限制和并发控制 |
| 用语言模型损失筛选可能有用的调用 | 任务成功评测、成本预算、安全策略和审计 |
| 以文本标记触发执行器 | 结构化协议、错误分类、不可信返回隔离 |
今天的 Function Calling 往往由模型输出结构化对象,由应用程序决定是否执行;Toolformer 使用线性化文本片段并通过微调学会生成。二者共享“模型提出调用、外部系统执行、结果回到上下文”的边界,但训练方式、协议和可靠性保证不同。
自测:确认你掌握了机制
- 为什么候选 API 调用不能在生成后直接作为正例,而必须先执行并过滤?
- 过滤时为什么还要比较“只有调用、没有返回结果”的条件?
- 如果一个搜索调用能降低未来 token 损失,却返回了过期事实,Toolformer 的原始过滤目标一定会拒绝它吗?为什么?
- 设计一个日历 API 的有用候选和一个格式正确但无用的候选,并说明期望的损失差异。
- Toolformer 与 ReAct 分别解决工具系统中的哪一层问题?
参考答案
- 候选来自模型采样,会包含错误参数、无关工具和无结果调用。只有真实执行后,才能知道返回值,并测量它是否帮助预测后文。
- 这样可以排除“调用文本本身已经泄露后文”的情况。保留样本必须证明结果比“不调用”和“只显示调用”中的较强基线更有用。
- 不一定会拒绝。原目标只测未来 token 预测损失,不直接验证事实时效性;过期结果如果恰好与语料后文一致,仍可能通过。因此生产数据还需要真实性与时间校验。
- 有用例:文本将说明“明天是星期几”,在答案前调用日历并返回当天日期,结果显著降低损失。无用例:描述一件商品颜色时调用日历,返回日期几乎不改变颜色 token 的预测损失。
- Toolformer 主要解决模型如何从训练数据获得调用时机、选择和参数行为;ReAct 主要解决推理时如何根据一次次环境观察继续规划和行动。二者可以组合,但不能互相替代。
上一篇:ReAct · 下一篇:Generative Agents · 返回 里程碑原典目录