LLM 请求重试:先分错误,再管预算
作者建议对超时、429 和 5xx 使用退避与随机抖动,并优先遵循 Retry-After;400、401、403 则直接失败。重试应受任务总预算约束,流式响应中断后应完整重启消息,过载时是否切换模型仍待权衡。
AI 深度解读
一个 Agent 把同一份错误请求重试了 11 次,每次还带上完整对话。请求始终不可能成功,重试策略却只关心「有没有抛异常」。作者由此整理出一套 LLM 调用规则:按错误类型决定是否重试,限制重试预算,并单独处理流式输出中断。
这篇短文值得读的地方,是把「失败就再来一次」拆成了几个具体决策。但它提供的是一次事故后的团队经验,没有对照实验;遇到服务过载时是否切换模型,作者也还没定论。
哪些错误值得再试一次
作者踩坑的起点,是把所有异常都交给同一个重试逻辑处理。一个格式有问题的请求被重复提交了 11 次,而且每次都重放完整对话。请求没有得到修复,重复调用还扩大了开销。
他们团队现在按状态码区分:
- 超时、429 和 5xx 可以重试。
- 400、401、403 不重试,立即失败,暴露问题,再修复请求。
这里真正有用的判断是:只有下一次调用存在成功的理由,重试才有价值。
在作者的规则里,超时、限流和服务端错误属于可能恢复的情况;请求格式、身份认证或访问权限出了问题,则需要先改变请求条件。把原请求原封不动再发一次,通常解决不了这些问题。
不过,「永不重试 400/401/403」是他们团队的工作规则,原文没有讨论更细的错误码,也没有交代认证信息更新后重新发起请求的流程。落地时,需要把「重复提交同一个错误请求」和「修复条件后重新调用」区分开。
重试要等多久,又该在哪里停下来
允许重试,也不代表立刻重发。
作者要求同时使用退避(backoff)和随机抖动(jitter):前者让连续失败后的等待逐步拉长,后者给等待时间加入随机变化,减少请求扎堆。如果服务端返回了 Retry-After,就以它为准,优先于客户端自己安排的重试时间。
原文没有提供退避公式、初始间隔、最大等待时间或具体实现,不能据此直接拼出一套生产配置。
另一个关键点是预算。作者主张给重试分配任务总预算的一部分,而不是只设置最大重试次数。次数只能限制发起多少次调用,却不能单独说明这些调用已经消耗了多少等待和执行资源。
重试预算耗尽后,任务应该明确失败。
这里也有一个空白:原文没有说明预算具体按耗时、Token、费用,还是多个维度计算,更没有给出分配比例。可直接借鉴的是约束方式,具体数值仍要由业务决定。
流式输出中断后,为什么不能接着拼
作者对流式输出的规则很明确:中途失败,就干净地重启这条消息,不要把新结果追加到已经生成一半的答案后面。
对聊天界面来说,这涉及前端如何管理消息状态。如果前一次调用留下了半段回答,下一次调用又生成一份新答案,直接拼接可能出现重复内容,或者前后逻辑接不上。按作者的规则重启消息,界面也应同步处理那段未完成内容。
但这套规则仍有一个未解决的问题:高峰期收到服务商的 529 或 overloaded 错误时,应该继续等待重试,还是立刻切换到另一个模型?
作者没有给出答案,只点出了代价:换模型可能改变回答质量。原地重试保留了模型选择,却要继续等待;切换模型改变了执行条件,也需要接受结果质量可能变化。原文没有两种方案的成功率、延迟或质量对照。
我的判断
我认同它把错误分类放在重试次数前面。对封装了 LLM 调用的 Node 服务或 Agent 来说,统一捕获异常之后直接重试,很容易掩盖真正需要修复的问题。
但这仍是一份经验规则,不能当成所有服务商通用的错误处理规范。作者没有给出各类错误的实测恢复率,也没有证明这套方案比固定次数重试节省多少资源。
相比只配置「最多重试几次」,预算约束更贴近任务能承受的代价;相比自动切换模型,它对结果质量的影响也更容易控制。不过,是否切换模型最终取决于任务要求,原文不足以替团队做决定。
能拿来做什么
- 在 Node 的 LLM 调用封装里,先记录并区分超时、429、5xx、400、401、403,再决定哪些异常进入重试流程。
- 为允许重试的调用加入退避和随机抖动,并让服务端的
Retry-After优先生效,避免各层代码各自安排重试。 - 给 AI 编程任务设定明确的重试预算,预算用尽就返回失败原因,方便使用者判断该修请求还是稍后再试。
- 检查聊天界面的流式重试逻辑,确保重新调用时会处理已有的半段回答;对于 529 和 overloaded,则先明确是否允许切换模型及接受质量变化。