Toolformer:语言模型如何自学使用工具

让语言模型通过自监督方式学习何时调用搜索、计算器、翻译等外部工具,把“会说”进一步推进到“会在合适时机借力外部系统”。

年份与会议

2023 · NeurIPS

作者

Timo Schick、Jane Dwivedi-Yu、Roberto Dessì、Roberta Raileanu、et al.

主题

工具调用

阅读时长

约 3 分钟

收录时间

2023/02/09

标签

原文链接

https://arxiv.org/abs/2302.04761

为什么 Toolformer 很值得认真看

当大模型开始进入真实应用后,大家很快意识到一个根本问题:

  • 模型会写文字
  • 但很多任务真正需要的是“调用外部能力”

例如:

  • 算数最好交给计算器
  • 最新信息最好交给搜索
  • 时间换算最好交给日历或时区工具
  • 知识查询最好交给数据库或检索系统

这就引出一个重要问题:

模型到底该如何学会在合适时机调用工具,而不是靠人工把所有规则都硬编码进 prompt?

Toolformer 的关键贡献,就是尝试让语言模型自己学会这件事。它不只关心“工具能不能接进去”,更关心“模型如何知道什么时候该用、在哪里插入、调用后怎么继续写下去”。

这也是为什么 Toolformer 在工具调用和 Agent 路线中非常有代表性。

背景:把工具接进模型,不代表模型就会用

很多早期系统已经知道可以给 LLM 接搜索、计算器、翻译器、知识库 API。但实际效果常常不稳定,原因在于:

  1. 模型不知道什么时候该调工具。
  2. 即使知道,模型也不一定会在正确位置插入调用。
  3. 工具返回结果后,模型不一定会正确整合进后续生成。

也就是说,工具调用的难点不只是“系统集成”,而是“调用决策本身”。如果完全靠人工写规则,系统很快会变得:

  • 不通用
  • 难扩展
  • 对新工具非常脆弱

Toolformer 试图解决的,正是这个自动化问题。

核心问题:语言模型如何知道何时需要外部工具

从本质上说,工具调用是一个策略问题。模型需要隐式回答:

  • 当前 token 继续纯语言生成够不够?
  • 如果不够,哪个工具最有帮助?
  • 该把什么参数传给工具?
  • 工具返回后,输出应该如何继续?

Toolformer 的高明之处在于,它没有把这个问题完全当成强化学习或复杂规划来做,而是把它转回语言模型最熟悉的框架:

通过训练数据,让模型在序列生成中学会把工具调用当成一种特殊 token 行为。

这会让工具使用能力可以自然融进语言建模过程,而不是额外挂一个非常硬的外部控制器。

核心方法:用少量示例启发,再靠自监督扩充数据

Toolformer 的方法论非常漂亮。它大致分成三步:

第一步:给模型少量人工示例

先提供少量演示,告诉模型某类工具一般长什么样、在什么位置插入调用比较合理。

第二步:让模型在大规模文本上尝试插入工具调用

模型会在文本里候选一些可能调用工具的位置,并尝试把调用结果插进去。

第三步:根据语言建模收益筛选有效调用

并不是所有调用都保留,只有那些真正提升后续 token 预测效果的调用,才会进入训练数据。

这一步非常关键。因为它相当于给“是否应该调用工具”一个可训练的判断标准:如果工具结果真的让语言模型更容易预测后文,那么这个调用就是有价值的。

这也是 Toolformer 最有启发性的地方:它把工具调用决策和语言建模目标重新连在了一起。

如果把这套方法画成一条训练流水线,Toolformer 的新意就会很清楚:它不是只“接工具”,而是在自监督阶段筛出真正有价值的调用位置。

