429 Too Many Requests:它意味着什么,何时该重试(2026)
一个 429 状态码对应 5 种不同的问题。先读 retry-after,按 1s/2s/4s 加抖动退避,遇到计费类 429 则完全跳过重试。
摘要
Status code: HTTP 429 (Too Many Requests)
Anthropic: error.type = rate_limit_error, plus a retry-after header
OpenAI: rate-limit 429 and spend/credit 429 share the code; read error.code
Google Gemini: 429 RESOURCE_EXHAUSTED, no retry hint documented
OpenRouter: 429 raised by OpenRouter, or relayed from the upstream provider
First thing to do: read retry-after, wait that long, retry once
No header: back off 1s, 2s, 4s with jitter, cap at 5 attempts
Never retry: credit/spend-cap 429s, they do not clear on their own
状态码本身几乎什么都告诉不了你。真正告诉你遇到的是五种问题中的哪一种的,是错误体和响应头,而这五种里有两种靠等待是解决不了的。
「429 Too Many Requests」到底是什么意思?
它意味着你的凭证被接受了,请求却依然被拒绝,因为你的账户请求的流量超过了当前允许的额度。 各厂商的措辞不同(「Rate limit reached for requests」、「rate limit exceeded」、RESOURCE_EXHAUSTED),但状态码是一样的。
429 不是以下三种情况:
- 认证失败。错误或被吊销的密钥是 401,没有资源访问权限的密钥是 403。
- 服务宕机。Anthropic 用 529
overloaded_error表示「the API is temporarily overloaded」(API 暂时过载),这是面向所有用户的,与你自己的限额无关。 - 未必与你的流量有关。在路由服务上,429 可能来自上游供应商,只是被转发给了你。
限流窗口通常是一分钟,但它不是时钟意义上的一分钟。Anthropic 将其限流器记录为令牌桶:「your capacity is continuously replenished up to your maximum limit, rather than being reset at fixed intervals.」(容量会持续补充到你的最大上限,而不是按固定间隔重置。)
速率超限错误是我的问题还是服务方的问题?
大多数情况下都不是。它是针对你账户的一项策略决定,而有五种不同的策略会产生同一个状态码。
| 你实际触发的是什么 | 它如何标识自己 | 等待能解决吗? |
|---|---|---|
| 每分钟请求或 token 上限 | Anthropic rate_limit_error + retry-after;OpenAI「Rate limit reached for requests」 | 能,按文档说明的时间等待即可 |
| 消费或额度上限 | OpenAI 的 error.code 为 credit_balance_exhausted、organization_spend_limit_exceeded、project_spend_limit_exceeded、organization_usage_limit_exceeded | 不能。重试只会白白消耗配额 |
| 加速限制(流量攀升过快) | Anthropic 在使用量陡增时返回 429,此时仍在你的名义限额之内 | 能,但正确做法是逐步爬坡 |
| 免费层每日上限 | OpenRouter 的 :free 模型:20 requests/minute、50 requests/day(购买额度低于 10 credits 时),达到 10+ 时为 1,000/day | 不能,得等到跨天才行 |
| 上游供应商容量 | OpenRouter 的 error.metadata.provider_code 携带供应商的原始代码 | 在同一条路由上重试只会更糟。改用故障转移 |
OpenAI 把这个区别说得很直白:Retry-After「does not mean that quota, billing, or other errors that require user action can be resolved by retrying.」(并不意味着配额、计费或其他需要用户处理的错误可以通过重试解决。)一个对所有 429 一视同仁的重试循环,会一直死磕一个已经耗尽的额度余额,直到你的告警系统察觉为止。
最后一行是人们最常误诊的。当一个发布期受限的模型无论你处于哪个层级都返回 429 时,在那条路由上再多的退避也无济于事,这正是 OpenRouter Kimi K3 429 问题的典型形态。
哪个响应头告诉你何时重试?
读 retry-after。它是服务器直接告诉你的唯一数值,其余所有响应头都只是上下文。 剩下的这套响应头因厂商而异,包括重置值的格式。
| 厂商 | 响应头 | 重置格式 |
|---|---|---|
| Anthropic | retry-after、anthropic-ratelimit-requests-{limit,remaining,reset}、anthropic-ratelimit-input-tokens-*、anthropic-ratelimit-output-tokens-*、anthropic-ratelimit-tokens-* | RFC 3339 时间戳 |
| OpenAI | Retry-After、x-ratelimit-{limit,remaining,reset}-requests、x-ratelimit-{limit,remaining,reset}-tokens,外加项目范围的 *-project-tokens | 时长字符串(1s、6m0s) |
| Google Gemini | 速率限制路径未做文档说明(not documented);文档改为建议使用指数退避 | 无 |
| OpenRouter | 当 OpenRouter 自身限流时返回 X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset;当供应商侧限制迫使重试时返回 Retry-After | 成功响应上不返回 |
那张表里有两个坑:
- 各厂商的重置值类型并不相同。 Anthropic 返回一个用于和时钟对比的时间戳。OpenAI 返回一个 Go 风格的时长,你需要把它解析成一段间隔。假设只有一种格式的代码,在遇到另一种时会悄无声息地产出垃圾数据。
- Anthropic 会把剩余 token 数向最接近的千位取整,所以把
anthropic-ratelimit-input-tokens-remaining当作精确值来用,在小请求上会高估。
响应头是否存在也无法保证,这在网关上尤其重要。在 2026-08-10 通过一个 OpenAI 兼容端点测试四个模型时,有两条路由返回了完整的 x-ratelimit-limit-requests / -limit-tokens / -remaining-* / -reset-* 集合(外加一个非标准的 x-ratelimit-renewalperiod-requests: 60),另外两条则完全没有返回任何速率限制响应头。这套响应头属于实际提供模型服务的那一方,而不属于你调用的那个端点。写解析器时,要让缺失的响应头退化为退避,而不是抛出异常。
收到 429 后应该等多久?
retry-after 说多久就等多久,如果没有这个响应头,就按 1s、2s、4s 加抖动,最多重试五次。 固定睡眠时间是错误答案,因为每个并行 worker 都会在同一瞬间醒来,再次触发同一个限制。
| 重试次数 | 基础延迟 | 加上完全抖动后实际睡眠 |
|---|---|---|
| 1 | 1s | 0 to 1s |
| 2 | 2s | 0 to 2s |
| 3 | 4s | 0 to 4s |
| 4 | 8s | 0 to 8s |
| 5 | 16s | 0 to 16s |
抖动是人们最常省略的部分,也正是当 20 个 worker 一起撞墙时最关键的部分。
import random, time
from openai import OpenAI, RateLimitError
client = OpenAI(base_url="https://api.ofox.io/v1")
def call_with_backoff(**kwargs):
for attempt in range(5):
try:
return client.chat.completions.create(**kwargs)
except RateLimitError as e:
# the SDK unwraps the envelope, so e.body is the inner "error" object
code = e.body.get("code") if isinstance(e.body, dict) else None
if code in {"credit_balance_exhausted", "organization_spend_limit_exceeded"}:
raise # a spend cap does not clear by waiting
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else random.uniform(0, 2 ** attempt)
time.sleep(delay)
raise RuntimeError("still rate limited after 5 attempts")
在写那个循环之前,先看看你的 SDK 是不是已经做了。查看已安装的 openai 2.53.0 客户端:DEFAULT_MAX_RETRIES is 2(默认最大重试次数为 2),重试路径先解析 retry-after-ms,然后是 retry-after(秒,或 HTTP 日期),会遵守服务器指定的延迟直到 120 seconds,若服务器要求的时间超过这个值则完全不重试。没有响应头时,它按 0.5 * 2^n 退避,上限为 8 seconds,再乘以一个介于 0.75 和 1.0 之间的抖动因子。Anthropic 的 SDK 默认也会对瞬时故障重试两次,并遵守 retry-after。所以在默认设置下,一个浮现到你代码里的 429,其实已经失败了三次(three times),每次之间仅间隔约半秒(half a second)和一秒(one second),离一分钟长的窗口差得远。要么调高 max_tokens……更准确地说,调高 max_retries 或自己接管这个循环;不要在第一层重试之上再叠加第二层重试。
RPM、TPM、ITPM 和 OTPM 到底在计什么?
不同厂商计量的东西不同,而单位决定了哪个旋钮有用。
- RPM 计的是调用次数,而非大小。如果你总是撞到它,那就往每次调用里塞更多工作。
- TPM 是输入和输出共用的一个合并预算。OpenAI 对某些模型还额外叠加了 RPD、TPD 和 IPM(每分钟图片数)。
- ITPM 和 OTPM 是 Anthropic 把该预算拆开的结果,按模型类别分别管控,所以长上下文的工作负载和长输出的工作负载会撞到不同的墙。
- 缓存读取是个有趣的例外。在大多数 Claude 模型上,
cache_read_input_tokens不计入 ITPM,而cache_creation_input_tokens会计入。Anthropic 自己的例子:在 2,000,000 ITPM 限额下,若缓存命中率为 80%,每分钟约可处理 10,000,000 个总输入 token。 max_tokens不计入 OTPM,OTPM 是按实际产出的 token 来评估的。一个宽松的上限在速率限制上不会让你付出任何代价。- 并发限制是另一码事。有些供应商限制的是在途请求数,而非每分钟速率,五家厂商速率限制对比里有各层级的具体数字。
为什么我流量很小却还是收到 429?
因为每分钟限制很少真的按每分钟来管控,而且这个桶也很少只属于你一个人。 常见嫌疑对象:
- 亚分钟级管控。Anthropic 的文档说得很明白:「a rate of 60 requests per minute (RPM) might be enforced as 1 request per second. Short bursts of requests can exceed the limit and trigger rate limit errors.」(每分钟 60 个请求的速率可能被按每秒 1 个请求来管控。短暂的突发请求会超出限制并触发速率限制错误。)
- 整个组织共用一个桶。限额挂在组织层级,而非每个密钥,所以除非你设置了工作区级别的限额,否则每个服务、notebook 和 CI 任务都从同一个池子里取用。
- 扇出。并行的智能体会成倍增加并发请求,且每个请求都携带完整上下文,所以 ITPM 会最先耗尽。
- 加速限制。使用量的陡增可能在你仍处于所声明的限额之内时就触发 429。
- 免费层每日上限。50 个请求的每日额度,一个下午的调试就用光了。
- 伪装成流量问题的计费 429。零流量却收到 429,通常意味着消费上限或额度余额耗尽,而不是吞吐量问题。
如果你是在一个编码智能体内部而非自己的代码里看到这个的,机制相同但旋钮不同,Claude Code 速率限制排查指南里讲了并发相关的设置。
429 和 529 或 RESOURCE_EXHAUSTED 是一回事吗?
不是。429 关乎你的账户,529 和 503 关乎服务方,而 RESOURCE_EXHAUSTED 是 Google 对 429 的叫法。
| 代码 | 厂商措辞 | 谁的问题 | 该怎么办 |
|---|---|---|---|
| 429 | rate_limit_error(Anthropic)、rate limit reached(OpenAI) | 你账户的限额或计费 | 读错误体,然后等待或处理计费 |
429 RESOURCE_EXHAUSTED | Google Gemini | 你的配额(RPM、TPM、RPD) | 指数退避,或申请配额 |
| 529 | overloaded_error(Anthropic) | 服务方容量,所有人 | 退避,或故障转移到另一个模型 |
| 503 | Service unavailable / UNAVAILABLE | 服务方容量 | 退避后重试 |
| 500 | api_error | 服务方 bug 或故障 | 带退避重试,然后附上请求 ID 上报 |
这个区分值得在你的日志里落实。一个把「429 + 529」当成一个数字来统计的仪表盘,没法告诉你到底该购买更高层级还是该增加一条兜底路由。如果你想深入了解容量这一类情况,请看 Claude API 529 过载指南。
只盯 Claude 一家的话,Claude API 报错汇总(429/401/529/超时)那篇按错误码逐个拆得更细,包括 402 余额不足和 streaming 中途报错这些本文没展开的分支。
怎样才能不再收到 429?
大致按「每单位缓解所需付出的努力」排序:
- 遵守
retry-after,并在它缺失时加抖动。免费,而且能修复你自己造成的那部分。 - 限制客户端侧的并发。在你的 worker 池外围加一个信号量,比任何重试策略都更可靠,因为它是预防突发,而不是在突发之后被动反应。
- 缓存你的前缀。在 Claude 模型上这能买到实实在在的 ITPM 余量,而不仅仅是更便宜的账单,提示缓存成本算账里展示了盈亏平衡点在哪。
- 把不紧急的工作转到批处理端点。批处理 API 有独立的限额,而且通常是半价(usually half price)。
- 与其更用力地重试,不如故障转移。当 429 来自上游容量时,对同一请求形态换用第二个模型,一跳就能恢复调用。这正是「一个端点后面挂多个模型」这一做法的实际理由:ofox 是 OpenAI 兼容的,所以兜底只需改一个模型字符串,而不必做第二套集成。
- 申请提额。Anthropic 在控制台里有一个「Request rate limit increase」(申请提高速率限制)的流程,OpenAI 则根据累计消费把账户提升层级。两者都不是即时生效的,所以这是下个月的计划,而不是今天下午的方案。
有两件事不要做:不要把一个工作负载分散到同一组织下的多个 API 密钥上(限额是组织级别的,所以什么都不会改变),也不要在你并没有真的生成那么多 token 的情况下,寄希望于降低 max_tokens 来缓解输出限制。
本次更新查证的来源
- https://platform.claude.com/docs/en/api/rate-limits
- https://platform.claude.com/docs/en/api/errors
- https://developers.openai.com/api/docs/guides/rate-limits
- https://developers.openai.com/api/docs/guides/error-codes
- https://ai.google.dev/gemini-api/docs/rate-limits
- https://ai.google.dev/gemini-api/docs/troubleshooting
https://openrouter.ai/docs/api-reference/limits
常见问题
- 收到 429 是不是意味着我的 API 密钥被封禁或失效了?
- 不是。无效或被吊销的密钥会返回 401(认证错误),而没有资源访问权限的密钥会返回 403。429 表示密钥认证通过了,请求只是因为流量原因被拒绝,所以只要限流窗口重新蓄满或计费问题得到解决,同一个密钥就能再次正常工作。
- 速率限制是不是每分钟整点重置一次?
- 在 Claude API 上不是。Anthropic 采用的是令牌桶机制:容量会持续补充到你的上限,而不是按固定间隔重置。这就是为什么一次突发请求可能在上一次突发成功后几秒内就触发 429,也是为什么重置类响应头给你的是一个时间戳,而不是固定的时钟边界。
- 提示缓存会提高我的速率限制吗?
- 在大多数 Claude 模型上,对于输入而言基本上是的。Anthropic 明确说明 cache_read_input_tokens 不计入 ITPM(Claude Haiku 3.5 是例外,它会计入),而 cache_creation_input_tokens 会计入。那些用一个合并 TPM 数字来管控的厂商通常会把所有输入 token(无论是否缓存)都算进去,所以在那里缓存只能降低账单,而买不到速率限制的余量。
- 如果没有 retry-after 响应头,我该不该立即重试 429?
- 不该。立即重试正是把短暂限流拖成持续限流的方式,因为每个并行的 worker 都会在同一瞬间重试。没有响应头时,请用带抖动的指数退避,并限制重试次数上限。如果错误体指向了消费上限或额度余额耗尽,那就完全不要重试。


