Agent工具调用报错之后:90%的团队只做了重试,然后越重试越糟

📅 2026/11/7 ✍️ 小文 📖 约 1 分钟

工具报错是Agent每天都会遇到的事,但重试不是万能的。本文拆解七类工具错误、每类该用什么恢复策略,以及为什么「原样重试三次」是事故放大器。

Agent 上线第一周最常收到的反馈不是“答案不准”,而是“它卡住了,反复调同一个接口,最后给你一句抱歉”。

看日志会发现一模一样的 pattern:工具返回 500,Agent 原样再调一次,再 500,再调一次,第三次后放弃并道歉。三次调用把预算烧完,用户什么也没得到。问题不在重试本身,在于把“重试”当成唯一的恢复手段。

先说清楚:错误分七类,恢复方式完全不同

把错误当成一坨处理,是恢复设计的第一大坑。至少要在每类错误上做区分:

错误类型典型信号正确恢复策略
瞬时故障503、超时、连接重置指数退避重试(1–3 次)
参数错误400、schema 校验失败修正参数后重试,禁止原样重试
鉴权/权限401、403不重试,报给用户或转人工
资源不存在404换检索路径,不要重放同一 ID
限流429读 Retry-After,排队等待
业务拒绝200 但 success:false按业务码分支,通常不重试
部分成功批量接口部分条目失败只重试失败子集,不要全量重放

最容易出事的是最后一行。批量创建 20 条记录,18 条成功,2 条失败,Agent 一口气把 20 条全部重放——产生 18 条重复数据。这种事故在真实环境里非常常见,而且通常没人写测试覆盖。

为什么“原样重试三次”是事故放大器

三个原因叠在一起:

一是把瞬时故障变成雪崩:上游已过载,最不需要的就是三倍流量,没有退避和抖动的重试本质是自制的 DDoS。二是很多错误重试多少次都不会成功:参数缺字段、token 过期、ID 写错,这类错误的不动点就是失败,Agent 却把它们当网络抖动处理。三是污染上下文:三次失败输出堆进历史,模型接收到“这个工具不可靠”的信号,接下来可能编造一个看似合理的答案绕过工具——这是最危险的一步。

恢复该怎么设计:把错误当作可读的输入

核心思路是把错误结构化地交回给模型,而不是让它猜。返回给 Agent 的错误对象应至少包含四项:

{
  "error_type": "invalid_param",
  "retryable": false,
  "message": "缺少必填字段 order_id",
  "suggestion": "若只有手机号,请先调用 search_customer 获取订单"
}

suggestion 字段的价值被严重低估。它不是给用户看的兜底文案,而是给模型看的下一步指令。加上这一个字段,参数类错误的二次成功率通常能明显上升——因为模型不再盲改,而是沿着你指的路走。

三条配套规则:

  1. 不可重试的错误,在返回里显式标注 retryable: false,并在系统提示中写明“标注为不可重试时不要再次调用”。
  2. 每个工具设调用上限(建议 2 次),超限后强制进入降级分支:换工具、换路径,或直接告知用户。
  3. 失败信息去噪,只把 message 和 suggestion 放进上下文,原始堆栈留在日志里。

降级必须显式,不能静默

如果所有恢复路径都失败,正确的做法不是“生成一个看起来合理的答案”,而是明确告知:“这一步我没能拿到订单数据,你可以提供订单号,或者我转人工。”

静默降级给出过时或编造的信息,用户是察觉不到的。这类错误的成本远比一次坦诚的失败高。

可落地的检查清单

上线前过一遍:每类错误有明确分支、批量操作只重试失败子集、幂等键覆盖所有写操作、工具调用有硬上限、降级路径有文案、所有失败都带 suggestion。六条不需要新技术栈,只改错误处理层,半天能补完,却能消掉大部分“Agent 卡住了”的投诉。

📤 分享到