大数跨境

大模型API频繁出现429怎么办?从限流机制到重试策略完整解析

大模型API频繁出现429怎么办?从限流机制到重试策略完整解析 香港文匯報
2026-08-21
28
导读:大模型API频繁出现429怎么办?从限流机制到重试策略完整解析

调用GPT、Claude、Gemini、DeepSeek等大模型API时,429是生产环境里很常见、也最容易被错误处理的一类状态码。

很多开发者看到429 Too Many Requests后的第一反应是“请求发太快了”,于是直接在代码里加一句重试。测试阶段这样做可能暂时有效,但到了并发量较高的业务中,无限制重试反而可能造成新的问题:原本只是短时间触发限流,几十个工作线程同时重试之后,请求量瞬间翻倍,最终形成重试风暴,把一个局部429放大成整个服务不可用。

因此,大模型API出现429时,正确处理方式不是简单“多重试几次”,而是先判断到底触发了哪一种限制,再决定是等待、减少并发、压缩Token、切换模型还是调整额度。

一、429不只是“请求数量太多”
HTTP 429通常表示当前请求超过了服务允许的使用速率或配额,但对大模型API来说,“速率”并不只有请求次数一个维度。

目前主流模型平台常见的限制至少包括:

限制类型    含义    常见触发场景
RPM    Requests Per Minute,每分钟请求数    大量短请求并发
TPM    Tokens Per Minute,每分钟Token量    长Prompt、大批量上下文
RPD    Requests Per Day,每日请求量    免费额度或低层级账号
并发限制    同时处理中的请求数量    Agent、批量任务、异步队列
账户/项目配额    项目、组织或账户级资源限制    多个Key共享同一项目额度
消费额度    单位时间内允许消耗的金额    大上下文、高价格模型集中调用
以Gemini API为例,其官方文档明确将RPM、TPM和RPD作为常见限流维度,任何一个维度超过限制都可能触发429;部分账户还存在消费速率限制。

所以看到429时,第一个需要改变的思路是:

429并不等于请求数量太多,也可能是Token太多、项目配额耗尽或者短时间资源消耗过高。

这也是为什么单纯降低HTTP请求频率,有时仍然无法解决429。

二、先判断自己触发的是RPM还是TPM
假设一个接口限制为:

RPM = 60
TPM = 100,000
用码道免费领 1 个月 Token
text
1
2
第一种业务每分钟发送50次请求,每次只有500 Token:

50 × 500 = 25,000 Token/min
用码道免费领 1 个月 Token
text
1
这种情况下:

RPM:50 / 60
TPM:25,000 / 100,000
用码道免费领 1 个月 Token
text
1
2
两个指标都没有超过上限。

但如果请求数量仍然是50次,每次Prompt突然扩大到3000 Token:

50 × 3000 = 150,000 Token/min
用码道免费领 1 个月 Token
text
1
此时请求次数并没有增加,却已经超过TPM限制。

另一种情况正好相反。

如果每个请求只有100 Token,但一分钟发送100次:

RPM:100 / 60
TPM:10,000 / 100,000
用码道免费领 1 个月 Token
text
1
2
触发的是RPM。

因此,大模型API限流最好按照两个维度同时观察:

请求压力 ≠ 只看QPS

实际压力 =
请求次数
+
输入Token
+
输出Token
+
并发持续时间
用码道免费领 1 个月 Token
text

1
2
3
4
5
6
7
8
9
10
尤其是RAG、长对话和Agent场景中,一个请求可能携带几万甚至几十万Token,此时TPM往往比RPM更容易成为瓶颈。

三、429出现后,先看错误信息和响应头
成熟的API客户端不应该只记录:

HTTP 429
用码道免费领 1 个月 Token
text
1
而应该尽量同时记录:

timestamp
model
request_id
status_code
error_type
retry_after
remaining_requests
remaining_tokens
prompt_tokens
completion_tokens
latency
用码道免费领 1 个月 Token
text

1
2
3
4
5
6
7
8
9
10
11
OpenAI当前API参考文档中列出了包括:

x-ratelimit-limit-requests
x-ratelimit-limit-tokens
x-ratelimit-remaining-requests
x-ratelimit-remaining-tokens
x-ratelimit-reset-requests
x-ratelimit-reset-tokens
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
等限流相关响应头,并建议生产环境记录请求ID用于故障排查。

