429 Too Many Requests 不只表示“请求太快”。在大模型 API 中,它还可能来自并发过高、Token 速率、账号额度、单模型繁忙,或者应用与 SDK 的双重重试。
先保存完整错误证据
至少记录以下字段:
发生时间:
模型 ID:
HTTP 状态:429
错误 type / code:
Retry-After:
请求 ID:
当时并发数:
输入 Token 估算:
重试次数:
错误正文里如果明确出现余额、配额或账号状态,就先处理账户问题;如果出现 rate limit、requests per minute 或 tokens per minute,再调整请求节奏。
429 的五种常见来源
| 来源 | 典型现象 | 正确动作 |
|---|---|---|
| 请求频率 | 短请求密集时触发 | 限速、排队、读取 Retry-After |
| Token 速率 | 长上下文更容易触发 | 缩短输入、控制批量大小 |
| 并发过高 | 单请求成功,并发任务失败 | 设置并发上限和队列 |
| 余额或配额 | 低频请求仍持续 429 | 检查余额、账号和模型权限 |
| 重试放大 | 故障后请求量突然增加 | 关闭重复重试层,增加抖动 |
先用同一模型发送一个短、非流式请求。如果单请求也持续 429,优先检查额度和模型状态;如果只有并发时失败,优先检查队列与限速。
正确的退避策略
服务端返回 Retry-After 时优先按该值等待。该请求头既可能是秒数,也可能是 HTTP 日期;应先解析成等待秒数。没有该字段时,再使用带随机抖动的指数退避:
第 1 次:约 1 秒
第 2 次:约 2 秒
第 3 次:约 4 秒
达到最大尝试次数后停止并返回明确错误
不要让所有实例在同一秒重试。随机抖动能减少同步重试造成的第二次流量峰值。
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
import random
import time
MAX_WAIT_SECONDS = 60.0
def parse_retry_after(value: str | None) -> float | None:
if not value:
return None
try:
return max(0.0, float(value))
except ValueError:
try:
retry_at = parsedate_to_datetime(value)
if retry_at.tzinfo is None:
retry_at = retry_at.replace(tzinfo=timezone.utc)
return max(0.0, (retry_at - datetime.now(timezone.utc)).total_seconds())
except (TypeError, ValueError, OverflowError):
return None
def backoff(attempt: int, retry_after_header: str | None = None) -> None:
retry_after = parse_retry_after(retry_after_header)
if retry_after is not None and retry_after > MAX_WAIT_SECONDS:
raise TimeoutError("Retry-After 超过当前任务允许的等待时间")
if retry_after is not None:
delay = retry_after
else:
delay = min(8.0, 2 ** attempt) + random.uniform(0, 0.5)
time.sleep(delay)
这段代码只负责解析等待时间和暂停;attempt 从 0 开始。是否重试还要根据错误类型、请求幂等性、业务截止时间和最大尝试次数决定。
避免 SDK 与业务层重复重试
OpenAI Python SDK 默认会在初次请求后自动重试 2 次,即每次 SDK 调用最多尝试 3 次。如果业务层总共调用 SDK 4 次,最坏可能发出 12 次上游请求。
自建重试器时应明确只保留一层:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://www.aifast.club/v1",
api_key=os.environ["AIFAST_API_KEY"],
max_retries=0,
)
如果使用 SDK 默认重试,则业务层不要对同一个异常再无条件循环。
批处理和 Agent 怎么限并发
批处理
- 把任务放入队列;
- 设置固定并发上限;
- 每次只提高一个档位并观察 429;
- 记录成功量、429 数量和 Token,而不是只看任务数。
Agent 与工具调用
一个用户任务可能触发多轮模型请求和工具回传。限制“用户并发”并不等于限制“模型请求并发”。应同时设置:
- 单任务最大模型轮次;
- 单任务最大工具调用次数;
- 全局模型请求并发;
- 失败后的最大重试次数;
- 单任务预算上限。
什么时候不应该重试
- 错误正文说明余额不足或账号不可用;
- 请求已经达到业务截止时间;
- 有副作用的操作无法确认是否已执行;
- 同一模型持续失败且已达到最大尝试次数;
- 业务层没有幂等键,重试可能产生重复任务或重复扣费。
修复完成的验收标准
- 单请求和目标并发分别完成至少一轮验证;
- 429 会读取
Retry-After或进入有上限的退避; - SDK 与业务层只有一套明确的重试责任;
- 监控能区分请求数、Token、并发和重试次数;
- 达到重试上限后能快速失败,不会无限等待。
如果短请求也持续 429,先查看当前模型与价格并核对账号状态;如果错误变成 502、断流或读取超时,继续查看502 与 stream disconnected 排查。