想象一家后厨里有一位学徒厨师:他背熟了成百上千道菜谱,能把“把面团放进烤箱,180 度烤 20 分钟”写得头头是道,可真让他动手烤面包,他却不知道什么时候该点火、怎么设定温度。传统的语言模型正是这样的“纸上厨师”——能生成流畅的文字,却不会真正使用计算器、搜索引擎这些“厨房工具”。ToolFormer 要做的事,就像给这位学徒一本神奇的菜谱合集:里面既有普通的做菜步骤,又夹着“此时举起搅拌器打 30 秒”这样的工具使用便签。学徒只需要像背菜谱一样把整本书从头读到尾——读着读着,他自然就明白“打蛋”之后该拿搅拌器,算式出现时该掏计算器。练熟之后,他再做菜时就能一边写步骤、一边随时抓起工具实测一把,再把结果写回菜谱里。就这样,一个只会纸上谈兵的厨师,蜕变成了能独立操作整个厨房的掌勺大厨。本篇我们就来拆解这套“菜谱炼金术”:数据怎么来、模型怎么练、工具怎么选、推理怎么闭环。

岗位关联

ToolFormer 是 Agentic AI 工具调用能力的奠基性范式。理解它的数据构建、训练与过滤机制,能让你在设计大模型 Agent 应用时,一眼看穿“模型凭什么知道该用什么工具”的本质。

目录
  1. 可视化演示
  2. 核心思想
  3. 训练数据构建
  4. 自监督训练
  5. 工具调用过滤
  6. 推理应用
  7. 范式演进意义
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示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 让模型获得工具直觉的方式。

Pθ(y1:T)=∏t=1TPθ(yt∣y<t)\displaystyle P_{\theta}(y_{1:T}) = \prod_{t=1}^{T} P_{\theta}(y_t \mid y_{<t})
这个公式说明:无论是普通文字还是工具调用,都被放进同一个“接龙”概率框架里,模型练好它,就等于同时学会了说话和用工具的时机。
  1. y_{1T} 混合序列:从第 1 个元素到第 T 个元素的完整序列,其中每个 y_t 可能是普通文本 token,也可能是工具调用标记或执行结果。
    y1:T=(y1,y2,…,yT)y_{1:T} = (y_1, y_2, \dots, y_T)
  2. P_{\theta} 模型概率带参数 θ 的语言模型给出的概率分布,θ 就是模型里待学习的全部权重。
    Pθ(⋅)P_{\theta}(\cdot)
  3. ∏ 连乘符号自回归生成是“一个接一个”的,所以整个序列的概率等于每一步条件概率的乘积。
    ∏t=1T(⋅)\prod_{t=1}^{T} (\cdot)
  4. y_t \mid y_{<t} 条件关系竖线左边是要预测的当前元素,右边是它之前的所有元素,表示“已知前文,预测下一个”。
    Pθ(yt∣y1,y2,…,yt−1)P_{\theta}(y_t \mid y_1, y_2, \dots, y_{t-1})
  5. 整体含义工具调用标记和文本 token 地位平等,模型必须在混合序列中同时学会“说什么”和“何时调用工具”。
    yt∈{文本,工具调用,工具结果}y_t \in \{\text{文本}, \text{工具调用}, \text{工具结果}\}

训练数据构建

学徒手头有两类资料:一类是干干净净的菜谱书,只讲文字步骤;另一类是主厨的手记,上面贴着便签:“面粉结块?过筛!”“烤箱火力不稳?测温!”ToolFormer 训练同样需要两类数据混合:纯文本语料负责维持语言功底,工具调用语料负责注入工具技能。

工具调用语料从哪来?答案是“自我标注”。先拿一个小语言模型在纯文本的每个位置采样候选工具调用(相当于主厨铅笔写在菜谱边上的便签),再把这些调用真实执行一遍,拿到结果。为了覆盖更多位置,还会用 KNN 把相似句子上学到的标注迁移过去,最后按比例混合成一份“带便签的菜谱”:

