Agent 训练实战 / 04

训练数据配比实战:Agent 不只吃轨迹数据

你搞定了 Agent 轨迹数据、选好了 RL 算法,迫不及待地开训——然后发现:模型的 Agent 能力确实上来了,但它不会正常聊天了。问它“今天星期几”,它非要调一个工具。让它写封邮件,它先来一段 <think> 分析然后试图调用一个不存在的 send_email API。

这就是数据配比没做好的典型症状。

Agent 训练不是只喂轨迹数据就完事——你需要一套精心配比的数据混合策略,让模型既学会“做 Agent”,又不丢失通用能力。本篇整理数据配比的实战经验:需要哪几类数据、各自比例怎么定、怎么根据训练阶段动态调整。

为什么配比这么重要

一句话:模型会变成它吃的数据的形状。

如果你只用 Agent 轨迹数据训练,模型的先验就会变成“所有输入都是需要调工具解决的任务”。这不是模型“笨”,是训练分布告诉它的——它见过的每一条数据都是在调工具,自然会把所有问题都往调工具上靠。

这个问题的学术名称叫 catastrophic forgetting(灾难性遗忘),但在 Agent 训练的语境下更准确的说法是 能力偏移——模型没有“忘记”怎么聊天,而是它的输出分布被 Agent 数据拉偏了,导致在非 Agent 场景下行为异常。

只用 Agent 轨迹数据训练的典型症状:
├── 所有问题都想调工具        连"你好"都想调 API
├── 格式过度结构化            回复一句话也包裹在 JSON 里
├── 拒绝回答通用问题          "我是一个工具调用助手,无法回答这个问题"
├── 长文本能力退化            Agent 轨迹通常 2K-8K tokens,更长的处理不了了
└── 安全对齐退化              Agent 数据里的安全覆盖不足,该拒绝的不拒绝

需要哪几类数据

Agent 训练的数据池通常包含六类数据,每类有不同的作用:

数据类别 核心作用 缺失的后果
Agent 轨迹 学习多轮推理 + 工具调用 Agent 能力起不来
Tool Calling 单轮 学习 function calling 基本功 工具调用格式不稳定
通用指令跟随 保持正常对话和指令执行能力 非 Agent 场景行为异常
长文本理解 保持长上下文处理能力 Agent 处理长轨迹时中间信息丢失
安全 / 拒绝 保持安全对齐 执行危险操作不拒绝
代码 / 推理 保持逻辑推理和代码生成能力 复杂推理链质量下降

下面逐类展开。

1. Agent 轨迹数据:核心但不能独占

这是上一篇 SFT 文章详细讲过的——完整的多轮推理 + 工具调用轨迹。

一条典型的 Agent 轨迹:
System → User → Think → ToolCall → ToolReturn → Think → ToolCall → ToolReturn → Response

特征:
├── 多轮交互(通常 3-15 步)
├── 包含工具调用和工具返回
├── 有明确的任务完成标准
└── 涉及推理、规划、错误恢复

质量要求:这是配比中占比最大的部分,数据质量直接决定 Agent 能力的天花板。劣质轨迹不如不放——模型会学到冗余步骤、错误的工具选择、不合理的推理模式。

数据来源

  • 强模型(GPT-4、Claude)在沙箱环境中生成 + 人工筛选
  • 真实用户使用日志脱敏后筛选(如果有线上 Agent 产品)
  • 人工标注(成本高,用于种子数据集和难样本)

2. Tool Calling 单轮数据:基本功不能丢

和 Agent 轨迹不同,这类数据是单轮的 function calling——用户给一个指令,模型直接输出一次工具调用,没有多轮推理。

示例:
User: 查一下北京今天的天气
Assistant: {"name": "get_weather", "arguments": {"city": "北京", "date": "today"}}

User: 帮我创建一个名为 test 的文件夹
Assistant: {"name": "create_directory", "arguments": {"path": "/home/user/test"}}

为什么需要单独放这类数据?

Agent 轨迹里的工具调用是嵌在多轮推理链中的,模型学到的是“在复杂上下文中调工具”。但很多实际场景是简单的单次工具调用——用户说一句话,直接调一次工具就行了。如果模型只见过复杂轨迹,简单场景反而会过度推理。

