章节导航 第 18 章 / 共 20 章
多轮对话与Agent数据
多轮数据结构(messages/loss只算assistant/上下文一致性)、三大来源(真实日志/人工对话/模型多轮自玩)、UltraChat合成(双GPT-4角色/5轮截断)、Tool-Use Trajectory(tool_calls结构化JSON/tool role/mock执行/多步嵌套)、ReAct合成范式(Thought/Action/Observation循环/xLAM/Glaive)、技能使用数据维度(SKT 2000 skills→4000 tasks→27164验证轨迹/SkillEval/验证是增益来源)、闭环自优化(ASTRA tool-call graph拓扑采样/可验证环境合成/SFT+4分vs轨迹级RL+13.6分增益不对称)、Agent数据六大难点(工具幻觉/参数错误/失败恢复/长trajectory/工具偏好/意图波动IACM-RL 13场景+五维指标+BeliefState stale flags)、JSON Schema静态校验、System Prompt数据(5类型配比)、多轮一致性评估(MT-Bench/MINT/τ-Bench/BFCL)
单轮 SFT 教模型说话,多轮 SFT 教模型对话。
Agent 数据是后训练的”深水区”——工具幻觉、参数错误、失败恢复,每一个都能毁掉上线。
18.1 多轮数据结构
18.1.1 messages 结构
多轮对话的标准结构:
{
"messages": [
{"role": "system", "content": "你是一个有用的助手。"},
{"role": "user", "content": "今天天气怎么样?"},
{"role": "assistant", "content": "我需要查询天气数据。请问你在哪个城市?"},
{"role": "user", "content": "北京"},
{"role": "assistant", "content": "北京今天晴,最高温度 25°C。"},
{"role": "user", "content": "明天呢?"},
{"role": "assistant", "content": "明天多云,最高温度 23°C。"}
]
}
18.1.2 loss 只算 assistant
多轮训练的关键:loss 只在 assistant 部分计算。
def compute_multi_turn_loss(input_ids, messages, template):
losses = []
for i, msg in enumerate(messages):
if msg['role'] != 'assistant':
continue # user/system 不算 loss
# 找到该 assistant 响应的 token 范围
start, end = find_assistant_region(i, input_ids, template)
# 只对这部分计算 loss
loss = cross_entropy(model(input_ids[start:end]), input_ids[start+1:end+1])
losses.append(loss)
return sum(losses) / len(losses)
18.1.3 上下文一致性
多轮数据的”上下文一致性”是质量核心——每轮对话必须与前面轮次逻辑一致。
典型不一致:
- 用户第 2 轮问”明天呢”,assistant 回答”今天是晴天”——上下文丢失
- assistant 第 1 轮说”我在北京”,第 3 轮说”我在上海”——自相矛盾
- 用户在第 5 轮称呼变了,assistant 没跟上——指代不一致
检测:
def check_consistency(messages):
# 用 LLM 检查上下文一致性
prompt = f"""
检查以下多轮对话的上下文一致性。是否存在:
1. 自相矛盾
2. 上下文丢失
3. 指代不一致
对话:{format_messages(messages)}
输出:{{"consistent": true/false, "issues": [...]}}
"""
return llm.generate(prompt)
18.2 多轮数据三大来源
18.2.1 来源对比
| 来源 | 真实度 | 规模 | 多样性 | 成本 |
|---|---|---|---|---|
| 真实日志 | 极高 | 10万-1亿 | 中 | 0 |
| 人工对话 | 高 | 1万-10万 | 高 | 5-50 美元/条 |
| 模型多轮自玩 | 中 | 10万-1000万 | 高 | 0.001-0.1 美元/条 |
18.2.2 真实日志
从生产环境拉取的多轮对话,最真实但有隐私与采样偏差问题。
处理流程:
1. 隐私脱敏(Presidio + 规则)
2. 用户去重(每用户最多 N 轮)
3. 质量过滤(RM 评分 > 0.5)
4. 长度过滤(≥ 3 轮)
5. 多样性采样(任务聚类)
18.2.3 人工对话
人工编写的多轮对话,质量最高但成本高。
典型流程:
- 标注员扮演用户,给 prompt
- 另一个标注员扮演 assistant,给响应
- 双盲审核,确保上下文一致
18.2.4 模型多轮自玩
让两个 LLM 模型互相扮演 user/assistant,自动生成多轮对话。代表:UltraChat。
18.3 UltraChat 合成
18.3.1 UltraChat 算法
UltraChat(Ding et al., 2023)用两个 GPT-4 模型多轮自玩:
def ultrachat_generate(user_model, assistant_model, n_conversations=50000):
conversations = []
for _ in range(n_conversations):
# 1. 随机选一个种子话题
topic = sample_topic()
# 2. 多轮对话
messages = [{"role": "system", "content": "You are a helpful assistant."}]
for turn in range(5): # 最多 5 轮
# user 模型生成问题
user_msg = user_model.generate(messages, temperature=0.7)
if is_ending(user_msg): # 检测到结束意图
break
messages.append({"role": "user", "content": user_msg})
# assistant 模型生成回答
assistant_msg = assistant_model.generate(messages, temperature=0.7)
messages.append({"role": "assistant", "content": assistant_msg})
conversations.append(messages)
return conversations
18.3.2 关键设计
- 5 轮截断:超过 5 轮话题容易发散,质量下降
- 双 GPT-4:用同一个模型会导致”同质化”,用两个独立实例更好
- 种子话题:从 30 个大类(科学、技术、艺术…)× 200 个小类采样
- 结束检测:user 模型可以输出
<|end|>主动结束
18.3.3 UltraChat 的局限
- 话题偏向”GPT-4 喜欢的”:哲学、文学多,实用任务少
- 多轮逻辑深度有限:第 3 轮后经常”为了聊天而聊天”
- 缺乏指令遵循:用户更像在”请教”而非”指令”
18.4 Tool-Use Trajectory
18.4.1 tool_calls 结构化 JSON
工业级 Tool-Use 数据用结构化 JSON 表示工具调用:
{
"messages": [
{"role": "user", "content": "北京明天天气"},
{"role": "assistant", "content": null, "tool_calls": [
{
"id": "call_001",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\", \"date\": \"tomorrow\"}"
}
}
]},
{"role": "tool", "name": "get_weather", "content": "{\"temp\": 23, \"weather\": \"cloudy\"}"},
{"role": "assistant", "content": "北京明天多云,最高温度 23°C。"}
]
}
18.4.2 tool role 的特殊性
tool 角色的 content 是工具返回的 JSON,不是自然语言。在 chat-template 中需要特殊处理:
# Llama-3 的 tool role 处理
def format_tool_message(msg):
return f"<|start_header_id|>tool({msg['name']})<|end_header_id|>\n{msg['content']}<|eot_id|>"
18.4.3 mock 执行
合成 Tool-Use 数据时,工具不真实执行——用 mock 返回:
def generate_tool_trajectory(prompt, available_tools):
messages = [{"role": "user", "content": prompt}]
for step in range(5): # 最多 5 步
# 1. 模型决定调用哪个工具
assistant_msg = model.generate(messages, tools=available_tools)
messages.append(assistant_msg)
if not assistant_msg.get('tool_calls'):
# 模型不再调用工具,结束
break
# 2. mock 执行每个工具调用
for call in assistant_msg['tool_calls']:
mock_result = mock_tool(call['function']['name'],
json.loads(call['function']['arguments']))
messages.append({
"role": "tool",
"name": call['function']['name'],
"content": json.dumps(mock_result)
})
# 3. 最终回答
final_msg = model.generate(messages)
messages.append(final_msg)
return messages
18.4.4 多步嵌套
复杂任务需要多步工具调用:
用户: "对比北京和上海今天的天气"
Step 1: assistant 调 get_weather(city="北京") → tool 返回
Step 2: assistant 调 get_weather(city="上海") → tool 返回
Step 3: assistant 综合两个结果回答
# 多步嵌套示例
{
"messages": [
{"role": "user", "content": "对比北京和上海今天的天气"},
{"role": "assistant", "tool_calls": [
{"id": "call_1", "function": {"name": "get_weather", "arguments": "{\"city\": \"北京\"}"}},
{"id": "call_2", "function": {"name": "get_weather", "arguments": "{\"city\": \"上海\"}"}}
]},
{"role": "tool", "tool_call_id": "call_1", "content": "{\"temp\": 25, \"weather\": \"sunny\"}"},
{"role": "tool", "tool_call_id": "call_2", "content": "{\"temp\": 28, \"weather\": \"cloudy\"}"},
{"role": "assistant", "content": "北京今天晴 25°C,上海多云 28°C。上海比北京高 3°C。"}
]
}
18.5 ReAct 合成范式
18.5.1 ReAct 结构
ReAct(Yao et al., 2022)是 Agent 的经典范式,结构为:
Thought: 用户问北京天气,我需要查询
Action: get_weather(city="北京")
Observation: {"temp": 25, "weather": "sunny"}
Thought: 查到了,可以回答
Action: finish("北京今天晴 25°C")
18.5.2 ReAct 数据合成
def generate_react_trajectory(prompt, tools):
trajectory = []
for step in range(10): # 最多 10 步
# 1. 生成 Thought + Action
react_msg = model.generate(prompt + trajectory, tools=tools)
trajectory.append(react_msg)
# 2. 解析 Action
action = parse_action(react_msg)
if action['name'] == 'finish':
break
# 3. 执行 Action,得到 Observation
observation = execute_tool(action)
trajectory.append(f"Observation: {observation}")
return trajectory
18.5.3 xLAM 与 Glaive
xLAM(Salesforce, 2024):
- 60K Tool-Use 数据
- 覆盖 4000+ 工具
- 支持 ReAct 与 OpenAI Function Calling 两种格式
Glaive:
- 100K Tool-Use 数据
- 单工具调用为主
- 工具集较小(< 100)
工业选择:xLAM 适合复杂 Agent 场景,Glaive 适合简单工具调用。
18.5.4 技能使用:与工具调用不同的第四个数据维度
18.4 与 18.5 讨论的都是工具调用(tool invocation)数据——教模型正确地调用一个 API。但 Agent 数据还有第四个维度,常被混在工具调用里:技能使用(skill use)。
两者的区别在于对象层次:
| 工具调用数据 | 技能使用数据 | |
|---|---|---|
| 教的内容 | 如何正确调用单个 API(参数、格式、时机) | 如何识别、应用并协调多个能力 |
| 知识形态 | 接口契约 | 可复用的程序性知识 |
| 单条数据跨度 | 一次或几次调用 | 跨多步的完整任务 |
| 典型失败 | 工具幻觉、参数错误 | 有技能但不知道该用哪个、不会组合 |
SKT(Skill-Use Training at Scale via Verified Synthetic Data Generation,Zelin Tan 等 14 人)把这个维度做成了一条可规模化的合成管线。它的问题陈述很直接:仅仅提供 skills,并不保证当前模型能有效识别、应用与协调它们——这正是不少团队”接了一堆 skills 但效果没提升”的原因。
管线三步:
- 技能配置选择:挑选合适的单技能与多技能组合
- 任务合成 + 反馈修复:通过 rule-based 与 agent-based verification 合成任务,并用 feedback-guided repair 修复失败样本
- 只保留合格轨迹:仅保留实质性使用了每一个必需技能的成功轨迹
规模(论文披露的完整链路):
2,000 个公开 skills
→ 4,000 个 task packages
→ 27,164 条经过验证的轨迹
→ 另有 SkillEval(基于同一管线 + 不重叠测试池构建的留出可执行基准)
三条可复用的工程结论:
- 验证是增益的来源,不是可选优化。论文的消融显示,增益依赖于高质量监督——去掉验证环节,规模化反而放大噪声。这与第 16 章”质量优先于数量”的结论一致。
- 增益能跨 agent harness 迁移。跨 harness 评估表明效果不限于单一 agent interface,说明学到的是技能使用能力本身,不是对某个框架提示词模板的过拟合。
- 增益随技能覆盖广度增长。scaling 实验显示覆盖的 skills 越多效果越好——这意味着技能使用数据是可以持续投入的方向,不会很快撞到边际收益递减。
与既有数据配比的关系:如果你当前的 Agent 数据全是工具调用格式,建议单独评估”模型有技能但不用”的失败占比。SKT 给出的判据是把”用到每个必需技能”作为轨迹的准入条件——这个思路也可以反向用于质检:统计你的现有轨迹中,实质性使用了多技能的占比是多少。
⚠️ 命名更正:部分转述把 SKT 展开为 “Skill-usage Knowledge Transfer”。论文标题为 SKT: Skill-Use Training at Scale via Verified Synthetic Data Generation,缩写 SKT 对应 Skill-Use Training。引用时请使用后者。
18.5.5 从静态轨迹到闭环自优化:ASTRA
18.4 与 18.5 的合成范式有一个共同前提:轨迹生成完就固定了。合成一次、SFT 一次,此后轨迹不会因为模型的实际表现而更新。ASTRA(Xiaoyu Tian 等 15 人)把这条链路闭上了,它列出的四个痛点正好对应本章前面几节的能力边界:
| 既有做法的边界 | ASTRA 的对应设计 |
|---|---|
| 合成需要人工介入 | 全自动化端到端管线 |
| 环境由 LLM 模拟,不可验证 | 代码可执行、规则可验证的环境 |
| SFT 与 RL 二选一 | SFT 打底 + 在线 RL 的统一训练法 |
| 多轮轨迹被拆成孤立的单步样本(18.4.4 的嵌套问题) | 轨迹级奖励的完整多轮学习 |
两条腿,缺一不可:
- SFT 侧——用工具调用图的静态拓扑合成轨迹:把已部署的 MCP servers 与工具池组织成 tool-call graph,沿图采样出结构上有根的多轮轨迹并自动打分。这一步解决的是结构有效性——图上走出来的调用序列,天然不会出现 18.6.1 的工具幻觉与 18.6.2 的参数不匹配。
- RL 侧——把环境本身也合成出来:关键设计在于 RL 环境同样自动生成,把分解后的问答轨迹转成独立、代码可执行、规则可验证的环境,从而得到确定性的多轮奖励。这一步直接针对既有做法的根病——LLM 模拟的环境给不出可验证的状态转移与奖励,长程多轮 RL 由此不稳定。
实测增益(论文 Table 2,三项 Overall:BFCL-MT / τ²-Bench / ACEBench):
| 阶段 | 14B(基座 Qwen3-14B) | 32B(基座 Qwen3-32B) |
|---|---|---|
| 基座 | 44.50 / 44.55 / 51.67 | 47.88 / 49.70 / 59.79 |
| + 合成轨迹 SFT | 48.50 / 50.45 / 67.71 | 52.13 / 52.30 / 67.71 |
| + 在线 RL(轨迹级奖励) | 58.13 / 57.70 / 68.96 | 64.25 / 63.70 / 71.88 |
这张表最值得记住的不是终点,而是两个阶段贡献的极端不对称:SFT 阶段在 BFCL-MT 上只拿到 +4.00(14B)与 +4.25(32B),RL 阶段却拿到 +13.63 与 +16.38。合成轨迹的价值主要是把策略带到一个足以开始探索的起点,能力增长的大头来自轨迹级 RL。
工程判据:如果你正在为 Agent 场景攒工具调用数据、且预算只够做一件事,上表给出的信号是——别急着把 SFT 数据量堆到某个量级。先用一批评分过得去的合成轨迹把格式与结构对齐(拿到前 4 个点),然后把资源投向”环境可验证 + 轨迹级奖励”。反过来,若你的工具集没有可执行后端、环境不可验证,RL 阶段就无从稳定进行,此时堆 SFT 数据是唯一选择——但要清楚自己走的是效率更低的那条路。
与 18.5.4 SKT 的分工:两者都做”合成 + 验证”,但验证对象不同。SKT 验证的是单条轨迹是否用对了技能(静态过滤,产出更好的 SFT 数据);ASTRA 验证的是环境的状态转移能否复现(可交互的执行后端,让 RL 成为可能)。做 Agent 数据时先判断瓶颈在哪一层,再决定抄哪一条。
⚠️ 引用边界:上表增益均在 Qwen3-14B / Qwen3-32B 基座上测得,跨基座迁移性未经验证。其 tool-call graph 依赖已部署的 MCP servers 与真实工具池;若你的工具集只是人工定义的 schema 而没有可执行后端,第 1 条腿(图拓扑采样)仍可复用,第 2 条腿(可验证环境)需要自行补齐执行层。此外论文 Table 1 与 Table 2 报告的 Qwen3-32B BFCL-MT 基线略有差异(49.63 与 47.88),本表统一采用 Table 2 的口径以保证同表可比。
18.6 Agent 数据六大难点
18.6.1 工具幻觉
模型”想象”出根本不存在的工具。
prompt: "查北京天气"
assistant: {"name": "weather_api_v2", "arguments": "..."} # 这个工具不存在
应对:
- 训练时严格限制在 available_tools 内
- 用 JSON Schema 静态校验工具名
18.6.2 参数错误
模型调用工具时参数错。
prompt: "查北京天气"
assistant: {"name": "get_weather", "arguments": "{\"location\": \"北京\"}"} # 参数名错
应对:
- JSON Schema 校验参数名与类型
- 在训练数据中加入”错误参数→修正”的负样本
18.6.3 失败恢复
工具调用失败时,模型应该重试或换工具。
Step 1: 调 get_weather(city="北京") → 失败
Step 2 (错误): 模型卡住,输出空
Step 2 (正确): 模型换一个工具,或告知用户失败
应对:
- 在训练数据中加入”工具失败→恢复”的 trajectory
- 用 Constitutional 风格生成”失败案例 + 修正”
HardGen 系统化方法:Constitutional 风格适合少量失败案例,但大规模生产需更系统化方案。HardGen(三阶段框架)专门合成”难”样本:
- 基础 trajectory:正常生成工具调用的成功路径
- 错误注入:刻意构造错误的环境响应(error_tool_response=true),模拟真实故障场景
- RL 优化:在 HardGen 合成数据上进行 RL 训练,学习从失败中恢复
效果:Qwen3-4B-Instruct 经 HardGen SFT+RL 后 BFCL Multi-Turn 从 22.13% 提升到 63.13%,超越 Gemini-3-Pro-Preview(60.75%)和 GPT-5.2(28.13%)。这揭示了一个重要叙事:工具调用能力的主要瓶颈不在模型大小,而在训练数据和方法——4B 模型经优质失败恢复训练后可超越未专门优化的顶级闭源模型。
18.6.4 长 trajectory
复杂任务需要 10+ 步工具调用,trajectory 超长(>8K tokens)。
挑战:
- 显存爆炸
- 上下文丢失
- 训练不稳定
应对:
- 用 YaRN 等长度外推技术
- 训练时用梯度累积
- 长 trajectory 数据用 Pack + document mask
18.6.5 工具偏好
模型过度偏好某个工具,不用其他工具。
用户: "今天几号"
assistant: 调用 search_engine("今天日期") # 偏好搜索引擎
正确: 调用 get_current_date() # 应该用专用工具
应对:
- 训练数据中均衡各工具使用频率
- 在 System Prompt 中明确工具选择优先级
18.6.6 意图波动(多轮特有的第六大难点)
前五个难点在单轮场景下同样存在。但有一个失效模式只在多轮中出现,而且不是”上下文不够长”能解释的:用户意图在对话中途变了。
IACM-RL(Dingwei Zhu 等 25 人)把它作为独立问题研究,给出的失效链条值得单独记住:
用户意图在后续轮次中漂移
→ 早期轮次的约束并未被删除,仍然留在上下文里
→ 过时约束稀释模型注意力
→ 灾难性意图偏移 + 无限 API 循环
为什么它不等于 18.6.4 的”上下文丢失”:长 trajectory 的问题是信息超出了窗口,解法是长度外推与压缩;意图波动的问题是信息还在窗口里、但已经过期了,模型却仍然被它支配——压缩与外推都救不了,甚至会把过时约束一起保下来。这是两类不同的失效,需要不同的解法。
现有方法的盲区:论文指出,既有方案(隐式历史扫描、文本压缩)大多假设简单场景下的完美指令——即用户一句话说清楚、中途不改。真实对话不满足这个假设,所以这些方法在意图波动下会失效。
IACM-RL 的三段式方案:
- DynamicIntent 管线:跨 13 种细粒度波动场景合成训练轨迹,并配套五维诊断指标套件用于量化失效
- 基于 BeliefState 的自生成上下文管理器:主动追踪不断漂移的目标,并用结构化的 stale flags 把被覆盖的参数隔离出去
- RL 优化:让模型自主内化上述管理能力
对数据工程的直接含义:
- 合成数据必须包含意图漂移场景。如果你的多轮训练数据全是”一路顺风”的对话(用户第一句说清需求,后面只补充细节),模型在真实对话中遇到意图变更时没有对应的训练信号。DynamicIntent 的 13 种场景分类可以直接作为合成管线的场景清单参考。
- “删除过时信息”比”保留全部信息”更重要。第 2 点的 stale flag 机制给出一个通用设计:与其让模型自己判断哪句还算数,不如在上下文结构上把已失效的参数显式标记出来。
- 需要配套的度量,而不只是配套的指标。五维诊断指标套件的价值在于——它把”意图漂移导致失败”从一种主观感受变成了可定位的具体维度。做多轮 Agent 数据质检时,建议建立类似的分维度失败归因。
⚠️ 引用边界:IACM-RL 的场景设定是复杂工具调用(complex tool invocation)下的长程执行。其 13 种波动场景与五维指标针对该设定设计;若你的 Agent 场景不涉及多步工具调用,场景分类需要重新梳理,但”过时约束仍在上下文中”这一失效机理仍然成立。
18.7 JSON Schema 静态校验
18.7.1 校验流程
from jsonschema import validate
def validate_tool_call(tool_call, tool_definitions):
"""静态校验工具调用是否符合定义"""
errors = []
# 1. 工具存在
tool_name = tool_call['function']['name']
if tool_name not in tool_definitions:
errors.append(f"Unknown tool: {tool_name}")
return errors
# 2. 参数符合 Schema
tool_def = tool_definitions[tool_name]
try:
args = json.loads(tool_call['function']['arguments'])
validate(args, tool_def['parameters'])
except Exception as e:
errors.append(f"Invalid arguments: {e}")
# 3. 必填参数齐全
for required in tool_def['parameters'].get('required', []):
if required not in args:
errors.append(f"Missing required argument: {required}")
return errors
18.7.2 校验在训练流水线中的位置
1. 合成 trajectory
2. JSON Schema 校验每一步工具调用
3. 不合格的 trajectory 整条丢弃
4. 通过的进入训练集
经验:合成 trajectory 的不合格率约 15-25%,必须严格校验。
18.8 System Prompt 数据
18.8.1 System Prompt 的 5 类型
工业级 System Prompt 数据按类型配比:
| 类型 | 占比 | 示例 |
|---|---|---|
| 通用助手 | 30% | “你是一个有用的助手” |
| 角色扮演 | 20% | “你是一个 19 世纪英国侦探” |
| 专家领域 | 20% | “你是 Python 专家” |
| 工具使用 | 20% | “你有以下工具:…” |
| 安全约束 | 10% | “你不能讨论…“ |
18.8.2 System Prompt 数据的构造
def generate_system_prompted_data(system_prompts, base_data):
data = []
for sys_prompt, ratio in system_prompts:
# 按比例采样基础数据
n_samples = int(len(base_data) * ratio)
sampled = random.sample(base_data, n_samples)
for d in sampled:
# 在 messages 前加 system message
d['messages'] = [
{"role": "system", "content": sys_prompt},
*d['messages']
]
data.append(d)
return data
18.8.3 System Prompt 的反例数据
加入”违反 System Prompt”的反例,教模型严格遵守:
{
"messages": [
{"role": "system", "content": "你只能说中文"},
{"role": "user", "content": "Tell me about AI in English"},
{"role": "assistant", "content": "抱歉,我只能用中文回答。AI 是人工智能..."}
]
}
18.9 多轮一致性评估
18.9.1 主流多轮评测集
| 评测集 | 维度 | 规模 | 备注 |
|---|---|---|---|
| MT-Bench | 多轮对话 | 80 | GPT-4 评分 |
| MINT | 多轮工具调用 | 800 | LLM-as-Judge |
| τ-Bench | Agent 工具调用 | 165 | 工具执行模拟 |
| BFCL | Function Calling | 2000+ | 工具调用准确率 |
18.9.2 MT-Bench 评分
MT-Bench 用 GPT-4 当 judge,对多轮对话评分:
def mt_bench_score(model, conversations):
scores = []
for conv in conversations:
# 模型生成多轮响应
model_responses = []
for msg in conv:
if msg['role'] == 'user':
response = model.generate(msg['content'])
model_responses.append(response)
# GPT-4 评分(1-10)
score = gpt4_judge(conv, model_responses)
scores.append(score)
return np.mean(scores)
18.9.3 τ-Bench 详解
τ-Bench(Yao et al., 2024)是 Agent 工具调用的硬核评测:
- 模拟真实 API 环境(如 airline/retail API)
- 测试多步工具调用 + 失败恢复
- 用规则检查最终状态是否正确
任务: "帮用户取消航班 UA123,用户有 credit"
Step 1: 查用户 credit
Step 2: 查航班状态
Step 3: 调 cancel_reservation
Step 4: 确认取消
τ-Bench 评测的是”最终任务是否成功”,不是”过程是否像”。
18.9.4 BFCL
BFCL(Berkeley Function Calling Leaderboard)专测工具调用准确率:
| 子任务 | 指标 |
|---|---|
| 工具选择准确率 | 选对工具的比例 |
| 参数准确率 | 参数名/值正确的比例 |
| 多工具调用 | 并行调用多个工具的准确率 |
| 失败恢复 | 工具失败时的恢复率 |
18.10 多轮/Agent 数据工业 SOP
1. 任务定义:多轮对话 / 工具调用 / 复杂 Agent
2. 来源配比:
- 30% UltraChat 风格多轮
- 30% xLAM 风格工具调用
- 20% 真实日志
- 20% 人工金标
3. 合成:双模型自玩 + mock 执行
4. JSON Schema 校验:不合格丢弃
5. 上下文一致性检查
6. 失败恢复 trajectory 补充
7. System Prompt 5 类型配比
8. 长度过滤 + Pack
9. 训练:SFT(多轮 loss mask)→ DPO → RL(可选,GRPO on tool-use)
- RL 使用多维奖励:validity + coverage + efficiency + name accuracy + argument accuracy
- 训练数据:多轮 MCP conversation(~13K 条即可见效)
- 对 BFCL Multi-Turn 有 3-10pp 改善(Qwen3-4B +10.2pp, Qwen2.5-7B +3.7pp)
- <!-- edit: 2026-07-29 SOP 第9步新增可选 RL 阶段(GRPO for tool-use, arXiv:2606.03892) -->
10. 评估:MT-Bench + τ-Bench + BFCL
第 19 章将深入评估闭环与归因——把数据、训练、评估串成闭环。