跳到主要内容
Router One
返回博客

LLM API 429 限流报错:三种成因与对症修法

发布修订作者Router One 团队方法说明

HTTP 429 是 LLM API 里信息量最低的报错:三种本质完全不同的故障共用这一个状态码,而三种故障的修法各不相同。重试代码只能修其中一种;对第二种,重试只是推迟必然的失败;对第三种,重试纯属浪费。这篇是错误码速查页背后的 429 深挖:怎么分辨你撞上的是哪一种,唯一值得重试的那种该怎么写生产级重试,以及让 429 从源头减少的结构性改法。

一个状态码,三种故障

实际发生了什么限制在哪一层修法
上游供应商限流(RPM/TPM 超限)模型厂商的基础设施有上限的指数退避 + 抖动;有 Retry-After 就照做
网关对 Key 或账户的限额Key 的 rateLimit / tokenLimitTpm,或账户共享的限额,由 X-RateLimit-Scope 指明分散或隔离负载,或申请调高限额——退避只能让你在限额以下排队
OpenAI 的 insufficient_quota官方 OpenAI API 的账单账户解决账单问题;重试毫无意义

误判方向的代价是双向的。把网关限额当作会自行消散的上游问题,你会写出一套对着永远不动的天花板反复冲撞的重试逻辑;把 insufficient_quota 当瞬时限流,你会对着一个没有余额的账户白白重试几个小时。

成因一:上游供应商在限流

模型厂商都有每分钟请求数和每分钟 token 数的上限,负载高峰时还会主动用 429(以及 Anthropic 风格的 529 过载响应)甩流量——哪怕你自己的请求频率没变。这是唯一一种客户端重试算对症下药的情况,但必须是有边界的重试,三个要素缺一不可:

  • 带上限的指数退避。 每次失败等待时间翻倍,但要有封顶——不封顶的话,第五次重试可能为一个几秒就恢复的限流干等几分钟。
  • 抖动(jitter)。 每次延迟加随机量。没有抖动,同一批失败的客户端会在同一时刻集体重试,同步的重试波会再次触发限流。
  • 放弃路径。 固定次数之后把错误抛出去。无限循环不是韧性,是一队越攒越陈旧的任务。

响应里带 Retry-After 头时照做——服务端已经明确告诉你容量什么时候恢复,这时还用退避去猜只会拖长故障时间。下面是 Python 版本,用标准 OpenAI 客户端指向 Router One:

import os
import random
import time

from openai import OpenAI, RateLimitError

client = OpenAI(
    base_url="https://api.router.one/v1",
    api_key=os.environ["ROUTER_ONE_API_KEY"],
)

MAX_ATTEMPTS = 5
BASE_DELAY = 1.0  # 秒
MAX_DELAY = 30.0  # 封顶:最长等这么久


def chat_with_backoff(**kwargs):
    for attempt in range(1, MAX_ATTEMPTS + 1):
        try:
            return client.chat.completions.create(**kwargs)
        except RateLimitError as err:
            if attempt == MAX_ATTEMPTS:
                raise  # 放弃路径:抛出错误,不要无限循环

            retry_after = err.response.headers.get("retry-after")
            if retry_after is not None:
                # 服务端已明确说了容量何时恢复——不需要抖动
                time.sleep(min(float(retry_after), MAX_DELAY))
            else:
                delay = min(BASE_DELAY * 2 ** (attempt - 1), MAX_DELAY)
                # full jitter:把同步失败的客户端错开
                time.sleep(random.uniform(0, delay))


response = chat_with_backoff(
    model="openai/gpt-5.5",
    messages=[{"role": "user", "content": "ping"}],
)

五次尝试、30 秒封顶、带抖动的延迟、尊重 Retry-After、最后干净地失败。整个模式就这些——忍住别把它写得更"聪明"。

成因二:撞上了网关对 Key 或账户的限额

每把 Router One API Key 都有每分钟请求数限额(rateLimit)和每分钟 token 限额(tokenLimitTpm),同一账户的所有 Key 还共享账户级的请求与 token 限额,其中包括单个模型的请求限额。这些限额按平台默认值生效——正常付费使用不设低额度固定上限——作用是不让泄漏的 key 或失控的循环把整个账户的吞吐打满。它们和 maxSpend 不同:消费硬上限由你在 Dashboard → API Keys 里按 Key 设置,而吞吐限额不在控制台修改。每客户一把 key 的转售模式依靠的是按 Key 的消费上限,吞吐限额在它下面兜底。