这些信息可以帮助判断:

到底是“请求次数快用完了”,还是“Token额度快用完了”。

不同服务的响应字段并不完全一致,因此实际接入第三方模型或API网关时,最好先查看其错误响应结构,不要假设所有429都完全按照OpenAI的Header返回。

四、为什么固定等待1秒再重试并不是好办法
一种很常见的写法是:

try:
    call_api()
except RateLimitError:
    time.sleep(1)
    call_api()
用码道免费领 1 个月 Token
python
运行
1
2
3
4
5
单用户脚本问题不大,但高并发系统中存在明显缺陷。

假设现在有100个请求同时触发429。

所有线程都等待:

1秒
用码道免费领 1 个月 Token
text
1
然后又在几乎同一时间重新发送。

流量会变成:

第一次:
████████████████████████

等待1秒

第二次:
████████████████████████
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
第二轮依然形成流量尖峰,于是继续429。

这就是典型的同步重试问题。

生产环境更适合使用:

指数退避(Exponential Backoff)+ 随机抖动(Jitter)

五、指数退避的核心不是“越等越久”,而是打散流量
指数退避可以简单表示为:

delay = base × 2^attempt
用码道免费领 1 个月 Token
text
1
例如:

第一次失败:1秒
第二次失败:2秒
第三次失败:4秒
第四次失败:8秒
用码道免费领 1 个月 Token
text
1
2
3
4
但只采用指数退避仍然有一个问题:

所有请求如果同时失败,它们仍然可能:

一起等1秒
一起重试

一起等2秒
一起重试

一起等4秒
一起重试
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
8
因此还需要增加Jitter。

例如使用Full Jitter:

delay = random(0, min(cap, base × 2^attempt))
用码道免费领 1 个月 Token
text
1
这样100个请求下一次发送时间会自然散开。

可能变成:

请求A:0.3秒
请求B:0.8秒
请求C:1.1秒
请求D:1.7秒
请求E:2.4秒
用码道免费领 1 个月 Token
text
1
2
3
4
5
从而避免瞬间重新冲击上游接口。

Gemini官方错误处理文档目前也建议在出现rate_limit_exceeded以及部分503场景时等待并采用指数退避重试。

六、Python中可以这样实现429重试
如果使用OpenAI兼容SDK,可以自己实现一层重试控制。

例如:

import asyncio
import random
import os

from openai import AsyncOpenAI, RateLimitError

client = AsyncOpenAI(
    api_key=os.environ["AI_API_KEY"],
    base_url=os.environ["AI_BASE_URL"],
    max_retries=0
)

semaphore = asyncio.Semaphore(8)


async def call_model(prompt, max_retries=4):
    for attempt in range(max_retries + 1):

        try:
            async with semaphore:
                response = await client.chat.completions.create(
                    model=os.environ["AI_MODEL"],
                    messages=[
                        {
                            "role": "user",
                            "content": prompt
                        }
                    ]
                )

            return response

        except RateLimitError as e:

            if attempt >= max_retries:
                raise

            retry_after = None

            if e.response is not None:
                retry_after = e.response.headers.get("retry-after")

            if retry_after:
                delay = float(retry_after)

            else:
                cap = min(30, 2 ** attempt)
                delay = random.uniform(0, cap)

            print(
                f"429触发,第{attempt + 1}次重试,"
                f"{delay:.2f}秒后再次请求"
            )

            await asyncio.sleep(delay)
用码道免费领 1 个月 Token
python
运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
这里有几个重要设计。

1. 设置最大重试次数
max_retries=4
用码道免费领 1 个月 Token
python
运行
1
意味着请求不能无限重试。

如果连续失败超过阈值,就应该让异常向上层传播,由业务决定:

返回错误;
进入队列;
切换备用模型;
延迟任务;
人工处理。
2. 优先尊重Retry-After
如果服务端明确告诉客户端:

Retry-After: 5
用码道免费领 1 个月 Token
text
1
就不应该自己猜:

1秒后再试
用码道免费领 1 个月 Token
text
1
而是优先按照服务端提示执行。

3. 增加Semaphore
这里:

