芥末
发布于 2026-05-13 / 0 阅读
0
0

Deep Research Agent 的 FC-SFT 冷启动:从 71% 到 94% 的工具调用准确率如何做出来

Function Calling(函数调用,工程里也常叫工具调用)让大模型不只生成自然语言,还能按约定格式调用搜索、浏览器、数据库、Python 代码执行器等外部工具。对于 Deep Research Agent 来说,工具调用能力直接决定系统能不能完成复杂研究任务。

通用模型已经具备基础工具调用能力,比如 GPT-4o、DeepSeek V3、Qwen3 都能根据工具描述生成调用参数。但“能跑通 Demo”和“能稳定跑生产任务”不是一回事。一个金融研究类 Agent 可能需要先搜索企业公告,再打开网页读取财报,再用 Python 计算债务期限结构,最后综合多份资料给出风险判断。这里任何一步工具选错、参数写错、顺序错了,都会让后续推理偏离事实。

一个典型现象是:基座模型不做专项微调时,工具调用准确率可能停在 65%~75%。以 Qwen3-30B-A3B 为例,在某个 Deep Research Agent 任务集上,直接使用原生工具调用能力得到 71% 准确率;经过 FC-SFT(Function Calling SFT,面向工具调用的监督微调)后,在同一测试集和判分口径下达到 94%。

这个提升不是靠“把学习率调一调”碰出来的,核心在数据工程:构造什么问题、让 Teacher 模型生成什么轨迹、过滤掉哪些样本、评估集怎么设计、如何防止模型只会调用工具而忘记普通问答。

工具调用到底错在哪里

工具调用不是一个单点能力,而是一条链路。模型需要判断是否需要工具、选择哪个工具、生成合法参数、根据工具返回继续推理,并在合适的时候停止调用。

sequenceDiagram
    participant U as 用户
    participant M as Agent 模型
    participant T as 工具执行器
    participant D as 外部数据源

    U->>M: 提出复杂研究问题
    M->>M: 判断是否需要工具
    M->>T: 生成工具调用 name + arguments
    T->>D: 查询 / 访问 / 计算
    D-->>T: 返回结果
    T-->>M: Observation
    M->>M: 基于返回结果继续推理
    M-->>U: 生成最终答案

常见错误可以拆成四类:

错误类型例子后果
工具选择错误应该用网页访问工具,却只调用搜索工具得到的是摘要片段,缺少原始证据
参数格式错误company_name 写成 company,或时间字段格式不符合约定工具执行失败,Agent 被迫猜答案
调用顺序错误还没拿到财报数据,就先让 Python 计算同比增长计算基于空数据或错误数据
过度调用工具“2 + 2 等于多少”也调用 Python说明模型被训练成“有问题就调工具”

FC-SFT 要解决的不是让模型“知道有工具”,而是让模型学会在领域任务里稳定走完整链路。

FC-SFT 冷启动的整体链路

SFT(Supervised Fine-Tuning,监督微调)需要有标注样本。对于工具调用任务,样本不是简单的“问题—答案”,而是“问题—推理—工具调用—工具返回—继续推理—最终答案”的完整轨迹。

冷启动阶段没有大量线上成功案例可用,所以需要从少量高质量种子问题出发,用 Teacher 模型生成轨迹,再经过质量门槛筛选,形成可训练数据。

flowchart LR
    A[种子问题<br/>约 200 条] --> B[问题扩充<br/>约 1200 条]
    B --> C[Teacher 模型生成轨迹]
    C --> D[格式验证]
    D --> E[逻辑验证]
    E --> F[人工抽检]
    F --> G[高质量轨迹<br/>约 840 条]
    G --> H[混入通用指令数据]
    H --> I[FC-SFT 训练]
    I --> J[三层测试集评估]

这条链路里,每一步都在控制一个风险:

环节控制目标如果做不好
种子问题覆盖真实任务分布模型只会处理人工想象出来的问题
问题扩充增加表达和参数变化模型对措辞和实体变化不稳
Teacher 轨迹提供可模仿的工具调用路径模型只学到最终答案,学不到过程
质量过滤去掉格式错、逻辑错、绕远路样本模型把坏习惯也学进去
数据配比防止工具类型偏置和能力遗忘模型过度调用某类工具,普通问答退化
评估闭环确认提升真实存在指标看起来变好,实际不可用

种子数据:少量高质量问题比盲目堆量重要

工具调用 SFT 的起点是种子问题。一个可操作的规模是 200 条左右,来源通常分两类。

真实日志

如果系统已经有早期用户或内部测试用户,线上日志是最有价值的种子来源。日志里的问题更接近真实分布,包含很多人工设计样本不容易覆盖的表达方式。