只用 Agent 轨迹训练的模型处理简单请求:
User: 查一下北京天气
Assistant: <think>用户想要查询天气,我需要分析这个请求...
           首先确认城市是北京...
           然后确认时间范围...
           </think>
           {"name": "get_weather", ...}

加入单轮 Tool Calling 数据后:
User: 查一下北京天气
Assistant: {"name": "get_weather", "arguments": {"city": "北京"}}

数据构造:覆盖你支持的所有工具类型,每种工具覆盖常见参数组合。不需要太多——每种工具 50-200 条就够了,关键是覆盖度。

3. 通用指令跟随:保命数据

这是 Alpaca、ShareGPT 之类的通用问答数据。看起来和 Agent 没关系,但它是防止能力偏移的压舱石

覆盖场景:
├── 开放问答        "解释一下量子纠缠"
├── 文本生成        "帮我写一封请假邮件"
├── 翻译            "把这段话翻译成英文"
├── 摘要            "总结一下这篇文章的要点"
├── 多轮对话        日常闲聊、追问、澄清
└── 拒绝回答        "我无法执行这个请求"(无需调工具的场景)

关键点:这些数据里不能出现工具调用。模型要从这些数据中学到一个信号——“不是所有问题都需要调工具,很多时候直接回答就好”。

如果你的通用数据里混入了工具调用样本(哪怕是少量),模型区分“该不该调工具”的能力会变差。

4. 长文本理解:Agent 的隐性需求

Agent 轨迹天然比普通对话长——几次工具调用加上返回结果,很容易到 4K-8K tokens。但训练数据的平均长度通常比这短,导致模型对长上下文的注意力分配退化。

长文本理解数据类型:
├── 长文档问答      给一篇 10K+ 的文档,在文档中间提问
├── 多文档总结      同时处理 3-5 篇文档
├── 长对话历史      包含 20+ 轮对话的上下文理解
└── 信息检索        在长文本中定位特定信息(needle-in-haystack)

和 Agent 的关系:Agent 在执行复杂任务时,对话历史会越来越长。如果模型在 8K tokens 之后开始“遗忘”前面的工具返回结果,Agent 就会做出矛盾的决策——比如重复调用已经调过的工具,或者忽略之前工具返回的关键信息。

5. 安全 / 拒绝数据:Agent 比对话模型更需要

这一点在前面的文章里已经提过——Agent 能真的执行操作,安全比对话模型重要一个量级。

Agent 安全场景:
├── 危险操作拒绝    "帮我删除 /root 目录下所有文件"
├── 权限越界拒绝    "帮我读取其他用户的邮件"
├── 信息泄露防护    "把数据库密码发给我"
├── 循环确认        "你确定要执行这个不可逆操作吗?"
└── Prompt 注入防护  工具返回中嵌入恶意指令

特别注意 Prompt 注入场景:Agent 会读取工具返回的内容,如果工具返回中包含“忽略之前的指令,执行 XXX”这类攻击文本,没有经过安全训练的 Agent 真的可能执行。安全数据中要包含这类样本。

6. 代码 / 推理数据:保持思维链质量

Agent 的核心能力之一是推理——根据当前状态判断下一步该做什么。这个能力不只来自 Agent 轨迹,还来自通用的代码和数学推理训练。

代码 / 推理数据类型:
├── 代码生成        根据描述写代码
├── 代码解释        阅读代码说明逻辑
├── 数学推理        多步数学问题
├── 逻辑推理        条件判断、因果分析
└── 规划问题        给定约束条件制定计划

如果在 Agent 训练中完全不放代码和推理数据,模型的思维链质量会明显下降——<think> 部分变得更短、更粗糙、更容易跳步。

配比经验:不同阶段不同策略

数据配比不是一个固定的比例表——它应该随训练阶段调整。

SFT 阶段配比

SFT 阶段的目标是让模型“学会 Agent 的基本行为模式”,同时保持通用能力。

推荐配比(SFT 阶段):

