[WIP] 工具调用失败模式:被忽视的 Agent 鲁棒性训练数据
本文提出将工具调用失败模式作为独立研究对象,系统化构建 Agent 鲁棒性训练数据的研究方案。从失败类型分类、日志挖掘、数据格式设计到评测体系,提供一套可操作的完整路径。
[WIP] 工具调用失败模式:被忽视的 Agent 鲁棒性训练数据
问题的起点:Agent 为什么脆弱?
当前 LLM-based Agent 的研究大量聚焦于「如何让 Agent 更好地调用工具完成任务」,但一个被系统性忽视的问题是:当工具调用失败时,Agent 该如何行动?
这不是小概率事件。在生产环境中,API 超时率通常在 0.1%–5% 之间,权限错误、参数格式错误、语义偏差更是家常便饭。现有 Agent 训练数据(包括 ToolBench、APIBench 等)几乎清一色是「成功调用轨迹」,这相当于只教学生在晴天开车,从未让他们练习过雨天刹车。
核心论点:工具调用失败模式应当作为独立的研究对象,配套专属的训练数据构建方案。
一、失败类型分类体系
1.1 工具本身问题(Infrastructure Failures)
这类失败与 Agent 行为无关,属于外部环境故障,但 Agent 必须正确响应。
| 子类型 | 典型表现 | 正确处理策略 |
|---|---|---|
| 超时(Timeout) | HTTPTimeoutError, 无响应 | 指数退避重试,超阈值后换备用方案 |
| 权限不足(AuthZ) | 403 Forbidden, Permission Denied | 停止重试,上报人工处理,不泄露敏感路径 |
| 服务端错误(5xx) | 500 Internal Server Error | 区分是否幂等再决定是否重试 |
| 限流(Rate Limit) | 429 Too Many Requests | 尊重 Retry-After 头,不暴力重试 |
数据构建方法: 在日志中捕获所有 status_code >= 400 的调用,按子类型分箱。对于权限类失败,可以在测试环境中系统性地注入不同权限级别的 Token,生成覆盖各种 Auth 场景的轨迹。
1.2 参数问题(Parameter Failures)
这类失败是 Agent 自身造成的,训练价值最直接。
格式错误(Syntactic): 参数类型不匹配、JSON 格式非法、枚举值拼写错误。容易自动检测,构建成本低,但训练价值相对有限——这类错误大模型已经做得不错。
范围越界(Boundary Violation): 日期超出数据范围、分页 offset 超过总条数、文件路径不存在。特点是错误信息明确,但 Agent 需要推理出合法范围再重试,而不是机械重填。
语义错误(Semantic Errors)——最核心的子类型:
语义错误的特点是:调用在技术层面完全成功(HTTP 200),但结果偏离了用户意图。这是所有失败类型中最难识别、也最有研究价值的。
举例:
- 用户问「上海明天的天气」,Agent 调用了
get_weather(city="Shanghai", date="today")——返回 200,数据正常,但日期填错了 - 用户要查「过去7天的订单」,Agent 传入
start_date="2026-03-23", end_date="2026-03-30"实际应为 UTC 时间但传了本地时间,结果少了8小时的数据 - 搜索工具返回了结果,但 Agent 用了错误的排序参数导致取到的不是最相关的文档
语义错误为什么难? 因为它没有显式的失败信号。Agent 必须具备「结果自验证」能力——不只是检查调用成功与否,而是判断返回内容是否满足原始意图。这需要一种元认知能力,而当前训练数据几乎不覆盖这个维度。
1.3 逻辑问题(Logic Failures)
死循环(Infinite Retry Loop): Agent 遇到同一错误反复重试,参数完全不变。这是最危险的失败模式,会导致 token 耗尽和费用爆炸。
幂等性错误(Idempotency Violation): 对非幂等操作(如创建订单、发送消息)在失败后直接重试,导致重复操作。Agent 需要区分 GET 类工具和 POST/写入类工具的不同重试策略。
级联失败(Cascade Failure): 步骤 A 失败,Agent 未中止后续步骤,导致步骤 B、C 建立在错误前提上。正确行为是在关键步骤失败时立即停止并向用户报告,而非继续执行。
二、数据来源:从真实日志中挖掘,而非合成
合成数据的核心缺陷在于:人写的「失败场景」往往过于规则化,缺少真实系统中的噪声、上下文依赖和奇特的失败组合。真实 Agent 系统日志是天然的宝矿。
2.1 日志格式设计:让日志本身就是可训练轨迹
关键原则:不是在已有日志上补打标注,而是在设计系统时就让日志格式对训练友好。
每条工具调用记录应包含:
{
"trace_id": "sess_a3f9c2",
"step_index": 3,
"timestamp": "2026-03-29T14:23:11Z",
"tool_name": "search_documents",
"intent": "查找过去一周关于项目X的会议记录",
"input_params": {
"query": "项目X会议记录",
"date_from": "2026-03-22",
"date_to": "2026-03-29",
"sort_by": "relevance"
},
"raw_response": {
"status_code": 200,
"body": { "results": [], "total": 0 }
},
"agent_observation": "搜索返回空结果",
"next_action": {
"type": "retry",
"params_delta": { "date_from": "2026-03-01" },
"reasoning": "尝试扩大日期范围"
},
"failure_annotation": null
}
关键字段说明:
intent:调用时的自然语言意图,语义错误检测的锚点agent_observation:Agent 自己对结果的解读(而非原始响应)next_action.params_delta:重试时只记录变化的参数,便于分析修正策略failure_annotation:初始为 null,由后续流程填入
2.2 自动标注「正确行为」vs「错误行为」
规则型自动标注(高覆盖、低精度):
- 同一工具相同参数重试超过 3 次 → 标注为
loop_failure - 非幂等操作(工具名含
create/send/delete)重试 → 标注为idempotency_risk - 最终任务结果为失败且最后 N 步存在某工具调用 → 该调用为候选负样本
回溯标注(结果驱动):
以任务最终结果为标注锚点。如果最终任务成功,则追溯成功路径上所有的「失败→正确恢复」步骤,标注为正样本;如果最终任务失败,则找出关键错误决策点,标注为负样本。
LLM 辅助标注(语义错误专用):
语义错误无法靠规则检测,需要用一个 Judge LLM 判断:
“工具返回了 {result},原始意图是 {intent},这次调用是否满足了意图?如果不满足,错误原因是什么?”
Judge LLM 的输出再经人工抽检校验,形成高质量的语义失败标注。
2.3 处理长尾失败
低频失败(如特定 API 的特定错误码)往往携带最高价值的信息——正因为罕见,模型最没见过,训练收益最大。
主动采集策略:
- 建立「稀有失败」报警,当某种新型失败首次出现时触发人工记录
- 在测试环境中系统性地注入故障(Chaos Engineering),将生成的失败轨迹加入训练集
- 与业务方合作,收集历史上「Agent 翻车」的真实事故 case
数据增强策略:
- 对已有的长尾失败轨迹,通过 LLM 进行「变体生成」——保持失败模式不变,改变工具名称、参数值、领域上下文——从 1 个 case 扩展为 10 个 case
三、数据格式设计:完整的失败轨迹 JSON
{
"trajectory_id": "traj_20260329_b7e2a1",
"task_description": "帮用户查询本月销售数据并生成报表",
"final_outcome": "success",
"steps": [
{
"step_index": 1,
"tool_name": "query_sales_data",
"input_params": {
"month": "2026-03",
"region": "华南",
"granularity": "daily"
},
"response": {
"status_code": 500,
"error_code": "DB_TIMEOUT",
"message": "Database connection timeout after 30s"
},
"failure_type": "infrastructure",
"failure_subtype": "timeout",
"agent_decision": {
"action": "retry_with_backoff",
"wait_seconds": 5,
"reasoning": "服务端超时,数据库可能短暂不可用,等待后重试"
},
"decision_correctness": "correct",
"correctness_reason": "超时类错误适合退避重试,参数无需修改"
},
{
"step_index": 2,
"tool_name": "query_sales_data",
"input_params": {
"month": "2026-03",
"region": "华南",
"granularity": "daily"
},
"response": {
"status_code": 200,
"body": {
"records": 31,
"data": ["..."]
}
},
"failure_type": null,
"agent_decision": {
"action": "proceed",
"reasoning": "数据获取成功,继续生成报表"
},
"decision_correctness": "correct",
"correctness_reason": null
}
],
"failure_summary": {
"total_failures": 1,
"failure_types": ["infrastructure/timeout"],
"recovery_pattern": "retry_with_backoff",
"recovery_success": true
},
"metadata": {
"source": "production_log",
"annotator": "rule_based_v2",
"human_verified": false,
"domain": "business_analytics",
"difficulty": "easy"
}
}
语义错误示例(最难标注的情形):
{
"step_index": 1,
"tool_name": "get_weather",
"input_params": {
"city": "Shanghai",
"date": "2026-03-29"
},
"response": {
"status_code": 200,
"body": { "temp": 18, "condition": "cloudy" }
},
"failure_type": "parameter",
"failure_subtype": "semantic_error",
"failure_detail": "用户询问的是明天(2026-03-30)的天气,Agent 填入了今天的日期",
"agent_decision": {
"action": "proceed",
"reasoning": "天气数据获取成功"
},
"decision_correctness": "incorrect",
"correctness_reason": "应检测到返回数据的日期与用户意图不符,需要重新调用",
"correct_action": {
"action": "self_verify_and_retry",
"params_delta": { "date": "2026-03-30" }
}
}
四、评测方式:构造失败场景测试集
4.1 FailBench 设计
提出 FailBench——专门针对 Agent 失败处理能力的评测基准,与现有能力评测正交。
评测维度:
| 维度 | 指标 | 测量方式 |
|---|---|---|
| 失败识别率 | 正确识别失败类型的比例 | 注入已知类型失败,测 Agent 分类准确率 |
| 恢复成功率 | 失败后最终完成任务的比例 | 在失败环境中运行任务,看任务完成率 |
| 循环避免率 | 不陷入无效重试循环的比例 | 注入无法恢复的错误,测 Agent 何时放弃 |
| 语义自验证率 | 对语义错误的主动检测比例 | 构造表面成功实则错误的返回,测 Agent 是否发现 |
| 幂等安全率 | 非幂等操作的重复执行率(越低越好) | 注入写操作失败,测是否重复执行 |
4.2 故障注入测试框架
在测试时用 Proxy 拦截真实工具调用,按配置注入故障:
fault_config = {
"tool": "query_sales_data",
"trigger": "always", # or "first_call_only"
"fault_type": "timeout",
"fault_params": { "delay_seconds": 35 }
}
测试用例覆盖:单步失败、级联失败、语义错误、混合失败序列(先超时后语义错误)。
五、与现有工作的关系和差异
5.1 与 SWE-bench 的对比
SWE-bench 是目前最具影响力的 Agent 编程能力评测,任务是修复 GitHub Issue。它的失败模式是「代码逻辑错误导致测试不通过」,属于领域特定的任务失败。
本研究关注的是工具调用层面的系统性失败,两者正交:
| 维度 | SWE-bench | 本研究 |
|---|---|---|
| 失败来源 | 代码逻辑错误 | 工具调用层错误 |
| 领域依赖 | 强(代码) | 弱(通用工具调用) |
| 失败可见性 | 高(测试报错) | 低(尤其语义错误) |
| 训练目标 | 代码推理能力 | 鲁棒性与自我修正 |
5.2 与 ToolBench / APIBench 的差异
这些数据集提供了大量「成功的工具调用轨迹」,用于教 Agent 如何调工具。本研究是其互补品:专门覆盖失败场景,提升 Agent 在工具调用出错时的应对能力。两类数据应当结合使用——就像教人开车,既要教正常驾驶,也要教紧急制动。
5.3 与 ReAct / Reflexion 的关系
Reflexion 等工作已经提出让 Agent 从失败中反思学习,但反思的对象通常是任务层面的策略失败(错误的行动计划),而非工具层面的调用失败。本研究更底层,专注在「单次工具调用失败→正确处置」这个微粒度的决策闭环上。
六、下一步计划
- 数据采集:与 2–3 个有生产规模 Agent 系统的团队合作,接入日志采集 SDK,6 个月内积累 10 万条带失败标注的轨迹
- 标注流水线:实现规则型 + LLM Judge 双层标注,人工抽检 5% 校验精度
- FailBench 发布:构建覆盖 5 大维度、200+ 测试用例的评测集,开源发布
- 训练实验:在 7B/13B 规模模型上做消融实验,验证加入失败轨迹数据后各维度指标的提升幅度
核心 claim:工具调用失败数据是当前 Agent 训练数据中最系统性缺失的一类。每一次生产系统中的工具失败,都是一个被浪费的训练样本。本研究的目标,是把这些「浪费的失败」变成 Agent 进化的燃料。