识别特征:响应会点名是哪一种限额。网关返回的 429 带 X-RateLimit-Scope——api_key 是这把 Key 的限额,subject 是整个账户的限额,subject_model 是账户在单个模型上的限额——同时带 X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetRetry-After;错误码为 RATE_LIMIT_EXCEEDED(请求数)或 TOKEN_QUOTA_EXCEEDED(每分钟 token 数)。这类 429 是确定性的:不管几点,都在同一个频率上复现。每分钟 token 限额在请求开始时按估算值(提示词长度加 max_tokens)计入,结算后再按实际用量修正,所以一批大提示词可能在实际用量达到之前先触到它。(如果 key 停摆时报的是 402,那是 maxSpend 上限或钱包余额的问题——钱的事,不是速度的事,速查页写了两者的区别。)

申请调高之前先问一句:为什么会撞上?如果是某个后台任务把生产流量共用的 key 打满了,更好的修法是再开一把 key,把吵闹的负载隔离出去、单独可见——但同一账户的 Key 仍共享账户级限额。负载确实需要更高吞吐时——压测、批量回填、中转站的汇总流量——Key 与账户限额都可以申请调高:发邮件到 support@router.one,写明账户 ID、Key、模型,以及预计峰值的每分钟请求数与 token 数。网关限额之上仍受上游容量约束。

成因三:insufficient_quota——套着 429 外衣的账单问题

如果你直连官方 OpenAI API,错误体里写着 insufficient_quota,请立刻停止重试。状态码虽然是 429,但它跟限流毫无关系:你的预付账单额度用光了,这个"限制"不会在几秒、几分钟后重置——账单不动它永远不动。每一次重试都是白打的请求,退避只是让你浪费得慢一点。

这个报错来自 OpenAI 平台,不是网关。insufficient_quota 修复指南完整讲了成因和解决路径,包括绑了支付方式但额度依然为零的情况。

怎么判断撞上的是哪一种

靠客户端症状猜不可靠,请求 Trace 才可靠。在 Router One 上,Dashboard → Logs 展示每个请求的最终记录——状态、模型、Token、花费、延迟与请求 ID——可按模型和时间范围过滤。诊断归结为三步:

  1. 先读错误体。 insufficient_quota 会自报家门。看到这个字符串就是账单问题——走成因三。
  2. 再读 X-RateLimit-Scope api_keysubjectsubject_model 就是成因二——网关对 Key 或账户的限额,X-RateLimit-Limit 告诉你天花板在哪;upstream_provider 指向成因一。
  3. 最后看模式。 上游限流(成因一)是突发的、和负载高峰相关——429 集中在特定时间窗,然后自行消散。网关限额则是平直、可预测的。

同一份每请求记录还能回答后续问题——那段故障窗口的重试白烧了多少 token——这就进入成本追踪的范畴了。

重试风暴:天真的重试如何把限流越搞越糟

限流是系统满载的信号。天真的响应——立刻重试、无限重试——把这个信号变成了放大器:每个被拒的请求变成两个,再变成四个,总到达率恰好在系统最需要降压的时刻不断爬升。这就是重试风暴,它能把服务在原始高峰早已过去之后继续按在水下。有上限的尝试次数和抖动(见上)是重试侧的防御。

结构性的修法是并发整形:用信号量或固定 worker 池限制同时在途的请求数,而不是每条任务起一个并发、让退避去收拾残局。8 个 worker 消化 10,000 条任务的队列,产生的是一条平稳可预测、天然低于限流线的请求速率;同样 10,000 条任务一次性并发发出,得到的是一堵 429 墙加一波同步重试潮。退避是安全带,并发上限才是把车速控制在能活命的区间。

网关故障转移在哪一层帮上忙

走 Router One 调用,在错误到达你之前多了一层:符合条件的 429 或 529,在存在另一个提供同一请求模型的健康供应商时,可以在那条路由上重试。限定词很重要——并非每个 429 都可重试(网关对 Key 或账户的限额、insufficient_quota 这类账单故障都不在候选之列),故障转移也不是零停机保证:没有兼容路由完成请求时,应用仍会收到错误。所以客户端的退避循环无论如何都要保留;故障转移的判定逻辑另有专页。

