AI 技术
#工具增强#ReAct#Toolformer#API调用#规划#大模型

自动规划工具使用:从 ReAct 到 Toolformer 的工程演进

大模型调用外部工具时,如何自动解析 API 文档、生成动作序列并处理错误?本文以企业客服查询系统为贯穿场景,对比 ReAct 的推理-行动交织与 Toolformer 的自监督工具学习,剖析二者在复杂 API 场景下的规划策略、鲁棒工具选择与执行验证方案,并给出工程权衡与常见失败模式。

一个面向企业知识库的客服智能体接到用户查询:“帮我查一下订单 ORD-8823 的物流状态,如果已签收,再查一下同品类商品最近的促销活动。” 这需要依次调用订单查询 API、物流 API,并根据返回结果决定是否触发促销查询 API。直接让大模型生成一个固定顺序的脚本很容易在物流状态为“运输中”时仍然错误地调用促销 API,或者因为 API 返回字段名与模型猜测不符而传入错误参数。

这种场景暴露了工具增强智能体(tool-augmented agent)的核心难题:模型不仅要理解自然语言指令,还要从一组可能频繁更新的 API 中选出正确的工具,按合理顺序调用,准确填入参数,并根据中间结果动态调整后续计划。ReAct 和 Toolformer 代表了两种截然不同的解决路径:前者在推理时通过提示词工程让模型显式地交替输出“思考”和“行动”,后者则在训练阶段自监督地学习何时插入 API 调用。

基线方案为什么不够用

在 ReAct 出现之前,让大模型使用工具的主流做法是“先规划后执行”:模型一次性生成完整的动作序列,然后逐步执行。这种方法在 API 行为完全可预测的简单场景下勉强可用,但面对真实世界 API 时,两个问题会迅速暴露。

第一,API 返回结果往往包含意外字段或状态码。例如,物流 API 可能返回 {"status": "exception", "message": "运单号不存在"},而模型在规划时假设只会返回“运输中”或“已签收”。一旦实际返回与预期不符,后续动作就会基于错误假设继续执行,形成级联错误。第二,API 文档会更新。一个促销查询 API 可能从 GET /promos?category={cat} 变更为 POST /promotions 并要求在请求体中传入 category_idwarehouse_code。一次性生成的计划无法适应这类变化,执行到一半就会因为参数错误而失败。

工程上,我们通常把这种失败归为两类:规划漂移(plan drift)和接口失配(interface mismatch)。规划漂移指环境反馈改变了前置条件,但计划没有随之调整;接口失配指模型生成的函数签名与实际 API 不兼容。ReAct 和 Toolformer 分别从推理时和训练时两个维度尝试解决这两个问题。

ReAct:推理与行动的交替协同

ReAct 的核心思想是让模型在生成最终答案之前,交替输出“推理轨迹”(reasoning trace)和“行动”(action)。推理轨迹用自然语言描述当前已知信息、还需要什么信息、下一步应该做什么;行动则是对外部工具的一次具体调用,例如 Wikipedia 搜索或计算器。模型看到工具返回的观察结果后,再继续生成下一段推理和行动,直到认为可以给出最终答案。

在论文中,ReAct 被应用于知识问答(HotpotQA)和交互式决策(ALFWorld)等任务。以 HotpotQA 为例,模型可以先用推理轨迹拆解问题:“我需要找到‘苹果公司总部’的位置,然后搜索‘苹果公司总部’的建筑面积。”接着调用 Wikipedia API 搜索“Apple Inc. headquarters”,得到观察结果后,再推理“搜索结果提到了 Apple Park,我需要进一步搜索 Apple Park 的建筑面积”,然后再次调用 API。这种模式将高层规划、信息筛选和异常处理都融合在自然语言推理中,使整个决策过程对人类可读。

从工程角度看,ReAct 的实现通常是一个循环:

  1. 将当前上下文(用户问题 + 历史推理-行动-观察)拼接成提示词,输入模型。
  2. 模型生成一段文本,解析出 Thought(推理)和 Action(行动)。
  3. 执行 Action,获取 Observation(观察)。
  4. 将 Thought/Action/Observation 追加到上下文,回到步骤 1,直到模型输出 Final Answer。

这种设计直接解决了规划漂移问题:因为每一步行动都基于最新的观察,模型可以随时修正方向。例如,当物流 API 返回“运单号不存在”时,模型可以在下一轮推理中写道:“运单号可能错误,我需要先调用订单查询 API 确认运单号是否正确。”然后调整行动。

但 ReAct 也有明显的工程局限。首先,它对提示词格式高度敏感。如果 Thought 和 Action 的解析规则不够鲁棒,模型可能输出不符合格式的文本,导致行动提取失败。其次,ReAct 依赖模型本身具备较强的推理能力,小模型很容易在长上下文中迷失,重复无效行动或过早结束。最后,ReAct 不涉及任何训练,模型对 API 的理解完全来自提示词中的描述和示例,当 API 数量增多或文档变长时,上下文窗口会迅速膨胀,推理延迟和成本都会显著上升。