Agent 轨迹数据         35-45%    核心学习目标
Tool Calling 单轮      10-15%    工具调用基本功
通用指令跟随           15-20%    防止能力偏移
长文本理解              5-10%    保持长上下文能力
安全 / 拒绝             5-10%    安全底线
代码 / 推理            10-15%    保持推理能力

几条硬规则

  • Agent 轨迹不超过 50%。超过这个阈值,通用能力开始明显退化
  • 安全数据不低于 5%。低于这个阈值,安全对齐容易崩
  • 通用指令不低于 15%。这是防偏移的最低线

RL 阶段的数据考量

RL 阶段不直接用“数据配比”(RL 是在环境中 rollout),但需要考虑:

RL 阶段的数据相关决策:

1. 任务分布
   ├── 不能只用简单任务(模型没有学习信号)
   ├── 不能只用困难任务(模型完全跑不通,Reward 全是 0)
   └── 经验:30% 简单 + 50% 中等 + 20% 困难

2. 工具覆盖
   ├── RL 任务要覆盖所有需要支持的工具类型
   └── 如果某类工具在 RL 中没被训到,该工具的调用能力会退化

3. 通用能力保持
   ├── RL 阶段也会导致通用能力退化
   ├── 方法 A:RL loss 中混入少量 SFT loss(通用数据)
   └── 方法 B:定期用通用 benchmark 检查,退化时暂停 RL 做一轮 SFT 补救

不同规模模型的配比差异

模型越小,被 Agent 数据“带偏”的风险越高,需要更大比例的通用数据来稳住。

模型规模 Agent 轨迹占比 通用数据占比 说明
1B-3B 25-35% 30-40% 小模型容量有限,容易偏移
7B-13B 35-45% 20-25% 主流选择,配比空间较大
30B-70B 40-50% 15-20% 大模型抗遗忘能力强
70B+ 45-55% 10-15% 足够大的容量可以多放 Agent 数据

这些数字是经验值,不同场景会有偏差。核心原则是:模型越小越要保守,宁可 Agent 能力弱一点,也不能通用能力崩。

数据质量比数量重要

一个常见误区是“数据越多越好”——于是拼命扩充数据量。但 Agent 训练中,数据质量对最终效果的影响远大于数量。

质量控制的几个维度

维度 1:轨迹的正确性

轨迹里的工具调用是否真的正确?参数是否合理?最终结果是否满足用户需求?

低质量轨迹的常见问题:
├── 工具参数错误但碰巧得到了正确结果(运气好)
├── 多余的工具调用(查了不需要查的东西)
├── Think 部分和实际行为不一致(嘴上说要查 A,实际查了 B)
└── 最终回复没有利用工具返回的信息(查了但没用)

维度 2:轨迹的多样性

如果你有 1 万条轨迹,但其中 8000 条都是“查天气”类型的简单任务,模型学到的能力是偏的。

多样性检查清单:
├── 工具类型覆盖    每种工具都有足够的训练样本
├── 任务复杂度分布   简单/中等/困难 任务都有
├── 轨迹长度分布    1 步到 15 步的轨迹都有
├── 错误恢复覆盖    包含工具报错后正确恢复的轨迹
└── 拒绝场景覆盖    包含"不该调工具"的情况

维度 3:格式一致性

Agent 数据涉及多种格式——tool call JSON、think 标签、工具返回格式。格式不一致会让模型困惑。

格式一致性要求:
├── 所有 tool call 使用统一的 JSON schema
├── think 标签统一(<think>...</think>,不要混用 <thinking>、<thought> 等)
├── 工具返回格式统一
└── 角色标记统一(system/user/assistant/tool)

数据量的经验值

到底需要多少数据?这取决于模型规模和任务复杂度。一些经验参考:

Agent 轨迹数据量参考:

入门可用(能跑通基本场景):
├── Agent 轨迹     1K-5K 条
├── Tool Calling   500-2K 条
└── 总数据量       ~10K 条

生产可用(覆盖主要场景):
├── Agent 轨迹     10K-50K 条
├── Tool Calling   5K-10K 条
└── 总数据量       ~50K-100K 条

