想象一家后厨里有一位学徒厨师:他背熟了成百上千道菜谱,能把“把面团放进烤箱,180 度烤 20 分钟”写得头头是道,可真让他动手烤面包,他却不知道什么时候该点火、怎么设定温度。传统的语言模型正是这样的“纸上厨师”——能生成流畅的文字,却不会真正使用计算器、搜索引擎这些“厨房工具”。ToolFormer 要做的事,就像给这位学徒一本神奇的菜谱合集:里面既有普通的做菜步骤,又夹着“此时举起搅拌器打 30 秒”这样的工具使用便签。学徒只需要像背菜谱一样把整本书从头读到尾——读着读着,他自然就明白“打蛋”之后该拿搅拌器,算式出现时该掏计算器。练熟之后,他再做菜时就能一边写步骤、一边随时抓起工具实测一把,再把结果写回菜谱里。就这样,一个只会纸上谈兵的厨师,蜕变成了能独立操作整个厨房的掌勺大厨。本篇我们就来拆解这套“菜谱炼金术”:数据怎么来、模型怎么练、工具怎么选、推理怎么闭环。
ToolFormer 是 Agentic AI 工具调用能力的奠基性范式。理解它的数据构建、训练与过滤机制,能让你在设计大模型 Agent 应用时,一眼看穿“模型凭什么知道该用什么工具”的本质。
可视化演示
展示ToolFormer自监督学习机制:在文本中采样工具调用候选位置、比较有无可显著降低困惑度的工具结果保留、四阶段训练管道及多任务性能对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
自监督工具调用学习 在语料中采样候选位置插入API调用,执行获取结果后比较有无可工具的预测损失 损失降低超过阈值τ的位置保留工具调用,反之为噪声过滤掉 keep if L(y|x,tool(x)) < L(y|x) - τ 无需人工标注即可学会何时调用工具
核心思想
学徒厨师最困惑的时刻,是菜谱写到一半突然冒出一句“此时用搅拌器打 30 秒”。他不知道该不该信这句话,更不知道什么时候该自己主动抓起搅拌器。ToolFormer 的核心思想,就是让模型把“抓工具”这件事变得和“写下一个字”一样自然。
2023 年 Meta AI 提出 ToolFormer(Toolformer: Language Models Can Teach Themselves to Use Tools),核心观察是:工具调用本质上可以写成一段文本,比如「调用 计算器 5+7」。既然如此,干脆把工具调用当作序列里的普通 token,和文字混合在一起,让语言模型用自回归的方式统一建模——工具调用不再是外挂动作,而是语言本身的一部分。
整个序列(文本、工具调用标记、执行结果)都服从同一个概率分布,模型要学的就是“给定前文,下一个元素是什么”:
回到厨房:学徒读菜谱时嘴里念叨的是“下一个字是什么”,工具调用标记对模型来说只是另一种“字”。念多了,看到“称重”就知道下一步该写“拿电子秤”——这就是 ToolFormer 让模型获得工具直觉的方式。
- y_{1T} 混合序列:从第 1 个元素到第 T 个元素的完整序列,其中每个 y_t 可能是普通文本 token,也可能是工具调用标记或执行结果。
- P_{\theta} 模型概率带参数 θ 的语言模型给出的概率分布,θ 就是模型里待学习的全部权重。
- ∏ 连乘符号自回归生成是“一个接一个”的,所以整个序列的概率等于每一步条件概率的乘积。
- y_t \mid y_{<t} 条件关系竖线左边是要预测的当前元素,右边是它之前的所有元素,表示“已知前文,预测下一个”。
- 整体含义工具调用标记和文本 token 地位平等,模型必须在混合序列中同时学会“说什么”和“何时调用工具”。
训练数据构建
学徒手头有两类资料:一类是干干净净的菜谱书,只讲文字步骤;另一类是主厨的手记,上面贴着便签:“面粉结块?过筛!”“烤箱火力不稳?测温!”ToolFormer 训练同样需要两类数据混合:纯文本语料负责维持语言功底,工具调用语料负责注入工具技能。
工具调用语料从哪来?答案是“自我标注”。先拿一个小语言模型在纯文本的每个位置采样候选工具调用(相当于主厨铅笔写在菜谱边上的便签),再把这些调用真实执行一遍,拿到结果。为了覆盖更多位置,还会用 KNN 把相似句子上学到的标注迁移过去,最后按比例混合成一份“带便签的菜谱”:
两份材料合订成一本带便签的菜谱:既有流畅的行文,又有关键时刻的工具提示。学徒抱着这本书读下去,既练了文笔,也记住了工具的位置。
- D_text 纯文本语料干净的“菜谱书”,负责让模型保持流畅的语言表达。
- D_tool 工具调用语料每条样本都夹着“标记—执行—结果”的三明治结构。
- λ 混合权重取值在 0 到 1 之间,控制两类语料各占多少比例,通常工具语料占比很小。
- ⊕ 合并运算把两类样本拼进同一个训练集,而不是分成两个阶段先后训练。
- 整体含义混合后的数据集同时包含“如何说话”和“何时用工具”的信息,模型一次训练全部吸收。
自监督训练
学徒练功靠“接龙”:主厨的训练方法是把合订本菜谱从头读到尾,每次遮住一个词让他猜下一个是什么。猜错了就调整,猜对了就继续。这种练法不需要任何人来讲解“为什么要用搅拌器”——只要菜谱里确实写着,读多了自然形成条件反射。
ToolFormer 使用的正是标准语言模型的自监督目标:预测下一个 token。特别之处在于,这些 token 里混着工具调用和工具结果,模型每一次“猜词”都是在同时训练语言能力和工具调用时机。训练目标就是最小化所有位置的负对数似然:
一整本菜谱读下来,学徒不仅学会了措辞,还学会了“读到'称重'就该拿电子秤”的条件反射。这种不经人工讲解、纯粹从数据里“悟”出来的能力,正是“自监督”三个字的精髓。
- L(θ) 损失函数衡量模型预测序列与真实序列的差距,数值越小说明“接龙”越准。
- log 对数把概率的连乘变成对数相加,避免数值下溢,也让梯度计算更稳定。
- −Σ 负求和对所有位置的对数概率取负号再求和,把“最大化概率”等价转化为“最小化损失”。
- 梯度更新用反向传播算出梯度并更新参数 θ,这就是“练功”的具体动作。
- 整体含义文本、工具调用、工具结果全部参与损失计算,模型被迫学会三者的节奏。
工具调用过滤
学徒试菜有个规矩:凡是标记了工具调用的步骤,必须真做一遍。如果做出来的菜比不做的版本还难吃,这条便签就得当场撕掉。ToolFormer 的过滤环节,就是给训练数据做一场严格的“试菜”。
采样出来的候选工具调用并不都靠谱。ToolFormer 的做法是把候选调用真实执行,把执行结果接回句子,看看它是否让“预测下一个词”的损失下降。只有那些执行后带来增益的调用才被留下,否则丢弃:
经过“尝菜”淘汰,留下来的都是经得起实操检验的步骤。菜谱越改越精,学徒再练时就不会被错误示范带偏——这就是工具调用过滤对数据质量的守护。
- c 候选工具调用模型在某个位置采样出的“此处该用工具”标记。
- L_base(c) 基线损失不使用工具结果、直接预测被遮蔽 token 时的损失。
- L_exec(c) 执行损失把工具真实执行的结果接回序列后再预测时的损失。
- 1[·] 指示函数条件成立取 1、否则取 0,相当于决定“留下”还是“撕掉”这张便签。
- 整体含义只有“用了工具反而预测得更准”的调用才能进入最终训练集,质量由此得到保障。
推理应用
出师那天,学徒要当着客人的面做一道完整的菜。他一边写步骤一边动手:写到“需要精确计时”,就伸手抓秒表;秒表显示 180 秒,他把这个读数记回操作单,继续往下做。ToolFormer 在推理时正是这样“边写边做”的。
当模型自回归生成时,一旦吐出特殊标记(比如「调用 计算器 5+7」),生成流程暂停,系统去执行真实的工具 API,得到的结果以文本 token 形式追加回上下文。模型“看到”这个结果后,继续生成后续内容。这个过程的数学表达就是上下文的更新:
“写一步、试一步、记一步”的闭环,看似简单,却正是智能体行动的本质雏形。客人面前那位从容的厨师,已经不再只是背书,而是在真实世界里和工具打交道。
- C_t 当前上下文模型生成过程中的全部历史,包括文本和之前所有工具结果。
- call_t 工具调用标记模型刚生成的特殊标记,描述了调用哪个工具、传什么参数。
- Execute(·) 执行器真实运行的 API,比如计算器算出 12、搜索引擎返回 3 条结果。
- ⊕ 拼接把执行结果 r_t 作为新的 token 追加进上下文末尾,模型“看见”结果。
- 整体含义“生成—调用—观察—再生成”构成闭环,模型越用越知道下一步该干什么。
范式演进意义
当初那个只会读菜谱的学徒,如今坐上了主厨的位置。他不仅自己会抓工具,还能同时指挥烤箱、搅拌器、温度计协同工作——语言模型也由此从“纸上谈兵”走向“动手做事”。这正是 Agent 范式演进的关键一步。
在算术、问答、表格处理、外语翻译等任务上,ToolFormer 相比同规模纯语言模型都有明显提升。它证明了一个重要结论:工具调用不需要专门的外挂模块,可以用数据直接教出来。这种“以数据驱动获得工具能力”的范式,为 ReAct、function calling 等后续 Agent 路线铺平了道路:
当然,ToolFormer 也有局限:早期版本只能单步调用工具、依赖执行反馈的质量、推理时有额外开销。未来方向是复杂多步工具链与大规模工具集上的规划。一个厨师能掌勺,但完整的餐厅还需要更多系统配合——这正是 Agentic AI 的下一个篇章。
- Perf_Baseline 基线性能同规模纯语言模型在目标任务上的性能指标。
- Perf_ToolFormer 增强性能接入工具学习后的模型在同一任务上的指标。
- Δ 差值两者相减,量化“学会用工具”带来的改善。
- 大于 0 的意义只有在绝大多数任务上 Δ>0,工具学习范式才被证明有效。
- 整体含义工具能力让模型从“会说话”升级为“会做事”,为更复杂的多步智能体打下基础。
AI 应用场景
企业知识库智能客服
阶段:训练数据构建 + 推理应用
解决的问题:传统客服机器人只能检索固定 FAQ,遇到“帮我算一下这个订单的税费”就哑火。用 ToolFormer 思路,模型学会在回答前自动调用搜索接口查知识库、调用计算接口算金额,把结果拼进回答,无需为每个场景单独训练一个工具模块。
具体案例:某电商平台客服接入工具学习后,用户问“三件 199 元商品打八折再减 50 是多少”,模型自动触发 calc(199*3*0.8-50),算出 427.6 后组织语言回答,计算类问题准确率从 62% 提升到 91%。
AI 数据分析助手
阶段:推理应用 + 工具调用过滤
解决的问题:大模型直接做数值计算经常算错,因为数字推理不是纯语言任务。通过 ToolFormer 式训练,模型学会在计算任务前调用代码解释器或计算器,而不是硬编数字;工具调用过滤则保证只有“执行后确实正确”的调用模式被保留。
具体案例:数据分析 Agent 收到“2023 年各季度营收环比增长率”时,先触发 sql 查询工具取出数据,再触发 calc 计算环比,最后生成图表,全程不需要人干预,数值错误率显著下降。
多工具出行规划 Agent
阶段:推理应用 + 范式演进
解决的问题:单次工具调用不够时,Agent 需要连续多次调用并观察结果再决策。这正是 ToolFormer 范式向 Agentic AI 演进的方向——模型把每次工具结果都写回上下文,逐步逼近完整答案。
具体案例:用户说“周六从北京去上海玩两天”,Agent 依次调用 search(weather)、search(flight)、calc(车费预算),每个结果都回填上下文,最后输出包含天气提醒、车次推荐和预算明细的完整行程单。
Python 演示
import re # 模拟 ToolFormer: 用带 <TOOL>/<RESULT> 标记的语料训练一个小模型# 模型学会在特定词后触发工具调用, 推理时执行工具并把结果写回序列 CORPUS = [ "今天天气<TOOL>search(weather)</TOOL><RESULT>晴,25度</RESULT>适合出门散步", "5加7等于<TOOL>calc(5+7)</TOOL><RESULT>12</RESULT>回答完毕", "矩形面积<TOOL>calc(3*4)</TOOL><RESULT>12</RESULT>平方米", "北京到上海<TOOL>search(flight)</TOOL><RESULT>高铁4.5小时</RESULT>非常方便",] SEARCH_DB = { "search(weather)": "晴,25度", "search(flight)": "高铁4.5小时",} TOKEN_RE = re.compile(r"<TOOL>[^<]*</TOOL>|<RESULT>[^<]*</RESULT>|[^<>]+") def tokenize(sentence): return [t for t in TOKEN_RE.findall(sentence) if t.strip()] def strip_tag(token): return token.replace("<TOOL>", "").replace("</TOOL>", "") class ToolFormer: def __init__(self, corpus): self.corpus = corpus self.bigram_table = {} # 前词 -> 后标记 -> 次数 self.tool_triggers = {} # 前词 -> 触发工具调用次数 def train(self): for sent in self.corpus: tokens = tokenize(sent) for prev, nxt in zip(tokens[:-1], tokens[1:]): key = strip_tag(prev) if key not in self.bigram_table: self.bigram_table[key] = {} self.bigram_table[key][nxt] = self.bigram_table[key].get(nxt, 0) + 1 if "<TOOL>" in nxt: self.tool_triggers[key] = self.tool_triggers.get(key, 0) + 1 def predict_next(self, word): table = self.bigram_table.get(word, {}) if not table: return None return max(table, key=table.get) def generate(self, start, max_len=6): out = [start] word = start for _ in range(max_len): nxt = self.predict_next(word) if nxt is None: break out.append(nxt) if "<RESULT>" in nxt: break word = strip_tag(nxt) return out def execute_tool(call_token): """模拟工具执行: calc 真算, search 查表""" if call_token.startswith("<TOOL>calc"): expr = re.sub(r"^<TOOL>calc\((.*?)\)</TOOL>$", r"\1", call_token) try: return str(eval(expr)) except Exception: return "ERROR" if call_token.startswith("<TOOL>search"): name = re.sub(r"^<TOOL>(search\(.*?\))</TOOL>$", r"\1", call_token) return SEARCH_DB.get(name, "未找到") return "未知工具" def main(): model = ToolFormer(CORPUS) model.train() print("=== 工具触发词统计(学到何时用工具) ===") for word, count in sorted(model.tool_triggers.items(), key=lambda x: -x[1]): print(" {0} 之后触发工具调用 {1} 次".format(word, count)) print() print("=== 推理: 生成带工具调用的序列 ===") for start in ["5加7等于", "今天天气", "矩形面积"]: seq = model.generate(start) text = "".join(seq) print("生成: {0}".format(text)) for token in seq: if "<TOOL>" in token: result = execute_tool(token) text = text.replace(token, "[执行: {0}]".format(result)) if "<RESULT>" in token: text = text.replace(token, "") print("执行后: {0}".format(text)) print() if __name__ == "__main__": main()
CORPUS = [...]构造带<TOOL>/<RESULT>标记的“菜谱语料”,对应 ToolFormer 的数据形态TOKEN_RE = re.compile(...)用正则把句子切成文本、工具调用、执行结果三类 tokenself.bigram_table[key][nxt] = ...统计相邻 token 转移次数,相当于模型学习“上一步接什么”if "<TOOL>" in nxt:记录哪些词后面常跟工具调用,这就是模型学到的“调用时机”def predict_next(self, word)根据当前词返回最可能的下一个标记,等价于简化版 P(y_t | y_{<t})def execute_tool(call_token)模拟工具执行器:calc 直接计算、search 查内置数据库seq = model.generate(start)自回归生成完整序列,遇到<RESULT>就停下等待text.replace(token, "[执行: ...]")把执行结果回填进序列,模拟推理时的上下文更新闭环
常见误区
误区我一开始以为 ToolFormer 就像教小孩用工具一样,需要人把“这句话后面该调用计算器”一条条标注出来。没有标注数据,模型怎么可能自己学会?
正解ToolFormer 是自监督的:它用小语言模型在海量纯文本上自动采样候选工具调用,把调用真实执行后看能否降低预测损失,能降低才保留。整个过程不需要人工标注“何时用工具”,只需要工具本身能提供执行反馈——就像学徒自己试菜,尝一口就知道好不好吃,不用主厨在旁边指指点点。
为何常见:传统监督学习“先标注再训练”的思维惯性太强,容易忽略语言模型自监督的强大潜力。
误区我以为筛选候选工具调用和普通分类任务一样,看模型输出那个标记时的置信度分数,分数高就留下。
正解ToolFormer 的过滤依据不是模型嘴上说的置信度,而是“实际执行效果”——把工具真实运行一次,把结果拼回句子,看预测下一个词的损失是否比不调用工具时更低。这好比判断一道菜好不好吃,不是听厨师吹嘘自己多有把握,而是真尝一口。置信度再高,执行结果不对也是白搭。
为何常见:深度学习中“置信度筛选”太常见,容易把执行反馈这层关键差异忽略掉。
误区我原来的思路是:模型负责生成文本,再写一个专门的选择器网络决定调用哪个工具,两个模块分开训练。
正解ToolFormer 的优雅之处在于把工具调用当成文本 token 本身,与语言模型一起端到端训练,根本不需要额外的选择器模块。模型学会了在合适的语境下“吐出”一个工具调用标记,就像厨师把“拿搅拌器”直接写进操作单,而不是旁边再站一个指挥员。
为何常见:早期的 Agent 架构普遍是“规划器 + 执行器”分离设计,容易让人误以为工具选择必须独立成模块。
误区既然工具调用能让模型变强,那就把训练数据全部换成带工具调用的语料,效果岂不更好?
正解ToolFormer 的最终训练集是纯文本与工具语料按比例混合的。纯文本负责维持语言能力,工具语料负责注入工具技能;如果只有工具语料,模型会像只读便签不读正文的学徒,连正常的句子都写不顺。两类数据缺一不可,λ 的取值本身就是个需要调的超参数。
为何常见:看到工具语料带来的收益后,容易产生“多多益善”的直觉,忽略了语言能力这个底盘。
面试题
Q1. ToolFormer 的核心创新在于什么?
- A.用强化学习训练工具选择策略
- B.把工具调用融入文本序列训练← 正确答案
- C.为每个工具单独训练专属模型
- D.用人工标注数据训练工具模块
答案:B。ToolFormer 的创新是把工具调用当作普通文本 token,与语言模型一起自回归训练,而不是用强化学习或独立模块。B 正确;A 是后续其他工作的方法,C、D 都违背了“自监督 + 统一序列”的设计初衷。
Q2. ToolFormer 训练数据的两大来源是?
- A.纯文本语料和工具调用语料← 正确答案
- B.问答对话对和代码仓库语料
- C.图像描述和语音转写语料
- D.人类反馈和奖励模型评分
答案:A。ToolFormer 混合两类数据:D_text(纯文本)保底语言能力,D_tool(工具调用语料)注入工具技能,对应文中“菜谱书 + 主厨便签”的比喻。B、C、D 都不是论文描述的数据来源。
Q3. 候选工具调用样本是如何生成的?
- A.由语言模型自动采样生成← 正确答案
- B.从随机词表中暴力抽取
- C.由人类专家逐条手工编写
- D.从 GitHub 代码中抓取
答案:A。候选工具调用由小语言模型在纯文本各位置自动采样产生,再通过执行和过滤形成高质量样本。A 正确;B 没有语义依据,C 违背自监督初衷,D 与工具调用标注机制无关。
Q4. ToolFormer 过滤工具调用的依据是?
- A.模型输出置信度的高低
- B.工具执行后能否降低损失← 正确答案
- C.工具调用的文本长度大小
- D.人工打分排序的先后顺序
答案:B。过滤标准是把工具真实执行后接回句子,看预测下一个词的损失是否比不调用时更低(L_exec < L_base)。B 正确;A 是常见误区,C、D 与执行质量无关。
Q5. 关于 ToolFormer 的推理过程,说法正确的有?
- A.模型生成特殊标记触发工具调用← 正确答案
- B.工具执行结果回填到上下文中← 正确答案
- C.模型在每一步都必须调用工具
- D.文本生成与工具调用同一序列← 正确答案
答案:ABD。推理时模型自回归生成,遇到特殊标记即暂停调用工具,结果以 token 形式回填上下文后继续生成,A、B、D 正确。C 错误——ToolFormer 学习的正是“何时调用”,而不是每步都调用。
Q6. ToolFormer 能实现“自我改进”的根本原因是?
- A.模型参数量比原来的版本更大
- B.训练数据经过真实执行反馈筛选← 正确答案
- C.训练过程使用了更多的 GPU 资源
- D.引入了大量人类专家的经验知识
答案:B。ToolFormer 的自我改进来自“采样—执行—过滤”的数据飞轮:候选调用只有经过真实执行并证明能降低损失才保留,数据质量随迭代提升。B 正确;A、C 是资源问题,D 违背自监督思想。
Q7. 相比传统外挂工具模块,ToolFormer 的优势有?
- A.无需额外训练工具选择模块← 正确答案
- B.模型自动学习工具的调用时机← 正确答案
- C.完全不需要工具执行的结果
- D.自然支持多种工具混合使用← 正确答案
答案:ABD。ToolFormer 把工具选择变成 token 预测,省去独立选择模块,调用时机从数据中自动习得,且多个工具可以混在同一序列里,A、B、D 正确。C 错误——工具执行结果是训练和推理都必需的回填信息。
Q8. 关于训练数据混合,下列说法正确的是?
- A.应只用工具调用语料来训练
- B.按比例混合纯文本与工具语料← 正确答案
- C.让模型只专注于学习工具细节
- D.按时间顺序排列两类不同数据
答案:B。最终训练集是 D = λ·D_tool ⊕ (1−λ)·D_text,纯文本保语言能力、工具语料注入技能。B 正确;A、C 会导致语言能力灾难性遗忘,D 的“时间排序”不是论文中的做法。
Q9. 工具执行结果在序列中是如何表示的?
- A.作为隐藏层向量直接传入模型
- B.作为普通文本标记拼接回上下文← 正确答案
- C.通过反向传播直接修改模型权重
- D.存入独立缓存数据库供后续查询
答案:B。执行结果 r_t 通过 ⊕ 拼接进上下文 C_{t+1} = C_t ⊕ Execute(call_t),作为普通 token 参与后续生成。B 正确;A、C 都不是序列层面操作,D 与自回归生成机制不符。
Q10. ToolFormer 的局限与挑战包括哪些?
- A.早期版本只支持单步工具调用← 正确答案
- B.结果质量依赖工具执行反馈← 正确答案
- C.推理阶段伴有额外的计算开销← 正确答案
- D.可以完全消除模型的幻觉问题
答案:ABC。早期 ToolFormer 每次只做一步工具调用,尚未形成复杂多步链;训练依赖执行反馈的质量;推理时暂停生成、执行工具、回填结果会引入额外开销,A、B、C 正确。D 错误——工具增强能减少但无法完全消除幻觉。