Toolformer:让模型自监督学会调用工具

Toolformer 采取了一条完全不同的路径:它不依赖推理时的提示词工程,而是在训练阶段教会模型自主决定何时调用哪些 API。核心流程是:

  1. 准备少量 API 使用示例,例如“计算 123 + 456 的结果是 [Calculator(123 + 456) → 579] 579”。
  2. 用这些示例在无标注文本中采样,让模型生成可能的 API 调用插入位置和参数。
  3. 执行生成的 API 调用,获得实际返回结果。
  4. 比较加入 API 调用前后的语言模型损失,如果损失降低,则保留该调用;否则丢弃。
  5. 用筛选后的数据微调模型,使模型学会在文本中插入特殊标记(如 <API></API>)来触发工具调用。

训练完成后,模型在生成文本时如果遇到需要外部知识或计算的地方,会自主输出 API 调用标记,外部系统执行调用并将结果插回文本流,模型再基于增强后的上下文继续生成。Toolformer 论文中集成了计算器、问答系统、搜索引擎、翻译系统和日历等工具,在零样本任务上取得了显著提升,且没有牺牲语言模型的核心能力。

Toolformer 的关键优势在于工具调用决策是内化在模型参数中的,不需要精心设计提示词,也不占用推理时的上下文窗口。模型自己学会了“这个问题需要计算”或“这个事实我不确定,需要搜索”。这在一定程度上缓解了接口失配问题,因为模型在训练时见过大量成功和失败的调用模式,对参数格式有更鲁棒的建模。

但 Toolformer 的局限同样明显。首先,它假设 API 是确定性的、无状态的,且调用结果可以无损地插入文本流。对于需要多步交互、状态依赖的 API(如订单查询后再查物流),Toolformer 很难处理,因为它没有显式的规划循环。其次,自监督数据生成阶段需要执行大量 API 调用,计算开销很大,且 API 必须可访问。最后,当 API 文档更新时,Toolformer 需要重新进行数据生成和微调,无法像 ReAct 那样通过修改提示词快速适应。

复杂 API 场景下的工具选择与执行验证

在真实的企业环境中,API 往往比论文中的示例复杂得多。以客服查询场景为例,我们可能面对数十个 API,每个 API 有多个参数,参数之间有依赖关系,且返回格式可能随版本变化。Gorilla 的工作专门针对这一问题:它微调 LLaMA 模型,并配合文档检索器,使模型能根据自然语言查询从大规模 API 集合中选出正确的 API 并生成准确的调用。

Gorilla 的核心洞察是,LLM 直接生成 API 调用时容易产生幻觉,例如编造不存在的函数名或参数。通过引入检索增强,Gorilla 在生成 API 调用前先从 API 文档库中检索最相关的文档片段,将其作为上下文提供给模型。这显著提高了调用的准确性,并且使模型能适应文档的实时更新——只要更新文档库,模型无需重新训练就能使用新版本的 API。

在工程实现中,一个鲁棒的工具选择与执行验证流水线通常包含以下组件:

  • API 文档索引:将所有 API 的文档(函数签名、参数说明、返回格式、示例)进行分块并建立向量索引,支持语义检索。
  • 规划器:根据用户意图和检索到的 API 文档,生成动作序列。可以是 ReAct 式的动态规划,也可以是 Toolformer 式的隐式决策。
  • 执行引擎:实际调用 API,处理认证、重试、超时等网络层问题。
  • 验证器:检查 API 返回结果是否符合预期模式(如状态码、必要字段是否存在),并在异常时触发重规划。

验证器是防止错误传播的关键。例如,当物流 API 返回 {"status": "error", "code": 503} 时,验证器可以捕获这一异常,将错误信息反馈给规划器,规划器可以决定重试、换用备用 API 或向用户询问更多信息。这种“执行-验证-重规划”的循环是生产环境中不可或缺的机制。

两种策略的工程权衡

下表从多个工程维度对比了 ReAct 和 Toolformer 在工具规划上的差异:

维度ReActToolformer
规划方式推理时显式推理-行动循环训练时隐式学习插入 API 调用
对提示词的依赖高,需精心设计格式和示例低,模型自主决定调用时机
适应 API 变化修改提示词或文档描述即可需重新生成数据并微调
多步交互能力强,原生支持基于观察的规划弱,难以处理状态依赖的 API 序列
推理延迟高,每步都要调用模型低,API 调用在生成过程中一次性插入
训练成本无,纯推理方案高,需自监督数据生成和微调
可解释性高,推理轨迹可读低,决策内化在参数中
适用场景交互式任务、需要动态调整计划简单工具调用、知识增强生成

