调用大模型 API 时,429 限流重试 和指数退避是一套应对频率限制的自动恢复机制。下面分别解释。
1. 429 状态码:你被限流了
HTTP 429 Too Many Requests 表示你在短时间内发送了太多请求,超出了 API 的速率限制 (例如每分钟最多 60 次)。服务器会拒绝请求并返回这个状态码,通常还会附带 Retry-After 头,提示需要等多少秒后重试。
如果不处理 429,直接报错退出,你的任务就会中断。
2. 限流重试:遇到 429 别放弃,等一等再试
限流重试 就是当收到 429 时,不立即报错,而是暂停一段时间,然后重新发送刚才的请求。这样可以自动扛过 API 的流量限制,让任务平滑完成。
最简单的重试是固定间隔,比如每次等 1 秒。但固定间隔有两个问题:
-
如果限流是持续的,每秒重试一次仍然可能反复触发 429,形成"踩踏";
-
如果多个客户端同时被限流,又在同一时刻重试,会导致新的限流风暴。
3. 指数退避:让等待时间越来越长,越来越"聪明"
指数退避(Exponential Backoff) 是一种动态计算重试等待时间的策略:
-
第一次重试:等待 1 秒
-
第二次重试:等待 2 秒
-
第三次重试:等待 4 秒
-
第 n 次重试:等待 2^(n-1) 秒(常加上上限,如最大 64 秒)
等待时间指数级增长,给服务器足够的时间恢复,同时避免客户端在短时间内密集重试。
为什么要加"随机抖动"(Jitter)?
如果成千上万个请求同时被限流,它们都按相同的指数时间重试,又会在同一刻同时涌入服务器,再次造成拥塞。随机抖动就是在等待时间上加一个随机值(例如 ±10% 的浮动),把重试的时间点"打散"。
带抖动的指数退避公式(以 Python 为例):
import random
import time
def exponential_backoff_with_jitter(retry_count, base=1, max_wait=64):
wait = min(base * (2 ** retry_count), max_wait)
jitter = wait * 0.1 * random.random() # 增加最多 10% 的随机抖动
return wait + jitter
整体流程示例
请求 -> 返回 429
第 1 次重试:等 1.2 秒 -> 再请求 -> 还是 429
第 2 次重试:等 2.5 秒 -> 再请求 -> 成功!
如果重试次数超过设定的最大值(如 5 次),则最终放弃并报错。
4. 在 LangChain 等框架中的应用
许多 LLM 框架已经内置了这种机制。例如 LangChain 中可以为模型设置 max_retries 和 request_timeout,底层使用了 tenacity 库实现指数退避重试。你只需配置参数,框架会自动处理 429 以及其它可重试的网络错误。
配置示例(以 ChatOpenAI 为例):
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4",
max_retries=5, # 最多重试 5 次
request_timeout=60, # 单次请求超时
)
当你调用 llm.invoke(...) 时,若遇到 429,底层会自动进行指数退避重试,无需手写循环。
总结
| 概念 | 作用 |
|---|---|
| 429 限流 | API 告诉你"太快了,暂停一下" |
| 重试 | 自动等一等再试,而不是直接失败 |
| 指数退避 | 让等待时间越来越长,给服务器喘息空间 |
| 随机抖动 | 打散重试时刻,避免同时涌入 |
这套机制是调用大模型 API 时保证稳定性的基本功,几乎所有生产级代码都会采用"指数退避 + 随机抖动"的重试策略。