例如金融研究场景里,用户不会只问“查某公司的营收”,更可能提出这种组合型任务:

分析某大型企业未来三年的债务到期分布和再融资风险。

这个问题隐含了多步操作:查债务结构、定位到期时间、获取融资渠道信息、对比现金流和行业环境,最后才能形成风险判断。

专家编写

真实日志有一个问题:高频问题多,低频但关键的复杂场景少。专家编写可以补齐这些缺口,比如:

  • 多跳推理任务;
  • 需要实时信息的任务;
  • 需要多个来源交叉验证的任务;
  • 工具返回异常时的处理任务;
  • 不应该调用工具的简单问题。

在一个比较稳妥的冷启动方案里,专家编写样本可以占 30%~40%,用来补齐日志天然覆盖不到的区域。

从 200 条扩到 1200 条:扩充的是分布,不是简单复制

200 条问题不足以支撑训练,需要扩充到约 1200 条。扩充不能只是同义句堆叠,而是要让模型看到表达、参数和任务组合的变化。

扩充策略做法例子训练价值
问题改写保持任务不变,改变表达方式“查 XX 企业营收” → “能帮我看一下 XX 企业 2024 年营业收入吗”提升对自然语言表达差异的鲁棒性
参数变化替换时间、公司、行业、数值等变量“2024 年” → “2023 年”,“A 公司” → “B 公司”覆盖更多实体和时间组合
组合扩展把单一任务组合成多步任务“查 A 公司营收” + “对比 B 公司”训练多工具协同和调用顺序

组合扩展尤其重要,因为 Deep Research Agent 的难点通常不在单次工具调用,而在多步依赖关系。搜索得到的信息可能决定下一步访问哪个网页,网页内容又决定是否需要 Python 计算。

Teacher 模型生成轨迹:让学生模型学过程,而不只学答案

扩充后的问题还不能直接用于 FC-SFT,需要 Teacher 模型生成完整轨迹。Teacher 可以选择工具调用能力较强、成本可控的大模型,例如 DeepSeek V3。

轨迹格式要稳定,不能让模型自由发挥。一个常见格式如下:

<think>
分析用户任务,判断需要哪些信息,决定调用哪个工具。
</think>

<tool_call>
{
  "name": "search",
  "arguments": {
    "query": "某企业 2024 年 年报 营业收入",
    "max_results": 5
  }
}
</tool_call>

<observation>
工具返回的搜索结果或页面内容。
</observation>

<think>
根据工具返回结果判断是否需要继续访问网页、计算或交叉验证。
</think>

<tool_call>
{
  "name": "python",
  "arguments": {
    "code": "revenue_2024 = 123.4\nrevenue_2023 = 110.2\ngrowth = (revenue_2024 - revenue_2023) / revenue_2023\nprint(growth)"
  }
}
</tool_call>

<observation>
0.1197
</observation>

<final_answer>
综合工具结果形成最终回答。
</final_answer>

这个格式有三个关键设计。

<think> 让推理过程显式出现。训练目标不是死记“某类问题调用某个工具”,而是让模型学会判断:为什么要调用工具、当前信息是否足够、下一步该做什么。

<tool_call> 使用 JSON(JavaScript Object Notation,一种结构化数据格式)。结构化格式方便自动校验,工具名、参数名、字段类型都可以被程序检查。

<observation><think> 交替出现。这样模型学到的是“看结果再决定下一步”,而不是一次性生成一串不看反馈的调用。

质量验证:Teacher 生成的数据不能直接全收

Teacher 模型生成的轨迹并不天然正确。冷启动中,1200 条问题可能只留下约 840 条高质量轨迹,过滤比例达到 30% 并不罕见。

质量门槛可以分成三层。

验证层级检查项处理方式
格式验证JSON 能否解析、工具名是否存在、必填参数是否齐全、字段类型是否正确自动过滤
逻辑验证轨迹步数是否异常、是否重复调用同一工具、最终答案是否有工具结果支撑自动过滤或打标复查
人工抽检推理路径是否合理、是否绕远路、是否使用了不可靠证据抽样检查,反推数据构造规则

格式验证只能保证“能执行”,不能保证“做得对”。例如 Teacher 可能连续搜索同一个关键词三次,格式完全合法,但这种轨迹会让学生模型学到低效行为。

轨迹步数也需要约束。对于 Deep Research 任务,少于 2 步可能说明没有真正使用工具,多于 15 步可能说明模型陷入循环或检索策略失控。阈值不需要固定照搬,但必须结合任务复杂度设定上限和下限。