asyncio.Semaphore(8)
用码道免费领 1 个月 Token
python
运行
1
代表最多允许8个任务同时进入API请求阶段。

它解决的是:

不要让业务自身无限制造并发。

需要注意,8只是演示值,不是所有项目都应该使用8。

真正的并发上限应该根据:

模型容量
平均响应时间
RPM
TPM
任务长度
业务峰值
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
综合测试确定。

七、使用OpenAI SDK时,要注意“SDK已经自动重试”
还有一个很容易被忽略的问题。

OpenAI当前Python SDK默认会对包括429在内的部分错误自动重试两次,并采用短指数退避;可以通过max_retries修改这一行为。

这意味着,如果业务层又写了:

业务层重试5次
用码道免费领 1 个月 Token
text
1
同时SDK内部:

每次再自动重试2次
用码道免费领 1 个月 Token
text
1
真正产生的请求数量可能远超开发者预期。

例如理论上一次业务请求:

初始请求
+
业务重试4次
用码道免费领 1 个月 Token
text
1
2
3
看起来最多5轮。

但每一轮底层又可能发生SDK自动重试。

结果就容易出现:

业务重试
    ↓
SDK重试
    ↓
HTTP客户端重试
    ↓
API网关重试
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
形成多层嵌套。

所以生产系统最好明确:

到底由哪一层负责重试。

如果自己已经实现统一重试策略,可以考虑关闭SDK自动重试,例如:

client = AsyncOpenAI(
    api_key=os.environ["AI_API_KEY"],
    base_url=os.environ["AI_BASE_URL"],
    max_retries=0
)
用码道免费领 1 个月 Token
python
运行
1
2
3
4
5
避免出现“看起来只重试3次,实际发出了十几次请求”的情况。

八、真正危险的是重试风暴
假设正常情况下系统有:

100 req/s
用码道免费领 1 个月 Token
text
1
突然上游开始返回429。

如果每个失败请求立即重试一次:

原始流量:100 req/s
重试流量:100 req/s
用码道免费领 1 个月 Token
text
1
2
上游实际收到:

200 req/s
用码道免费领 1 个月 Token
text
1
如果再次失败继续重试:

100
+100
+100
...
用码道免费领 1 个月 Token
text
1
2
3
4
很快就会形成恶性循环。

典型表现是:

429增加

重试增加

请求量进一步增加

429进一步增加

线程和连接池被占满

正常请求也开始超时

整个业务雪崩
用码道免费领 1 个月 Token
text

1
2
3
4
5
6
7
8
9
10
11
12
13
因此429治理实际上属于系统稳定性问题,而不仅仅是HTTP错误处理问题。

九、生产系统最好增加“重试预算”
比“最多重试3次”更进一步的方式,是设置Retry Budget。

例如规定:

每分钟正常请求:10,000次

允许额外重试:
不超过正常流量的10%
用码道免费领 1 个月 Token
text
1
2
3
4
也就是:

最多1,000次额外Retry
用码道免费领 1 个月 Token
text
1
一旦超过预算:

停止继续重试
用码道免费领 1 个月 Token
text
1
然后进入:

降级
排队
备用模型
返回稍后重试
用码道免费领 1 个月 Token
text
1
2
3
4
这种做法的目的,是防止:

失败流量反过来压垮正常流量。

对于Agent尤其重要。

因为一个用户请求可能触发:

主模型调用

Tool Calling

搜索

模型再次推理

工具结果总结
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
8
9
一次用户请求背后可能已经对应5—10次API调用。

如果每一层都独立重试,流量放大倍率会非常高。

十、减少429不能只靠重试,还要从请求本身减压
有些429本质上是TPM问题。

例如:

100个请求 × 20,000 Token
用码道免费领 1 个月 Token
text
1
这种情况下即使请求数量不高,也会产生:

2,000,000 Token
用码道免费领 1 个月 Token
text
1
如果TPM容量不足,依然会持续429。

这时更有效的方法不是“等两秒”。

而是减少Token。

例如:

1. 对历史消息进行裁剪
不要每轮聊天都发送完整历史。

2. RAG限制召回数量
例如:

Top-K = 20
用码道免费领 1 个月 Token
text
1
不一定比:

Top-K = 5
用码道免费领 1 个月 Token
text
1
效果更好,却会显著扩大Prompt。

