中级工具调用技术一面
工具调用失败:重试策略怎么设计才不死循环
考察候选人对Tool Calling异常处理的工程思维——可恢复与不可恢复错误的区分、退避策略、以及如何防止Agent进入无限重试
#Tool Calling#重试策略#异常处理#容错设计
情景对话
大J
工具调用失败了,你的Agent会怎么处理?
小Y
第一反应是先搞清楚为什么失败——这个问题的核心不是「要不要重试」,而是「这个错误值不值得重试」。
我会把错误分两类:一类是「可恢复的」,比如网络抖动、限流、超时,这些重试是有意义的;另一类是「不可恢复的」,比如参数格式错误、鉴权失败、资源不存在,重试只是在浪费时间和token,应该直接放弃并告知用户。
这个判断如果不做,Agent就会对着一个永远会失败的工具反复调用,直到耗尽轮次。
大J
怎么判断一个错误是可恢复的?
小Y
主要看两个维度:HTTP状态码和错误语义。
5xx基本都是可恢复的候选——服务端临时故障;429是限流,可恢复但要退避等待;4xx里面,400/422是参数问题,不可恢复,重试没意义;401/403是权限问题,也不可恢复;404是资源不存在,要分情况——如果是查询类操作,404是正常结果不是错误。
另外有些工具会在error message里带上语义信息,比如「quota exceeded」和「invalid input」,也可以用来辅助判断。
坦白说,边界情况挺多的,我之前的项目里是维护了一个错误码白名单,只有在白名单里的才走重试逻辑。
大J
好。那重试本身怎么设计?直接重试还是有等待?
小Y
肯定不是直接重试,特别是对限流场景。我用的是指数退避加抖动:第一次失败等1秒,第二次等2秒,第三次等4秒,但每次加一个随机抖动,避免多个Agent同时重启的「惊群效应」。
最大重试次数我设3次,超过就走降级。次数不宜太多,因为每次重试都要把工具调用结果带回LLM做推理,context会持续膨胀。
还有一个细节:重试时要带上上一次失败的错误信息给LLM,让它在下一个Thought里能感知到「我刚才失败了,原因是XXX」,而不是盲目重试。有时候LLM会自己调整参数,比如上次超时它会减少查询量。
大J
LLM自己调整参数——这个靠谱吗?不会调出更烂的结果?
小Y
这个确实是个风险点。我们的做法是限定LLM能修改的参数范围——比如查询工具,它可以调整时间范围或关键词,但不能修改鉴权信息或目标接口。通过工具的schema描述来约束,readonly字段就不暴露给LLM改。
另外对高风险工具,我们完全禁止LLM在重试时修改参数,必须保持原始调用参数,只允许它决定「要不要继续」。低风险工具才允许参数微调。这是在灵活性和安全性之间做的权衡。
大J
说说实际踩过的最深的一个坑。
小Y
最典型的一次是一个数据库查询工具,返回的是空结果而不是错误码。LLM把「空结果」当成「查询失败」处理,然后不断修改查询条件重试,条件越改越宽,最终查出了不相关的数据,还很「自信」地把这些数据当作答案返回给了用户。
那次之后我们规定:空结果是正常语义,必须在工具的schema里明确标注「空数组是合法返回值,代表无匹配记录」。LLM看到这个说明就不会把空结果误判为错误了。
本质上这类问题都是工具契约不清晰导致的——工具告诉LLM的信息越精确,LLM的行为就越可预期。
核心概念
重试策略的前提是错误分类。5xx/429等服务端临时故障值得重试;4xx参数错误/权限问题不值得重试。错误分类决策错了,重试只会浪费资源。
每次重试等待时间指数增长(1s→2s→4s),叠加随机抖动避免惊群效应。防止在服务限流期间集中冲击,也防止多Agent同时恢复时的拥塞。
重试时将失败信息反馈给LLM,让它在下一轮Thought中感知失败原因,而不是盲目重放原始调用。LLM有机会基于错误信息自适应调整策略。
工具的schema描述越精确,LLM的行为越可预期。空结果、边界值、readonly字段都需要在schema中明确标注,否则LLM会用错误的语义解读正常返回。
评分维度
延伸追问
超时是最难处理的场景——操作可能已执行也可能没执行。关键是工具本身要设计成幂等的,或者提供一个查询接口来确认状态。对于不幂等的高风险操作(如支付、发送邮件),超时后应该走人工确认而不是自动重试。
静态分析是读操作,超时可重试2-3次加指数退避。超过上限后降级为:1) 跳过本次分析,标注「静态分析暂时不可用,仅基于LLM判断」;2) 缩小分析范围,只对改动最大的文件运行;3) 同时记录失败日志,供后续异步补跑。关键是审查结论要注明可信度,不能把降级结果当完整结果呈现。
用Mock工具替换真实工具,注入可控的失败序列(如前两次返回429、第三次成功)。重点测试:1) 是否只对可恢复错误重试;2) 退避时间是否正确;3) 超过上限后是否正确降级;4) 重试后context是否包含失败信息。