数据分布:模型会学会样本里的偏见

高质量不只指单条样本正确,还包括整体分布合理。如果 840 条轨迹里 70% 都是搜索工具,只有 10% 涉及 Python 计算,模型就会偏向搜索;即使面对明确需要计算的问题,也可能先去搜索。

工具调用数据至少要检查这些分布:

分布维度需要观察什么
工具类型分布search、browser、python、database 等工具比例是否符合线上任务
调用步数分布单步、两三步、多步复杂任务比例是否合理
参数类型分布时间、实体、行业、数值、布尔开关等字段是否覆盖充分
是否调用工具需要工具与不需要工具的问题是否都有
成功与异常路径工具返回空结果、错误结果、冲突结果时是否有样本

分布问题最好在种子构造阶段解决,而不是训练后靠调参补救。训练数据缺少某类行为时,模型很难凭空学出来。

防遗忘:不能让模型变成“工具调用机器”

专项 SFT 有一个常见副作用:模型在目标任务上变强,但通用能力下降。工具调用微调尤其容易出现这种问题,因为所有训练样本都在暗示模型“遇到问题就调用工具”。

解决办法是在训练集中混入一定比例的通用指令数据。例如在一个实验配置中,混入 30% 通用指令样本可以控制普通问答退化。这个比例不是理论公式推出来的,而是实验调出来的工程参数。

pie title FC-SFT 训练数据配比示例
    "工具调用轨迹数据" : 70
    "通用指令数据" : 30

通用指令数据的作用不是提升工具调用准确率,而是保住模型原有能力。没有这部分数据,模型可能对“2 + 2 等于多少”这类问题也调用 Python,表面上工具调用很积极,实际是过拟合。

评估:71% 到 94% 必须有固定口径

工具调用准确率不是一句话就能说清的指标。要让“71% 到 94%”可信,至少要固定四件事:

  1. 同一个基座模型;
  2. 同一套工具定义;
  3. 同一个测试集或严格隔离的同分布测试集;
  4. 同一套判分规则。

一个简单口径可以这样定义:

工具调用准确率 = 工具调用正确的样本数 / 参与评估的样本总数

但多步任务里还要说清“正确”的含义。常见判分方式有两种:

判分方式规则特点
Step-level每一次工具调用单独判分能定位具体错误类型
Trajectory-level整条轨迹的工具选择、参数、顺序都正确才算对更严格,更接近真实任务成功率

生产系统更关心 Trajectory-level,因为用户不会因为其中某一步对了就得到正确答案。训练调试阶段则需要 Step-level,方便定位是工具选错、参数错,还是顺序错。

三层测试集:既测基础,也测泛化和过拟合

评估集不能和训练集重叠。更关键的是,测试场景要覆盖训练中少见甚至没见过的分布。

测试层级规模示例目标
标准测试集100 条从种子数据中预留,不参与训练,用来验证基础能力
分布外测试50 条覆盖 4 个以上工具协同、工具返回异常等低频复杂场景
对抗测试30 条构造“不该调用工具”的问题,检查是否过度工具化

除了总体准确率,还要拆解指标:

指标说明
工具选择准确率是否选到了正确工具
参数格式准确率工具选对后,参数字段和值是否符合 schema
调用顺序准确率多工具任务中,依赖顺序是否合理
最终答案支撑率答案是否由工具返回结果支撑,而不是凭空生成
遗忘率普通问答、知识理解等非工具任务是否退化

在一个完整迭代中,冷启动阶段可以先得到约 840 条高质量轨迹;后续继续通过日志、失败样本回流、人工修正扩到 5000 条级别。以 FC-SFT 5000 样本配置为例,工具调用准确率从 71% 提升到 94%,同时 MMLU(Massive Multitask Language Understanding,大规模多任务语言理解评测)下降 0.3%,处在误差范围内,说明专项微调没有明显破坏通用能力。

Claude Code 的 ExtractionCoordinator:选择性积累比无差别堆积更重要

Claude Code 里的 ExtractionCoordinator 可以作为一个类比。Deep Research Agent 的 FC-SFT 是通过筛选训练轨迹,让模型逐渐学会稳定调用工具;ExtractionCoordinator 则是在对话过程中提取可持久化记忆,让系统逐渐了解一个项目。

两者解决的问题结构相似:系统一开始缺少领域知识,需要通过使用过程积累信息,但不能把所有信息都塞进去。