在实际选型时,如果任务需要多步交互且 API 行为不确定性强,ReAct 或其变体更合适;如果工具调用模式相对固定、追求低延迟且训练资源充足,Toolformer 的思路可以纳入考虑。许多生产系统会结合两者:用 Toolformer 式微调让模型掌握基本工具使用能力,再在推理时引入轻量级规划循环处理复杂情况。

贯穿场景:客服查询的规划流程

回到开头的客服查询场景,一个基于 ReAct 的智能体可能会这样运行:

flowchart TD
    A[用户输入查询] --> B[模型推理: 需要先查订单]
    B --> C[调用订单查询 API]
    C --> D{订单状态}
    D -- 不存在 --> E[推理: 订单号可能错误]
    E --> F[向用户确认订单号]
    D -- 存在 --> G[调用物流 API]
    G --> H{物流状态}
    H -- 已签收 --> I[推理: 查询同类促销]
    I --> J[调用促销查询 API]
    J --> K[生成最终回答]
    H -- 运输中 --> L[推理: 无需查促销]
    L --> K
    H -- 异常 --> M[推理: 物流信息异常]
    M --> N[反馈错误给用户]

在这个流程中,模型在每一步都会输出推理文本,例如“订单 ORD-8823 存在,状态为已发货,下一步需要查询物流”。执行引擎调用 API 后,验证器检查返回的 JSON 是否包含 tracking_number 字段。如果物流 API 返回错误,验证器将错误信息格式化后注入上下文,模型在下一轮推理中会看到“物流查询失败:服务不可用”,并决定重试或告知用户。

如果采用 Toolformer 的思路,模型可能在生成回答的过程中直接插入 <API>order_lookup(ORD-8823)</API><API>logistics_track(...)</API>,但很难表达“如果已签收则查促销”的条件逻辑。因此,对于这种有分支决策的场景,ReAct 的显式推理循环更为自然。

常见失败模式与缓解措施

在部署工具增强智能体时,有几个反复出现的失败模式需要特别关注:

幻觉调用:模型生成了不存在的 API 名称或参数。Gorilla 通过检索增强来缓解,但检索也可能失败。工程上可以维护一个 API 注册表,对模型生成的调用进行静态校验,拒绝不在注册表中的函数名。

循环与停滞:ReAct 智能体可能陷入重复调用同一 API 的循环,或者过早输出 Final Answer。可以通过设置最大步数、监控行动重复率,并在检测到循环时注入强制重置信号来缓解。

上下文溢出:随着推理-行动-观察序列增长,上下文窗口可能被撑爆。需要设计上下文压缩策略,例如对较早的观察进行摘要,或者只保留最近 N 轮交互。

工具选择错误:当多个 API 功能相似时(例如有两个不同的物流查询 API),模型可能选错。可以通过在 API 文档中强调适用条件,并在验证阶段检查返回数据是否与预期模式匹配来降低风险。如果返回的字段集合与所选 API 的文档定义不一致,可以标记为可疑并触发重选。

分布偏移:Toolformer 在训练时见过的 API 返回模式可能与生产环境不同。例如,训练时日历 API 总是返回成功,但生产环境中可能因权限问题返回错误。这会导致模型在遇到错误时行为不可预测。定期用生产数据更新训练集并重新微调是必要的,但成本较高。

仍未解决的问题

尽管 ReAct 和 Toolformer 分别从推理和训练角度推进了工具规划,但几个关键问题仍然开放:

  • 自动 API 理解:目前仍需人工编写 API 描述或示例,模型无法直接从原始 API 文档(如 OpenAPI 规范)中自动构建可靠的工具表示。Gorilla 的检索增强是重要一步,但检索质量直接影响调用准确性。
  • 代价敏感的规划:真实 API 调用有金钱和时间成本。模型应该学会权衡调用收益与成本,例如避免在免费额度用完后继续调用付费 API。当前方法几乎不考虑这一维度。
  • 工具组合爆炸:当可用工具数量达到数百个时,如何高效检索和选择工具,以及如何组合多个工具完成复杂工作流,仍是挑战。
  • 安全与权限:如何确保智能体不会因为恶意提示或自身错误而执行危险操作(如删除数据、发送邮件)?工具执行需要细粒度的权限控制和人工确认机制,但这会增加交互延迟。

这些问题的解决可能需要融合推理时的动态规划、训练时的工具建模,以及更强大的 API 文档理解能力。工程上,一个务实的路线是先从受限工具集和明确边界开始,逐步扩展,并在每一层都加入验证和回退机制。

资料来源

  1. ReAct: Synergizing Reasoning and Acting in Language Models
  2. Toolformer: Language Models Can Teach Themselves to Use Tools
  3. Gorilla: Large Language Model Connected with Massive APIs