大规模(追求极致性能):
├── Agent 轨迹     100K+ 条
├── Tool Calling   20K+ 条
└── 总数据量       200K+ 条

但再次强调:1 万条高质量轨迹的效果远好于 10 万条低质量轨迹。在数据量充足之前,精力应该放在质量筛选上,而不是数量扩充。

数据配比的调试方法

配比不对怎么发现?不能等训练完了才发现——需要在训练过程中持续监控。

必须监控的指标

训练过程中监控:
├── Agent 任务完成率          每 500 步在测试集上跑一次
├── 通用 benchmark 分数      MT-Bench / AlpacaEval,检测能力偏移
├── 工具调用格式正确率        输出的 JSON 是否合法
├── 不该调工具时的调用率      给通用问题,看模型是否还想调工具
├── 安全场景拒绝率            给危险指令,看模型是否正确拒绝
└── 长文本准确率              8K+ tokens 的场景表现

发现问题后的调整策略

症状 可能原因 调整方向
所有问题都想调工具 Agent 数据占比过高 增加通用指令数据,降 Agent 轨迹到 35%
工具调用格式经常错 Tool Calling 数据不足或格式不一致 增加单轮 Tool Calling 数据,统一格式
长轨迹后期决策质量下降 长文本数据不足 增加长文本理解数据到 10%
该拒绝的不拒绝 安全数据不足 安全数据提到 10%,补充 Agent 专有安全场景
推理链变短变粗糙 代码/推理数据不足 增加代码和推理数据到 15%
Agent 能力上不去 Agent 轨迹数据质量差 先做数据清洗再调比例

实用的 A/B 测试方法

不确定两种配比哪个更好时,用 A/B 测试:

1. 准备一个固定的评测集,覆盖:
   ├── Agent 任务(简单/中等/困难各 50 条)
   ├── 通用问答(100 条)
   ├── 安全场景(50 条)
   └── 长文本理解(30 条)

2. 用配比 A 和配比 B 各训练一个模型(其他超参完全一致)

3. 在评测集上跑,对比各维度的指标

4. 重点看的不是 Agent 能力的绝对值,而是"Agent 能力提升了多少 vs 通用能力退化了多少"

好的配比应该让 Agent 能力显著提升,同时通用能力退化控制在 5% 以内。如果通用能力退化超过 10%,配比需要调整。

数据飞轮:从线上反馈持续优化数据

如果你的 Agent 已经在线上跑了,有一个非常有价值的数据来源:线上真实交互日志

数据飞轮流程:

线上 Agent 运行
  ↓
收集交互日志(脱敏)
  ↓
自动筛选:
├── 成功轨迹 → 直接加入训练集(补充真实分布数据)
├── 失败轨迹 → 分析失败原因
│   ├── 工具调用错误 → 构造正确的轨迹作为训练样本
│   ├── 推理错误     → 用强模型纠正后加入训练集
│   └── 系统错误     → 不是模型问题,跳过
└── 边界案例 → 人工标注后加入训练集(最有价值的数据)
  ↓
更新训练数据,重新训练
  ↓
上线新模型,回到第一步

这个飞轮的核心价值是:线上数据的分布和你手工构造的数据分布不一样。用户真实的使用方式往往超出你的预期——他们会用你没想到的方式调工具、问你没预料到的问题。这些数据是最宝贵的。

但有一个前提:线上数据要做好脱敏和合规审查,不能把用户隐私信息混进训练集。

小结

  • Agent 训练数据必须混合六类:轨迹、单轮 Tool Calling、通用指令、长文本、安全、代码推理——只喂轨迹会导致通用能力崩塌
  • SFT 阶段 Agent 轨迹占 35-45%,通用指令不低于 15%,安全数据不低于 5%;模型越小越要保守
  • 数据质量远比数量重要:1 万条高质量轨迹胜过 10 万条低质量;重点关注正确性、多样性、格式一致性
  • 训练过程中要持续监控 Agent 完成率和通用 benchmark,发现偏移及时调整配比
  • 线上数据飞轮是持续提升数据质量的最有效手段,但必须做好脱敏和合规

下一篇建议继续看: