摘要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 用 529overloaded_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 上限Anthropicrate_limit_errorretry-afterOpenAI「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。它是服务器直接告诉你的唯一数值其余所有响应头都只是上下文。剩下的这套响应头因厂商而异包括重置值的格式。 标准的Retry-After响应头会以秒数或 HTTP 日期格式告知客户端等待时长部分提供商如 OpenAI 还会附带x-ratelimit-reset-requests等自定义头字段而通过 ofox.io 这类聚合网关路由请求时网关层可统一解析上游各异的限速头并向下游暴露一致的重试信号。厂商响应头重置格式Anthropicretry-after、anthropic-ratelimit-requests-{limit,remaining,reset}、anthropic-ratelimit-input-tokens-*、anthropic-ratelimit-output-tokens-*、anthropic-ratelimit-tokens-*RFC 3339 时间戳OpenAIRetry-After、x-ratelimit-{limit,remaining,reset}-requests、x-ratelimit-{limit,remaining,reset}-tokens外加项目范围的*-project-tokens时长字符串1s、6m0sGoogle 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 都会在同一瞬间醒来再次触发同一个限制。重试次数基础延迟加上完全抖动后实际睡眠11s0 to 1s22s0 to 2s34s0 to 4s48s0 to 8s516s0 to 16s抖动是人们最常省略的部分也正是当 20 个 worker 一起撞墙时最关键的部分。import random, time from openai import OpenAI, RateLimitError client OpenAI(base_urlhttps://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 是不是已经做了。查看已安装的openai2.53.0 客户端DEFAULT_MAX_RETRIESis 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 统计每分钟总 token 数而 ITPM 与 OTPM 则分别单独计量输入 token 和输出 tokenOpenAI、Anthropic 等主流提供商对这四个维度设有独立配额使用 OpenRouter 或 ofox.io 等多后端网关时需了解网关是否会将这些计量指标分别透传以便准确判断触发了哪一层限制。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不计入 OTPMOTPM 是按实际产出的 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 是 HTTP 标准状态码表示客户端超出速率限制529 是部分服务商如 Anthropic在系统过载时返回的非标准码gRPC 体系中的RESOURCE_EXHAUSTED语义与 429 最为接近三者触发原因和重试策略存在差异OpenRouter 与 ofox.io 等网关层通常会将这些异构错误码归一化后再透传给调用方。代码厂商措辞谁的问题该怎么办429rate_limit_errorAnthropic、rate limit reachedOpenAI你账户的限额或计费读错误体然后等待或处理计费429RESOURCE_EXHAUSTEDGoogle Gemini你的配额RPM、TPM、RPD指数退避或申请配额529overloaded_errorAnthropic服务方容量所有人退避或故障转移到另一个模型503Service unavailable /UNAVAILABLE服务方容量退避后重试500api_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-limitshttps://platform.claude.com/docs/en/api/errorshttps://developers.openai.com/api/docs/guides/rate-limitshttps://developers.openai.com/api/docs/guides/error-codeshttps://ai.google.dev/gemini-api/docs/rate-limitshttps://ai.google.dev/gemini-api/docs/troubleshootinghttps://openrouter.ai/docs/api-reference/limits