HTTP 429 的标准含义是 Too Many Requests,但 AI API 使用场景中,它往往承载多个不同原因。无条件立即重试通常会让问题更严重。
先做这三件事
保存完整错误体和响应头;确认账户余额与模型权限;根据 Retry-After 或限流头等待,并使用带随机抖动的指数退避。
四种常见 429
| 类型 | 表现 | 处理方式 |
|---|---|---|
| RPM 超限 | 单位时间请求数过多 | 排队、合并请求、降低并发 |
| TPM 超限 | 输入和输出 Token 速率过高 | 缩短上下文、限制输出、错峰 |
| 额度不足 | 余额或月度配额耗尽 | 充值或调整预算 |
| 上游容量 | 热门模型暂时拥堵 | 退避、切换允许的备用模型 |
第一步:检查错误体和响应头
不要只记录状态码。错误 JSON 中的 type、code 和 message 通常能区分限流与余额问题。响应头可能包含剩余请求数、剩余 Token、重置时间或 Retry-After。
const response = await fetch(url, options);
if (response.status === 429) {
const body = await response.text();
console.error({
status: response.status,
retryAfter: response.headers.get("retry-after"),
requestId: response.headers.get("x-request-id"),
body
});
}日志里不要记录 API Key、完整用户提示词或隐私数据。请求 ID、模型、Token 数、状态码和重试次数通常足以排查。
正确的重试策略
指数退避让等待时间逐步增加,随机抖动避免大量实例在同一时刻再次请求。只对临时错误重试,并设置最大次数。
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
async function withRetry(run, maxRetries = 4) {
for (let attempt = 0; ; attempt++) {
const response = await run();
if (response.status !== 429 || attempt >= maxRetries) return response;
const retryAfter = Number(response.headers.get("retry-after"));
const base = Number.isFinite(retryAfter)
? retryAfter * 1000
: Math.min(1000 * 2 ** attempt, 16000);
const jitter = Math.random() * 500;
await sleep(base + jitter);
}
}重试必须考虑幂等性。文本生成重复请求主要增加成本,创建异步媒体任务则可能产生多个任务和多次计费。
如何从源头降低 429
使用并发队列
不要让每个用户请求直接冲向上游。为每个模型或租户设置并发上限,把突发流量平滑成可控速率。
减少无效 Token
删除重复系统提示、裁剪历史对话、对长文档先检索再拼接,并设置合理的最大输出长度。TPM 限制计算的是流量,不只是请求数量。
缓存确定性结果
分类、固定知识问答、嵌入和重复提示可以缓存。缓存键应包含模型、提示词、关键参数和版本,避免返回不兼容结果。
按能力设置备用模型
备用模型不能只按价格选择。工具调用、上下文长度、结构化输出和多模态能力必须满足任务要求。可在 模型广场 对比模型属性。
聚合网关场景下怎么排查
429 可能来自网关自身配额,也可能是上游返回。检查控制台中的分组限额、账户余额、模型渠道状态和请求日志。如果只有一个模型报错,通常优先检查该模型渠道;如果所有模型同时报错,则检查账户或全局配额。
- 确认 API Key 所属分组和可用模型。
- 确认错误发生在提交阶段还是流式输出阶段。
- 记录请求 ID,便于定位具体上游。
- 检查是否因客户端超时而重复发起同一任务。
- 对图片和视频任务使用幂等键或业务去重。
一分钟排查清单
- 读取完整错误消息和响应头。
- 检查余额、配额与模型权限。
- 查看 RPM、TPM、并发和上下文大小。
- 遵循 Retry-After,启用指数退避。
- 限制最大重试次数,避免无限循环。
- 确认任务是否允许安全重试。
- 必要时降载或切换经过验证的备用模型。
Sublyx Field Notes