class ExtractionCoordinator:
    MIN_NEW_MESSAGES = 4

    async def maybe_extract(self, session):
        new_messages = session.messages_since_last_extraction

        if len(new_messages) < self.MIN_NEW_MESSAGES:
            return

        if self.is_running:
            self.dirty = True
            return

        await self.run_extraction(session)

    async def run_extraction(self, session):
        self.is_running = True
        try:
            memories = await self.model.extract_memories(
                session.recent_messages
            )
            if memories:
                await self.memory_writer.update(memories)
        finally:
            self.is_running = False

            if self.dirty:
                self.dirty = False
                await self.run_extraction(session)

MIN_NEW_MESSAGES = 4 是一个门槛:不是每条消息都触发记忆提取,而是积累到一定数量后再异步处理。这样可以减少无意义提取,也避免对主流程造成阻塞。

这个机制和 FC-SFT 的质量过滤有相同的工程原则:

系统积累对象门槛目标
Deep Research Agent FC-SFT工具调用轨迹格式验证、逻辑验证、人工抽检、分布控制让模型稳定学会工具调用
Claude Code ExtractionCoordinator项目记忆至少 4 条新消息、模型判断是否值得写入让系统逐渐理解项目上下文

有门槛的选择性积累,比无差别堆数据更可靠。训练数据如此,长期记忆也是如此。

把 FC-SFT 工程链路讲清楚的口径

如果要解释一个“工具调用准确率从 71% 到 94%”的指标,最好按问题、流程、评估三个层次讲。

问题口径

通用模型原生支持工具调用,但在复杂多工具协同任务中,准确率通常只能达到刚刚可用的水平。FC-SFT 的目标是在不更换基座模型的前提下,用领域内高质量轨迹数据提升工具选择、参数生成和调用顺序的稳定性。

流程口径

数据工程可以拆成六步:

flowchart TD
    A[收集种子问题<br/>日志 + 专家编写] --> B[扩充问题<br/>改写 + 参数变化 + 组合扩展]
    B --> C[Teacher 生成 Thought-Action-Observation 轨迹]
    C --> D[自动过滤格式错误和逻辑错误]
    D --> E[人工抽检推理质量]
    E --> F[混入通用指令数据防遗忘]
    F --> G[执行 FC-SFT]

关键数字可以这样描述:

环节示例规模
种子问题约 200 条
扩充后问题约 1200 条
过滤后高质量轨迹约 840 条
后续迭代训练样本约 5000 条
通用指令混合比例约 30%

评估口径

评估不能只报一个总准确率,要说明测试集隔离、测试层级和拆解指标。一个可信评估至少包括:

  • 标准测试集:验证基础工具调用能力;
  • 分布外测试:验证复杂任务泛化;
  • 对抗测试:验证是否过度调用工具;
  • 参数格式、调用顺序、最终答案支撑率;
  • 普通问答退化情况,例如 MMLU 变化。

这样讲出来的 94% 才不是孤立数字,而是一个完整实验闭环的结果。

容易踩的坑

只扩数量,不控质量

5000 条粗糙轨迹不一定比 840 条高质量轨迹更好。如果大量样本存在重复搜索、无依据回答、参数错误,模型会把这些模式也学进去。

只测工具调用,不测最终答案

工具调用正确不等于最终答案正确。Agent 可能调用了正确工具,却错误解读了工具返回结果。评估时要检查最终答案是否能被 Observation 支撑。

测试集和训练集泄漏

如果测试问题由训练问题简单改写而来,指标会虚高。标准测试集需要预留,分布外测试和对抗测试要单独构造。

忽略“不调用工具”的样本

工具调用微调不能只训练调用工具。否则模型会把“回答问题”误学成“必须调用工具”。简单算术、常识问答、开放闲聊都需要作为负例或通用指令混入。

不记录失败样本

FC-SFT 不是一次性工程。线上失败样本最能暴露真实缺口:工具描述不清、参数 schema 设计不合理、某类任务缺少训练样本、模型容易在某一步循环。失败样本经过清洗和修正后,可以进入下一轮训练数据。

关键结论

Deep Research Agent 的工具调用能力要从“偶尔会做”变成“稳定会做”,核心不在调参,而在数据闭环。

一条可复现的 FC-SFT 冷启动链路包括:用真实日志和专家样本构造种子问题,通过改写、参数变化和组合扩展扩大覆盖面;让 Teacher 模型生成 Thought-Action-Observation 轨迹;用格式验证、逻辑验证和人工抽检过滤低质量样本;控制工具分布,并混入通用指令数据防止遗忘;用标准测试、分布外测试和对抗测试验证真实收益。

“71% 到 94%”这类指标只有放在固定模型、固定工具、固定测试集、固定判分规则下才有意义。数字本身不难写,难的是把背后的数据构造、训练配比、质量门槛和评估闭环讲清楚。


评论