Toolformer 的自监督工具学习流程图 从少量人工示例出发,模型在大规模文本中候选工具插入位置,执行工具调用并观察是否降低语言建模损失,保留有效样本继续训练工具感知模型。 Toolformer 的关键不是“装更多工具”,而是自监督筛出“什么时候调用才真的有帮助”
  <g>
    <rect x="34" y="116" width="164" height="82" rx="18" fill="#ede9fe" stroke="#b7a8ea" />
    <text x="116" y="148" text-anchor="middle" font-size="19" font-weight="700">少量人工示例</text>
    <text x="116" y="172" text-anchor="middle" font-size="13" fill="#4b5563">先示范工具格式</text>
  </g>

  <g>
    <rect x="222" y="104" width="184" height="106" rx="20" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="314" y="138" text-anchor="middle" font-size="19" font-weight="700">候选插入位置</text>
    <text x="314" y="162" text-anchor="middle" font-size="13" fill="#4b5563">在大规模文本里猜测</text>
    <text x="314" y="183" text-anchor="middle" font-size="13" fill="#4b5563">“这里要不要查工具”</text>
  </g>

  <g>
    <rect x="430" y="104" width="170" height="106" rx="20" fill="#eef6e8" stroke="#a8c48e" />
    <text x="515" y="138" text-anchor="middle" font-size="19" font-weight="700">执行工具调用</text>
    <text x="515" y="162" text-anchor="middle" font-size="13" fill="#4b5563">搜索 / 计算器 / 翻译</text>
    <text x="515" y="183" text-anchor="middle" font-size="13" fill="#4b5563">把结果插回序列</text>
  </g>

  <g>
    <rect x="624" y="94" width="190" height="126" rx="22" fill="#fff4dc" stroke="#e2c36f" />
    <text x="719" y="128" text-anchor="middle" font-size="19" font-weight="700">收益筛选</text>
    <text x="719" y="152" text-anchor="middle" font-size="13" fill="#4b5563">看调用后是否更利于</text>
    <text x="719" y="173" text-anchor="middle" font-size="13" fill="#4b5563">预测后续 token</text>
    <text x="719" y="194" text-anchor="middle" font-size="13" fill="#4b5563">无收益调用直接丢弃</text>
  </g>

  <g>
    <rect x="838" y="116" width="108" height="82" rx="18" fill="#dff4f0" stroke="#8dc7bd" />
    <text x="892" y="148" text-anchor="middle" font-size="19" font-weight="700">训练</text>
    <text x="892" y="172" text-anchor="middle" font-size="13" fill="#4b5563">Tool-aware LM</text>
  </g>

  <line x1="198" y1="157" x2="222" y2="157" stroke="#5b6b7f" stroke-width="3" marker-end="url(#toolformer-arrow)" />
  <line x1="406" y1="157" x2="430" y2="157" stroke="#5b6b7f" stroke-width="3" marker-end="url(#toolformer-arrow)" />
  <line x1="600" y1="157" x2="624" y2="157" stroke="#5b6b7f" stroke-width="3" marker-end="url(#toolformer-arrow)" />
  <line x1="814" y1="157" x2="838" y2="157" stroke="#5b6b7f" stroke-width="3" marker-end="url(#toolformer-arrow)" />

  <rect x="154" y="264" width="676" height="70" rx="20" fill="#f9fafb" stroke="#d7e2f1" />
  <text x="492" y="292" text-anchor="middle" font-size="18" font-weight="700">核心判断标准</text>
  <text x="492" y="316" text-anchor="middle" font-size="14" fill="#4b5563">不是“这个工具能不能用”,而是“这个调用是否真的改善了后续生成”</text>
</g>
Toolformer 最重要的转变,是把“是否该调用工具”变成可训练、可筛选的序列决策,而不是完全依赖人工硬编码规则。

为什么这种训练方式很聪明

Toolformer 的方法之所以漂亮,是因为它避免了两个常见难题:

1. 不需要昂贵的大规模人工标注

如果每种工具都靠人手工标“这里应该调用”,成本会非常高,也难以扩展。

2. 不需要一开始就构造复杂 RL 环境

它不是先上强化学习,而是先利用语言模型自身的预测目标,构造一个更自然的训练信号。

换句话说,Toolformer 做的不是“教模型一堆死规则”,而是让模型通过自监督方式逐步体会:

  • 哪些地方调用工具对生成更有帮助
  • 哪些地方调用其实是多余的