两份材料合订成一本带便签的菜谱:既有流畅的行文,又有关键时刻的工具提示。学徒抱着这本书读下去,既练了文笔,也记住了工具的位置。

D=λ⋅Dtool⊕(1−λ)⋅Dtext\displaystyle \mathcal{D} = \lambda \cdot \mathcal{D}_{\text{tool}} \oplus (1 - \lambda) \cdot \mathcal{D}_{\text{text}}
纯文本与工具语料按 λ 加权混合,既要保住语言能力,又要学会用工具,两不耽误。
  1. D_text 纯文本语料干净的“菜谱书”,负责让模型保持流畅的语言表达。
    Dtext\mathcal{D}_{\text{text}}
  2. D_tool 工具调用语料每条样本都夹着“标记—执行—结果”的三明治结构。
    Dtool\mathcal{D}_{\text{tool}}
  3. λ 混合权重取值在 0 到 1 之间,控制两类语料各占多少比例,通常工具语料占比很小。
    0<λ<10 < \lambda < 1
  4. ⊕ 合并运算把两类样本拼进同一个训练集,而不是分成两个阶段先后训练。
    merge(Dtool,Dtext)\text{merge}(\mathcal{D}_{\text{tool}}, \mathcal{D}_{\text{text}})
  5. 整体含义混合后的数据集同时包含“如何说话”和“何时用工具”的信息,模型一次训练全部吸收。
    D∼加权混合后的训练集\mathcal{D} \sim \text{加权混合后的训练集}

自监督训练

学徒练功靠“接龙”:主厨的训练方法是把合订本菜谱从头读到尾,每次遮住一个词让他猜下一个是什么。猜错了就调整,猜对了就继续。这种练法不需要任何人来讲解“为什么要用搅拌器”——只要菜谱里确实写着,读多了自然形成条件反射。

ToolFormer 使用的正是标准语言模型的自监督目标:预测下一个 token。特别之处在于,这些 token 里混着工具调用和工具结果,模型每一次“猜词”都是在同时训练语言能力和工具调用时机。训练目标就是最小化所有位置的负对数似然:

一整本菜谱读下来,学徒不仅学会了措辞,还学会了“读到'称重'就该拿电子秤”的条件反射。这种不经人工讲解、纯粹从数据里“悟”出来的能力,正是“自监督”三个字的精髓。

L(θ)=−∑t=1Tlog⁡Pθ(yt∣y<t)\displaystyle \mathcal{L}(\theta) = -\sum_{t=1}^{T} \log P_{\theta}(y_t \mid y_{<t})
损失函数衡量模型预测与真实序列的差距。工具调用标记和其他 token 一同参与计算,模型必须“猜”出何时调用工具才能降低损失。
  1. L(θ) 损失函数衡量模型预测序列与真实序列的差距,数值越小说明“接龙”越准。
    L(θ)\mathcal{L}(\theta)
  2. log 对数把概率的连乘变成对数相加,避免数值下溢,也让梯度计算更稳定。
    log⁡Pθ(yt∣y<t)\log P_{\theta}(y_t \mid y_{<t})
  3. −Σ 负求和对所有位置的对数概率取负号再求和,把“最大化概率”等价转化为“最小化损失”。
    −∑t=1T(⋅)-\sum_{t=1}^{T} (\cdot)
  4. 梯度更新用反向传播算出梯度并更新参数 θ,这就是“练功”的具体动作。
    θ←θ−η∇θL(θ)\theta \leftarrow \theta - \eta \nabla_{\theta} \mathcal{L}(\theta)
  5. 整体含义文本、工具调用、工具结果全部参与损失计算,模型被迫学会三者的节奏。
    yt∈{文本,工具调用,工具结果}y_t \in \{\text{文本}, \text{工具调用}, \text{工具结果}\}

工具调用过滤