3. 对长资料提前摘要
把:

50,000 Token原始资料
用码道免费领 1 个月 Token
text
1
变成:

5,000 Token结构化摘要
用码道免费领 1 个月 Token
text
1
再参与高频请求。

4. 限制最大输出长度
如果业务实际只需要:

300 Token回答
用码道免费领 1 个月 Token
text
1
就没有必要允许模型每次生成:

5,000 Token
用码道免费领 1 个月 Token
text
1
因此处理TPM型429,本质上属于:

Token预算管理。

十一、什么时候应该切换备用模型?
并不是出现一次429就立即Fallback。

否则会产生另一个问题:

主模型429

备用模型

备用模型429

第三模型

所有模型同时被冲击
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
8
9
比较合理的策略可以是:

第一次429
→ 等待Retry-After

第二次429
→ 指数退避

连续达到阈值
→ 判断是否允许Fallback

Fallback仍失败
→ 进入队列或返回可恢复错误
用码道免费领 1 个月 Token
text

1
2
3
4
5
6
7
8
9
10
11
而且备用模型必须满足任务要求。

例如:

主模型:
长上下文推理模型

备用模型:
低成本轻量模型
用码道免费领 1 个月 Token
text
1
2
3
4
5
如果当前任务需要复杂代码修改,那么即使备用模型接口正常,也不一定适合作为直接替代。

所以真正的Fallback应该维护的是:

模型能力映射
用码道免费领 1 个月 Token
text
1
而不只是:

model_A → model_B
用码道免费领 1 个月 Token
text
1
十二、多模型统一接口可以降低Fallback的工程复杂度
如果业务同时直连多家官方模型,Fallback逻辑可能类似:

OpenAI SDK
Claude SDK
Gemini SDK
DeepSeek接口
Kimi接口
Qwen接口
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
每一层还需要分别处理:

鉴权
Endpoint
错误结构
模型名称
返回格式
重试策略
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
一旦开始设计模型降级,复杂度会明显增加。

一种常见的工程做法,是在业务和模型供应商之间增加统一API层:

业务
  ↓
限流器
  ↓
重试控制
  ↓
统一模型API
  ↓
GPT / Claude / Gemini / DeepSeek / Kimi / Qwen
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
7
8
9
根据4SAPI现有产品资料,其定位就是多模型API中转与统一管理平台,覆盖OpenAI、Claude、Gemini、DeepSeek、Kimi、Qwen、GLM等主流模型,并提供OpenAI兼容接口。

因此,对于已经基于OpenAI SDK开发的应用,可以把不同模型配置为应用层候选模型,在统一调用结构下实现自己的Fallback逻辑。

例如:

MODELS = [
    "PRIMARY_MODEL",
    "BACKUP_MODEL"
]

for model in MODELS:

    try:
        response = await call_model(
            model=model,
            prompt=user_prompt
        )

        return response

    except RateLimitError:
        continue

raise RuntimeError("当前所有候选模型暂时不可用")
用码道免费领 1 个月 Token
python
运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
实际生产环境还应该加入:

任务类型判断
错误类型判断
重试次数
模型能力
成本
延迟
用码道免费领 1 个月 Token
text
1
2
3
4
5
6
而不是无条件轮询模型。

这里统一API入口的价值不是让429“消失”,而是:

让限流、Fallback和模型切换逻辑更容易集中管理。

十三、429发生时,可以按照这套顺序排查
如果线上已经出现429,可以按照以下顺序处理。

第一步:确认429来源
判断是:

模型厂商
API服务层
网关
还是自己应用的限流器
用码道免费领 1 个月 Token
text
1
2
3
4
第二步:查看错误Body和Header
重点寻找:

rate_limit
quota
retry_after
remaining
reset
用码道免费领 1 个月 Token
text
1
2
3
4
5
等信息。

第三步:判断限制维度
区分:

RPM
TPM
并发
日配额
账户额度
用码道免费领 1 个月 Token
text
1
2
3
4
5
第四步:检查应用是否存在瞬时尖峰
不要只看一分钟平均值。

例如:

一分钟600次请求
用码道免费领 1 个月 Token
text
1
平均只有:

10 req/s
用码道免费领 1 个月 Token
text
1
但实际情况可能是:

