Agent 工具调用失败后,不应一律重试;应先判断错误类型,再分配有限预算。达到终止条件时停止调用,熔断器打开后转入降级。能否自动重试,取决于故障是否可恢复、调用是否能够安全重放,以及剩余预算是否充足;超时、参数错误和业务拒绝不能共用一套重试逻辑。
查询工具调用超时后,模型收到错误信息,再次生成相同调用,工具又超时,错误继续回灌,最终形成循环。掘金热榜文章将容易缺失的这一层机制概括为“错误自救与熔断”。这类循环通常源于执行器缺少重复检测、预算限制和明确的终止条件,而非工具单点故障。
失控重试始于错误回灌
典型的工具调用链包括生成结构化请求、解析参数、执行工具和回传结果。模型输出、参数解析、工具超时、网络抖动以及返回数据解析,任何一环都可能失败。
如果每次失败都把原始错误重新交给模型,却没有记录已消耗的尝试次数和调用指纹,模型很可能继续生成相同请求。无退避、无上限的重试与错误信息反复回灌,还会推高日志量和 Token 成本。因此,重试决策应该由执行器控制,而不是完全交给模型临场判断。
错误类型决定处置路径
先建立失败矩阵,比捕获异常后统一调用 retry() 更可靠:
| 失败类型 | 典型表现 | 默认处置 |
|---|---|---|
| 瞬时依赖故障 | 网络抖动、超时、依赖暂时不可用 | 在预算内退避重试 |
| 参数或协议错误 | 参数缺失、格式错误、Schema 不匹配 | 修正参数后重新生成,不原样重试 |
| 业务拒绝 | 资源不存在、状态不允许、权限不足 | 更换路径、追问用户或停止 |
| 无任务进展 | 工具执行成功,但任务状态没有变化 | 识别无进展并切换策略 |
| 副作用结果未知 | 下单、支付、删除等写操作超时 | 查询执行状态或使用幂等机制 |
| 高风险操作未授权 | 缺少授权或二次确认 | 阻断执行,确认后才能继续 |
参数错误可以把结构化错误反馈给模型,让它修正参数;业务拒绝则应换工具或向用户澄清,不能伪装成临时故障继续重试。适合自动重试的主要是网络抖动、超时和暂时不可用等瞬时故障。
重试预算要覆盖调用和任务
至少需要同时设置调用级的 maxAttempts、任务级的 maxRounds、总 deadline 和 tokenBudget。调用级预算限制一段重试序列,任务预算限制整个 Agent 循环,熔断器则描述工具依赖的健康状态,三者不能互相替代。
recovery:
maxAttempts: ${TOOL_MAX_ATTEMPTS}
maxRounds: ${TASK_MAX_ROUNDS}
deadline: ${TASK_DEADLINE}
tokenBudget: ${TASK_TOKEN_BUDGET}
backoff:
base: ${TOOL_BACKOFF_BASE}
cap: ${TOOL_BACKOFF_CAP}
jitter: true
maxAttempts 约束一个逻辑调用的总尝试次数,maxRounds 约束任务可以经历多少轮规划与执行,deadline 是墙钟时间上限,tokenBudget 则限制任务总 Token 消耗。具体数值应来自工具 SLA、业务成本和幂等性,不能给出通用固定值。
还要明确 Agent 层和 SDK 层各自是否负责重试。如果两层都自动重试,实际尝试次数可能成倍放大。
指数退避必须配合预算
对可重试的瞬时故障,可以采用有上限的指数退避并加入随机抖动:
delay = min(cap, base × 2^(attempt - 1) + jitter)
每次重试前都要重新检查 deadline 和剩余预算。如果剩余时间不足以完成下一次调用,就应停止并返回已有结果,而不是启动一次注定无法完成的等待。
退避只调整重试时机,不会纠正错误分类、修复错误参数或终止无进展循环。错误回灌时还应携带已消耗的预算与调用指纹,让执行器能够识别“正在重复同一件事”。
用调用指纹识别无效重试
使用工具名和规范化参数生成调用指纹,可以识别同工具、同参数的原样重复调用:
const fingerprint = hash(`${toolName}:${canonicalize(args)}`);
规范化可以统一对象字段顺序,但不能删除具有业务含义的参数。指纹还应限定在当前任务或会话内,避免不同任务之间的合法同名调用互相干扰。
如果同一指纹反复出现,而且错误码、返回状态和任务状态都没有变化,就应认定调用没有取得进展,停止原样重试。此时可以让模型修正参数、更换工具或向用户追问。对于状态持续变化的异步轮询,不应误判为重复调用,因为任务实际上仍在推进。
写操作要先确认执行结果
下单、支付、删除等写操作超时,只表示结果未知,不能直接认定执行失败。此时应优先通过请求标识查询执行状态,或者使用工具提供的幂等机制,避免重复扣费和重复写入。
如果无法确认副作用是否发生,执行器应停止自动重试,并把状态标记为“结果未知”,不能随意报告成功或失败。
终止条件应写进执行器
以下条件都应由执行器判断:
- 错误不可重试:停止当前路径,修正参数或向用户澄清。
maxAttempts耗尽:结束该工具的重试序列。maxRounds、deadline或tokenBudget耗尽:停止整个任务并输出部分结果。- 重复调用没有进展:切换工具或处理策略。
- 高风险操作未确认:阻断执行并请求授权。
- 副作用结果无法核对:停止盲目重试,标记结果未知。
- 熔断器已经打开:停止调用该依赖,转入降级路径。
这些条件应当是可执行的状态机规则,而不是只写在提示词里。模型可以提出下一步建议,但是否继续调用必须由执行器决定。任务预算耗尽时,输出还应区分“已完成”“未执行”和“结果未知”,避免把不确定状态包装成成功。
熔断后转到备用路径
熔断器可以使用 Closed、Open、Half-Open 三种状态:Closed 正常放行,Open 使调用直接失败且不再触发重试,Half-Open 只放行探测请求,用于试探工具是否恢复。
熔断阈值应结合工具 SLA 和失败成本配置,不存在通用的固定次数。熔断器打开后,应改用替代工具、返回已有部分结果或向用户澄清;非关键步骤失败,不必直接判定整个任务失败。但支付、删除和管理员操作不能在降级时被静默替换,替代路径仍要满足授权与幂等要求。
我的判断是,可靠的 Agent 不必以永不失败为目标。系统应明确判断何时继续、何时停止,并让每次失败都进入受预算和终止条件约束的处置流程。
[email protected]
。
我们承诺在核实信息后,将第一时间删除相关内容或断开链接。






















暂无评论内容