学徒试菜有个规矩:凡是标记了工具调用的步骤,必须真做一遍。如果做出来的菜比不做的版本还难吃,这条便签就得当场撕掉。ToolFormer 的过滤环节,就是给训练数据做一场严格的“试菜”。

采样出来的候选工具调用并不都靠谱。ToolFormer 的做法是把候选调用真实执行,把执行结果接回句子,看看它是否让“预测下一个词”的损失下降。只有那些执行后带来增益的调用才被留下,否则丢弃:

经过“尝菜”淘汰,留下来的都是经得起实操检验的步骤。菜谱越改越精,学徒再练时就不会被错误示范带偏——这就是工具调用过滤对数据质量的守护。

1[c^]={1,Lexec(c)<Lbase(c)0,否则\displaystyle \mathbb{1}[\hat{c}] =\begin{cases}1, & \mathcal{L}_{\text{exec}}(c) < \mathcal{L}_{\text{base}}(c) \\0, & \text{否则}\end{cases}
判断标准不是模型嘴上说的置信度,而是“真做一遍”后预测是否更准。实践上还会设阈值,比如要求 60% 以上的候选优于基线才保留该工具调用模式。
  1. c 候选工具调用模型在某个位置采样出的“此处该用工具”标记。
    c^=sample(yt)\hat{c} = \text{sample}(y_t)
  2. L_base(c) 基线损失不使用工具结果、直接预测被遮蔽 token 时的损失。
    Lbase(c)\mathcal{L}_{\text{base}}(c)
  3. L_exec(c) 执行损失把工具真实执行的结果接回序列后再预测时的损失。
    Lexec(c)\mathcal{L}_{\text{exec}}(c)
  4. 1[·] 指示函数条件成立取 1、否则取 0,相当于决定“留下”还是“撕掉”这张便签。
    1[条件成立]=1\mathbb{1}[\text{条件成立}] = 1
  5. 整体含义只有“用了工具反而预测得更准”的调用才能进入最终训练集,质量由此得到保障。
    Filter={c^:Lexec(c)<Lbase(c)}\text{Filter} = \{\hat{c} : \mathcal{L}_{\text{exec}}(c) < \mathcal{L}_{\text{base}}(c)\}

推理应用

出师那天,学徒要当着客人的面做一道完整的菜。他一边写步骤一边动手:写到“需要精确计时”,就伸手抓秒表;秒表显示 180 秒,他把这个读数记回操作单,继续往下做。ToolFormer 在推理时正是这样“边写边做”的。

当模型自回归生成时,一旦吐出特殊标记(比如「调用 计算器 5+7」),生成流程暂停,系统去执行真实的工具 API,得到的结果以文本 token 形式追加回上下文。模型“看到”这个结果后,继续生成后续内容。这个过程的数学表达就是上下文的更新:

“写一步、试一步、记一步”的闭环,看似简单,却正是智能体行动的本质雏形。客人面前那位从容的厨师,已经不再只是背书,而是在真实世界里和工具打交道。

Ct+1=Ct⊕Execute(callt)\displaystyle \mathcal{C}_{t+1} = \mathcal{C}_{t} \oplus \text{Execute}(\text{call}_t)
上下文拼接上工具执行结果,模型基于更新后的完整历史继续生成。推理时的“暂停—执行—回填—继续”就是 Agent 行动闭环的最小雏形。
  1. C_t 当前上下文模型生成过程中的全部历史,包括文本和之前所有工具结果。
    Ct=(y1,y2,…,yt)\mathcal{C}_t = (y_1, y_2, \dots, y_t)
  2. call_t 工具调用标记模型刚生成的特殊标记,描述了调用哪个工具、传什么参数。
    callt=[调用 工具名(参数)]\text{call}_t = \text{[调用 工具名(参数)]}
  3. Execute(·) 执行器真实运行的 API,比如计算器算出 12、搜索引擎返回 3 条结果。
    Execute(callt)→rt\text{Execute}(\text{call}_t) \to r_t
  4. ⊕ 拼接把执行结果 r_t 作为新的 token 追加进上下文末尾,模型“看见”结果。
    Ct+1=(Ct,rt)\mathcal{C}_{t+1} = (\mathcal{C}_t, r_t)
  5. 整体含义“生成—调用—观察—再生成”构成闭环,模型越用越知道下一步该干什么。
    生成→调用→观察→生成\text{生成} \to \text{调用} \to \text{观察} \to \text{生成}

范式演进意义

当初那个只会读菜谱的学徒,如今坐上了主厨的位置。他不仅自己会抓工具,还能同时指挥烤箱、搅拌器、温度计协同工作——语言模型也由此从“纸上谈兵”走向“动手做事”。这正是 Agent 范式演进的关键一步。

在算术、问答、表格处理、外语翻译等任务上,ToolFormer 相比同规模纯语言模型都有明显提升。它证明了一个重要结论:工具调用不需要专门的外挂模块,可以用数据直接教出来。这种“以数据驱动获得工具能力”的范式,为 ReAct、function calling 等后续 Agent 路线铺平了道路:

当然,ToolFormer 也有局限:早期版本只能单步调用工具、依赖执行反馈的质量、推理时有额外开销。未来方向是复杂多步工具链与大规模工具集上的规划。一个厨师能掌勺,但完整的餐厅还需要更多系统配合——这正是 Agentic AI 的下一个篇章。

ΔPerf=PerfToolFormer−PerfBaseline>0\displaystyle \Delta_{\text{Perf}} = \text{Perf}_{\text{ToolFormer}} - \text{Perf}_{\text{Baseline}} > 0
性能差值衡量“学会用工具”带来的增益。单个任务上增益看似微小,但在一大批任务上累积,就构成了 Agent 范式演进的坚实基座。
  1. Perf_Baseline 基线性能同规模纯语言模型在目标任务上的性能指标。
    PerfBaseline\text{Perf}_{\text{Baseline}}
  2. Perf_ToolFormer 增强性能接入工具学习后的模型在同一任务上的指标。
    PerfToolFormer\text{Perf}_{\text{ToolFormer}}
  3. Δ 差值两者相减,量化“学会用工具”带来的改善。
    ΔPerf=PerfToolFormer−PerfBaseline\Delta_{\text{Perf}} = \text{Perf}_{\text{ToolFormer}} - \text{Perf}_{\text{Baseline}}
  4. 大于 0 的意义只有在绝大多数任务上 Δ>0,工具学习范式才被证明有效。
    ΔPerf>0\Delta_{\text{Perf}} > 0
  5. 整体含义工具能力让模型从“会说话”升级为“会做事”,为更复杂的多步智能体打下基础。
    ∑task1[Δtask>0]≫0\sum_{\text{task}} \mathbb{1}[\Delta_{\text{task}} > 0] \gg 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 演示

python103 行
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()
目的:用 n-gram 统计模型模拟 ToolFormer 的完整流程——从带工具标记的语料中学习“何时调用工具”,推理时自回归生成,遇到工具标记就暂停执行并回填结果。
  1. CORPUS = [...]构造带 <TOOL>/<RESULT> 标记的“菜谱语料”,对应 ToolFormer 的数据形态
  2. TOKEN_RE = re.compile(...)用正则把句子切成文本、工具调用、执行结果三类 token
  3. self.bigram_table[key][nxt] = ...统计相邻 token 转移次数,相当于模型学习“上一步接什么”
  4. if "<TOOL>" in nxt:记录哪些词后面常跟工具调用,这就是模型学到的“调用时机”
  5. def predict_next(self, word)根据当前词返回最可能的下一个标记,等价于简化版 P(y_t | y_{<t})
  6. def execute_tool(call_token)模拟工具执行器:calc 直接计算、search 查内置数据库
  7. seq = model.generate(start)自回归生成完整序列,遇到 <RESULT> 就停下等待
  8. text.replace(token, "[执行: ...]")把执行结果回填进序列,模拟推理时的上下文更新闭环

常见误区

误区我一开始以为 ToolFormer 就像教小孩用工具一样,需要人把“这句话后面该调用计算器”一条条标注出来。没有标注数据,模型怎么可能自己学会?

正解ToolFormer 是自监督的:它用小语言模型在海量纯文本上自动采样候选工具调用,把调用真实执行后看能否降低预测损失,能降低才保留。整个过程不需要人工标注“何时用工具”,只需要工具本身能提供执行反馈——就像学徒自己试菜,尝一口就知道好不好吃,不用主厨在旁边指指点点。

为何常见:传统监督学习“先标注再训练”的思维惯性太强,容易忽略语言模型自监督的强大潜力。

误区我以为筛选候选工具调用和普通分类任务一样,看模型输出那个标记时的置信度分数,分数高就留下。

正解ToolFormer 的过滤依据不是模型嘴上说的置信度,而是“实际执行效果”——把工具真实运行一次,把结果拼回句子,看预测下一个词的损失是否比不调用工具时更低。这好比判断一道菜好不好吃,不是听厨师吹嘘自己多有把握,而是真尝一口。置信度再高,执行结果不对也是白搭。

为何常见:深度学习中“置信度筛选”太常见,容易把执行反馈这层关键差异忽略掉。

误区我原来的思路是:模型负责生成文本,再写一个专门的选择器网络决定调用哪个工具,两个模块分开训练。

正解ToolFormer 的优雅之处在于把工具调用当成文本 token 本身,与语言模型一起端到端训练,根本不需要额外的选择器模块。模型学会了在合适的语境下“吐出”一个工具调用标记,就像厨师把“拿搅拌器”直接写进操作单,而不是旁边再站一个指挥员。

为何常见:早期的 Agent 架构普遍是“规划器 + 执行器”分离设计,容易让人误以为工具选择必须独立成模块。

误区既然工具调用能让模型变强,那就把训练数据全部换成带工具调用的语料,效果岂不更好?

正解ToolFormer 的最终训练集是纯文本与工具语料按比例混合的。纯文本负责维持语言能力,工具语料负责注入工具技能;如果只有工具语料,模型会像只读便签不读正文的学徒,连正常的句子都写不顺。两类数据缺一不可,λ 的取值本身就是个需要调的超参数。

为何常见:看到工具语料带来的收益后,容易产生“多多益善”的直觉,忽略了语言能力这个底盘。

面试题

Q1. ToolFormer 的核心创新在于什么?

单选题 · easy

  • A.用强化学习训练工具选择策略
  • B.把工具调用融入文本序列训练← 正确答案
  • C.为每个工具单独训练专属模型
  • D.用人工标注数据训练工具模块

答案:B。ToolFormer 的创新是把工具调用当作普通文本 token,与语言模型一起自回归训练,而不是用强化学习或独立模块。B 正确;A 是后续其他工作的方法,C、D 都违背了“自监督 + 统一序列”的设计初衷。

Q2. ToolFormer 训练数据的两大来源是?

单选题 · easy

  • A.纯文本语料和工具调用语料← 正确答案
  • B.问答对话对和代码仓库语料
  • C.图像描述和语音转写语料
  • D.人类反馈和奖励模型评分

答案:A。ToolFormer 混合两类数据:D_text(纯文本)保底语言能力,D_tool(工具调用语料)注入工具技能,对应文中“菜谱书 + 主厨便签”的比喻。B、C、D 都不是论文描述的数据来源。

Q3. 候选工具调用样本是如何生成的?

单选题 · easy

  • A.由语言模型自动采样生成← 正确答案
  • B.从随机词表中暴力抽取
  • C.由人类专家逐条手工编写
  • D.从 GitHub 代码中抓取

答案:A。候选工具调用由小语言模型在纯文本各位置自动采样产生,再通过执行和过滤形成高质量样本。A 正确;B 没有语义依据,C 违背自监督初衷,D 与工具调用标注机制无关。

Q4. ToolFormer 过滤工具调用的依据是?

单选题 · mid

  • A.模型输出置信度的高低
  • B.工具执行后能否降低损失← 正确答案
  • C.工具调用的文本长度大小
  • D.人工打分排序的先后顺序

答案:B。过滤标准是把工具真实执行后接回句子,看预测下一个词的损失是否比不调用时更低(L_exec < L_base)。B 正确;A 是常见误区,C、D 与执行质量无关。

Q5. 关于 ToolFormer 的推理过程,说法正确的有?

多选题 · mid

  • A.模型生成特殊标记触发工具调用← 正确答案
  • B.工具执行结果回填到上下文中← 正确答案
  • C.模型在每一步都必须调用工具
  • D.文本生成与工具调用同一序列← 正确答案

答案:ABD。推理时模型自回归生成,遇到特殊标记即暂停调用工具,结果以 token 形式回填上下文后继续生成,A、B、D 正确。C 错误——ToolFormer 学习的正是“何时调用”,而不是每步都调用。

Q6. ToolFormer 能实现“自我改进”的根本原因是?

单选题 · hard

  • A.模型参数量比原来的版本更大
  • B.训练数据经过真实执行反馈筛选← 正确答案
  • C.训练过程使用了更多的 GPU 资源
  • D.引入了大量人类专家的经验知识

答案:B。ToolFormer 的自我改进来自“采样—执行—过滤”的数据飞轮:候选调用只有经过真实执行并证明能降低损失才保留,数据质量随迭代提升。B 正确;A、C 是资源问题,D 违背自监督思想。

Q7. 相比传统外挂工具模块,ToolFormer 的优势有?

多选题 · mid

  • A.无需额外训练工具选择模块← 正确答案
  • B.模型自动学习工具的调用时机← 正确答案
  • C.完全不需要工具执行的结果
  • D.自然支持多种工具混合使用← 正确答案

答案:ABD。ToolFormer 把工具选择变成 token 预测,省去独立选择模块,调用时机从数据中自动习得,且多个工具可以混在同一序列里,A、B、D 正确。C 错误——工具执行结果是训练和推理都必需的回填信息。

Q8. 关于训练数据混合,下列说法正确的是?

单选题 · extreme

  • A.应只用工具调用语料来训练
  • B.按比例混合纯文本与工具语料← 正确答案
  • C.让模型只专注于学习工具细节
  • D.按时间顺序排列两类不同数据

答案:B。最终训练集是 D = λ·D_tool ⊕ (1−λ)·D_text,纯文本保语言能力、工具语料注入技能。B 正确;A、C 会导致语言能力灾难性遗忘,D 的“时间排序”不是论文中的做法。

Q9. 工具执行结果在序列中是如何表示的?

单选题 · mid

  • A.作为隐藏层向量直接传入模型
  • B.作为普通文本标记拼接回上下文← 正确答案
  • C.通过反向传播直接修改模型权重
  • D.存入独立缓存数据库供后续查询

答案:B。执行结果 r_t 通过 ⊕ 拼接进上下文 C_{t+1} = C_t ⊕ Execute(call_t),作为普通 token 参与后续生成。B 正确;A、C 都不是序列层面操作,D 与自回归生成机制不符。

Q10. ToolFormer 的局限与挑战包括哪些?

多选题 · hard

  • A.早期版本只支持单步工具调用← 正确答案
  • B.结果质量依赖工具执行反馈← 正确答案
  • C.推理阶段伴有额外的计算开销← 正确答案
  • D.可以完全消除模型的幻觉问题

答案:ABC。早期 ToolFormer 每次只做一步工具调用,尚未形成复杂多步链;训练依赖执行反馈的质量;推理时暂停生成、执行工具、回填结果会引入额外开销,A、B、C 正确。D 错误——工具增强能减少但无法完全消除幻觉。