前5秒发送500次
后55秒发送100次
用码道免费领 1 个月 Token
text
1
2
平均值看起来正常,瞬时流量却已经非常高。

第五步:检查是否存在嵌套重试
确认:

SDK
业务代码
代理层
任务队列
API网关
用码道免费领 1 个月 Token
text
1
2
3
4
5
是否同时在重试。

第六步:再决定解决方式
原因    更适合的处理方法
RPM过高    限速、排队、平滑流量
TPM过高    缩短Prompt、减少上下文
瞬时并发过高    Semaphore、队列、背压
临时限流    Retry-After + 指数退避
长期容量不足    提升额度或调整架构
单模型容量不足    合理Fallback
免费配额耗尽    等待恢复或调整使用层级
十四、一个更完整的429处理架构
对于已经进入生产环境的大模型应用,可以考虑:

用户请求
   ↓
任务队列
   ↓
并发控制
   ↓
Token预算检查
   ↓
API调用
   ↓
成功 ─────────→ 返回结果
   ↓
429
   ↓
读取Retry-After
   ↓
指数退避 + Jitter
   ↓
是否超过Retry Budget?
   │
   ├─ 否 → 重试
   │
   └─ 是
        ↓
   是否存在合适备用模型?
        │
   ┌────┴────┐
   是        否
   ↓         ↓
Fallback    延迟队列/返回可恢复错误
用码道免费领 1 个月 Token
text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
这套思路比:

while True:
    retry()
用码道免费领 1 个月 Token
python
运行
1
2
更加适合长期运行的API服务。

十五、FAQ:大模型API 429常见问题
1. 429是不是代表API服务挂了?
不是。429主要表示当前请求触发了某种限流或配额规则。服务不可用更常见的是5xx错误,例如503。Gemini当前官方错误说明也将429与503分别定义为限流和服务不可用两类问题。

2. 429后应该等待多久?
优先读取服务端提供的Retry-After或对应Reset信息。如果没有明确提示,再使用指数退避并增加随机抖动,不建议所有请求固定等待相同时间。

3. 多申请几个API Key能解决429吗?
不一定。许多模型平台的额度是按照账户、项目或组织计算,而不是单个Key。Gemini例如明确说明部分限流按项目计算,因此创建更多Key并不会自动增加该项目的整体额度。

4. 为什么并发不高仍然出现429?
可能触发的是TPM、每日配额或消费额度,而不是RPM。需要结合Token数量和账户额度一起判断。

5. API中转站能够彻底避免429吗?
不能。只要底层资源存在容量或配额限制,任何调用链都可能出现限流。统一API层的主要价值在于集中模型接入、错误处理和Fallback管理,而不是保证永远不会出现429。

6. 429应该重试多少次?
不存在适用于所有业务的固定数字。实时聊天通常应该控制较少的重试次数,批处理任务可以允许更长等待。更合理的方式是同时设置最大重试次数、最大等待时间和Retry Budget。

结语
大模型API出现429时,真正需要解决的问题并不是“怎么让这一条请求重新成功”,而是:

怎样让整个系统在模型容量不足时仍然保持稳定。

先区分RPM、TPM、并发和账户配额,再结合Retry-After、指数退避、Jitter、并发控制和Retry Budget处理,大多数429问题都会比简单无限重试更容易管理。

如果应用本身已经需要同时使用GPT、Claude、Gemini、DeepSeek、Kimi、Qwen等多个模型,也可以使用4SAPI这样的统一API入口创建独立测试Key,用固定并发脚本分别测试不同模型的429表现、响应延迟和错误处理,再根据业务实际容量设计自己的限流和Fallback策略。

真正上线前,建议不要只测试“能不能调用”,而要主动把系统压到出现429,然后观察它能不能平稳恢复。这才是API稳定性测试真正有价值的部分。

【声明】内容源于网络
香港文匯報
《香港文汇报》是由香港文汇报社主办的繁体中文日报,创刊于1948年9月9日。
内容 8934
粉丝 0
认证用户
香港文匯報 香港文汇报有限公司广西办事处 《香港文汇报》是由香港文汇报社主办的繁体中文日报,创刊于1948年9月9日。
总阅读251.9k
粉丝0
内容8.9k