这为后来的工具学习和 Agent 训练都提供了非常重要的思路。

Toolformer 真正解决的是哪一层问题

很多人第一次看 Toolformer,会以为它主要是在展示“接很多工具很酷”。其实它真正解决的是更底层的一层:

工具调用应该被当作语言模型序列决策的一部分,而不是完全外置的补丁逻辑。

也就是说,它的意义不只是工程接线,而是能力建模:

  • 什么时候查
  • 查什么
  • 查完后怎么接着说

这些问题如果不能进入模型的决策过程,那么工具再多也只是外部装饰。

这也是 Toolformer 与 ReAct 可以互补的地方:

  • ReAct 更强调思考和行动的流程结构
  • Toolformer 更强调工具调用本身如何被模型学会

为什么它对今天的函数调用和 API Agent 仍然有启发

今天很多产品里的函数调用、tool calling、MCP、agent workflow 看起来和 Toolformer 的实验设定不完全一样,但底层问题高度一致:

  • 模型要不要调用工具
  • 该调用哪一个
  • 参数从哪里来
  • 返回结果如何被整合

Toolformer 的启发在于,它提醒我们不要把这件事只当系统工程,而要把它看作模型行为学习问题。

换句话说,现代函数调用系统常常有两层:

  1. 框架层定义调用协议
  2. 模型层决定何时使用协议

Toolformer 正是在第二层上非常有代表性的早期工作。

关键实验传递出的信号

Toolformer 的实验最想说明的,并不是“某个 benchmark 提升了多少”,而是下面这个更本质的结论:

语言模型并非只能在封闭上下文里续写,它可以学会在生成过程中有选择地借助外部系统。

这个结论很重要,因为它改变了大家对“模型能力边界”的理解:

  • 有些能力可以通过参数内化获得
  • 有些能力更适合通过外部工具按需补充

从这个角度看,Toolformer 实际上在推动一种更模块化的 AI 观:模型不需要自己会一切,但要会决定什么时候借力。

局限:Toolformer 距离真实工具生态还有哪些距离

虽然 Toolformer 很有启发,但它也有明显局限:

1. 工具环境仍然偏理想化

论文里的工具接口相对干净,而真实世界里常常有权限、失败重试、网络波动、参数 schema 等复杂问题。

2. 调用收益不一定容易用语言建模损失衡量

有些工具调用也许对最终任务很重要,但未必在局部 token 预测上立刻体现出巨大收益。

3. 多工具协同仍然很难

单次调用已经不易,多个工具串联、参数依赖、状态共享会让问题复杂得多。

4. 工具使用不等于完整 Agent 能力

模型会调工具,并不自动意味着它会规划、反思、纠错和长期追踪目标。

因此,Toolformer 更像工具学习路线的开端,而不是完整 Agent 终局。

从今天看,Toolformer 最重要的遗产是什么

Toolformer 最重要的遗产,是它把“工具调用”从纯系统工程问题推进成了模型学习问题。它告诉我们:

  1. 工具使用可以被训练,而不只是被规则硬编码。
  2. 何时调用工具,本身就是模型能力的一部分。
  3. 外部工具不是 LLM 的补丁,而可以成为其自然扩展。

这三点对今天的函数调用、Browser Agent、代码执行 Agent、企业工作流系统都很有影响。很多现代系统虽然实现路径不同,但都在延续这个观念。

读这篇论文时最该抓住什么

如果你只想抓住主线,请记住:

  1. Toolformer 的关键不是“接工具”,而是“让模型学会何时用工具”。
  2. 它通过自监督数据构造,把工具调用融进语言建模过程。
  3. 它为后来函数调用和 Agent 系统提供了非常重要的能力视角。

理解这三点后,你再看今天各种 tool calling 框架时,就不会只把它们理解成接口协议,而会更关心模型到底有没有学会好的调用决策。

延伸阅读

相关内容

沿着相近主题继续阅读,加深对方法边界与实践场景的理解。