至于 Router One 自己的限流口径:正常付费用量没有低固定上限——但滥用防护、账户级保护限制和上游约束仍然存在。如果正当的负载撞上了天花板,那是找支持团队聊的事,不是架构问题。

常见问题

怎么判断 429 来自我的 Key 限额还是上游供应商? 读 X-RateLimit-Scope 响应头。api_key、subject 或 subject_model 表示网关对这把 Key、整个账户或账户在单个模型上的限额,错误码为 RATE_LIMIT_EXCEEDED 或 TOKEN_QUOTA_EXCEEDED;upstream_provider 表示模型厂商的限制。上游 429 是突发的、跟负载高峰相关、会自行消散;网关限额则在同一频率上确定性地复现。Dashboard → Logs 里能看到每个请求的状态和时间。

每个 429 都应该重试吗? 不。只有限制真的会重置的情况——上游限流——才值得用有上限的指数退避加抖动去重试。网关限额每分钟重置,按 Retry-After 节奏重试可以排队通过,但持续高于限额的流量会一直失败,直到负载降下来或限额调高;OpenAI 的 insufficient_quota 是账单额度耗尽,任何重试节奏都填不回余额。

Router One 会对我的请求加自己的限流吗? 正常付费用量没有低固定上限,但每把 Key 和每个账户都按默认的每分钟请求数与 token 数限流,上游供应商约束也仍会生效。这些限额不在控制台修改,可以发邮件到 support@router.one 申请调高,写明账户 ID、Key 和预计峰值流量。

只做指数退避够吗? 必要但不结构性。退避处理的是单个失败请求,拦不住一个无界批量任务从源头制造 429。用信号量或固定 worker 池限制在途并发,让总请求速率从构造上就低于限流线,退避留作安全网。

网关故障转移能让 429 彻底消失吗? 不能。符合条件的 429 或 529 在存在另一个提供同一请求模型的健康供应商时可以重试,这能吸收相当一部分上游限流事件——但并非每个 429 都可重试,这也不是零停机保证。应用仍应准备好用有上限的退避处理最终返回的 429。

排查清单

429 出现时:先读错误体(insufficient_quota 等于账单问题),再读 X-RateLimit-Scope(网关对 Key 或账户的限额——分散负载,或申请调高),最后才当作真正的上游限流处理——有上限的退避加抖动、尊重 Retry-After、并发封顶。其余状态码见错误码速查页,Key 与响应头的完整说明见 API 文档。换一个 base URL,你就有了让诊断从猜测变成查表的请求 Trace。

相关权威页面

这篇文章归入「LLM API 网关与路由」主题,以下页面作为商业页、配置文档、证据页和信任事实源。

商业主页面Router One API 网关承接统一模型调用、路由、fallback、预算和观测的产品首页。API 文档Router One API 文档OpenAI 兼容端点、CLI 配置和模型调用示例。证据页智能路由方法论路由信号、模型与请求 ID,以及客户侧 trace 的字段边界。对比页OpenRouter 替代方案专业对比全球模型目录与中国友好路由、支付能力的差异。信任页可引用事实表面向搜索爬虫、AI 答案引擎和客户的稳定事实源。数据留存数据留存政策prompt/completion 留存边界和请求元数据政策。网关页面统一 LLM API 网关一个 OpenAI 兼容端点接入整个模型目录,含路由、fallback 与预算控制。路由页面智能模型路由候选排序如何使用延迟、公示成本与可靠性信号。故障转移页面LLM 供应商故障转移什么样的请求才符合在另一条健康供应商路由上重试的条件。可观测页面逐请求 Trace 日志每个请求的模型与请求 ID、Token、延迟、状态与报错。兼容性页面OpenAI 兼容端点沿用 OpenAI SDK,只改 base URL 即可触达各个模型系列。成本追踪页面LLM 成本追踪按 Key、按模型、按请求的花费归因,配合硬性消费上限。转售方页面在 Router One 上搭你自己的 API 服务带消费上限的客户 Key、按 Key 的用量归因,以及明确的「不提供」清单。客户端接入SDK 与客户端配置指南把任意编程 agent、SDK、聊天客户端或 LLM 应用平台指向同一个端点,每个都有专属指南。模型对比模型价格与上下文两两对比每百万 token 单价、上下文窗口与能力,渲染自实时模型目录。

相关阅读