上周用 Claude Opus 4.6 跑一个批量代码审查脚本,跑到第 30 条请求的时候,控制台开始疯狂刷 429 Too Many Requests。这个错我之前零星遇到过,但这次直接把整个流水线卡死了,排查加修复折腾了差不多一天半。把踩过的坑和最终方案记录下来,省得再走一遍。
Claude API 返回 429 错误,本质是触发了 Anthropic 的速率限制。解决方案有四种:调整请求频率加退避重试、申请更高 Tier 的速率配额、用令牌桶做客户端限流、或者换聚合 API 平台绕开单一供应商的限制瓶颈。 下面逐个讲怎么操作。
先说结论
| 方案 | 实现难度 | 见效速度 | 适合场景 |
|---|---|---|---|
| 指数退避重试 | ⭐ 低 | 即时 | 偶尔触发 429,请求量不大 |
| 申请提升 Rate Limit Tier | ⭐ 低 | 1-3 个工作日 | 长期高频调用,有充值记录 |
| 客户端令牌桶限流 | ⭐⭐ 中 | 即时 | 批量任务、脚本场景 |
| 换聚合 API 平台 | ⭐ 低 | 即时 | 不想折腾、多模型切换 |
为什么会触发 429
先搞清楚 Anthropic 的限流逻辑,不然瞎调参数没用。
Claude API 有三层限制同时生效:
- RPM(Requests Per Minute):每分钟请求次数
- TPM(Tokens Per Minute):每分钟 Token 吞吐量
- TPD(Tokens Per Day):每日 Token 总量上限
2026 年 Anthropic 的 Tier 体系大概是这样(具体数字以官方文档为准,这里列的是我账号实际看到的量级):
| Tier | RPM | TPM (输入) | TPM (输出) | 触发条件 |
|---|---|---|---|---|
| Tier 1(新号) | 50 | 40,000 | 8,000 | 注册即有 |
| Tier 2 | 1,000 | 80,000 | 16,000 | 充值 $40+ |
| Tier 3 | 2,000 | 160,000 | 32,000 | 充值 $200+ |
| Tier 4 | 4,000 | 400,000 | 80,000 | 充值 $1,000+ |
我那次翻车就是因为脚本没做任何限流,30 个并发请求一口气打上去,Tier 2 的 RPM 上限直接打满了。
429 响应头里会带 retry-after 字段,告诉你多少秒后可以重试。很多人不看这个字段直接疯狂重试,反而会被限得更狠。
sequenceDiagram
participant Client as 你的代码
participant API as Claude API
Client->>API: 请求 1-50(正常)
API-->>Client: 200 OK
Client->>API: 请求 51(超限)
API-->>Client: 429 Too Many Requests<br/>retry-after: 30
Note over Client: 不看 retry-after<br/>立即重试 ❌
Client->>API: 疯狂重试
API-->>Client: 429(限制加重)
Note over Client: 读取 retry-after<br/>等待后重试 ✅
Client->>API: 等待 30s 后重试
API-->>Client: 200 OK
方案一:指数退避重试(最基础,必须有)
不管你用哪种方案,这个都是兜底逻辑,必须加上。
import time
import anthropic
client = anthropic.Anthropic(api_key="your-key")
def call_claude_with_retry(prompt, max_retries=5):
for attempt in range(max_retries):
try:
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
return response
except anthropic.RateLimitError as e:
if attempt == max_retries - 1:
raise
# 优先读 retry-after 头
retry_after = getattr(e, 'response', None)
if retry_after and hasattr(retry_after, 'headers'):
wait_time = int(retry_after.headers.get('retry-after', 0))
else:
wait_time = 0
# 没有 retry-after 就用指数退避
if wait_time == 0:
wait_time = min(2 ** attempt * 1.5, 60) # 1.5s, 3s, 6s, 12s, 24s
print(f"429 了,第 {attempt + 1} 次重试,等 {wait_time:.1f}s")
time.sleep(wait_time)
return None
# 测试
result = call_claude_with_retry("用一句话解释什么是 Rate Limit")
if result:
print(result.content[0].text)
偶发的 429 基本第一次重试就过了,等 1-2 秒的事。但如果是持续高频调用,这个方案只是在拖时间,治标不治本。
踩坑点:anthropic SDK 从 0.39 版本开始,RateLimitError 的异常结构变了,老版本直接 catch APIStatusError 然后判 status code 才靠谱。建议先 pip install --upgrade anthropic 升到最新。
方案二:申请提升 Rate Limit Tier
如果确实需要高频调用,最正经的方式就是充钱升 Tier。
操作路径:Anthropic Console → Settings → Limits → 查看当前 Tier → 充值到对应门槛自动升级。
花钱解决问题,但有两个坑:
- 升 Tier 不是实时生效的,充完 $200 等了差不多 6 小时才看到 Tier 3 的配额生效
- Tier 4 以上需要人工审核,要填申请表说明用途,提交后等了 3 个工作日
方案三:客户端令牌桶限流(批量任务必备)
这是我最终在脚本里用的方案。原理很简单:在客户端主动控制请求速率,别等服务端拒绝你。
import time
import threading
from openai import OpenAI
class TokenBucketLimiter:
"""简易令牌桶限流器"""
def __init__(self, rpm=40):
"""
rpm: 每分钟最大请求数,建议设为实际限额的 80%
"""
self.rpm = rpm
self.interval = 60.0 / rpm # 每次请求的最小间隔
self.lock = threading.Lock()
self.last_request_time = 0
def wait(self):
with self.lock:
now = time.time()
elapsed = now - self.last_request_time
if elapsed < self.interval:
sleep_time = self.interval - elapsed
time.sleep(sleep_time)
self.last_request_time = time.time()
# 用 OpenAI 兼容接口调用 Claude(方便切换不同平台)
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1" # 聚合接口,一个 Key 调所有模型
)
limiter = TokenBucketLimiter(rpm=40) # Tier 1 限 50,留 20% 余量
def batch_review(code_snippets):
results = []
for i, code in enumerate(code_snippets):
limiter.wait() # 自动控制速率
try:
response = client.chat.completions.create(
model="claude-sonnet-4-20250514",
messages=[
{"role": "system", "content": "你是一个代码审查助手"},
{"role": "user", "content": f"审查这段代码:\n```\n{code}\n```"}
],
max_tokens=512
)
results.append({
"index": i,
"review": response.choices[0].message.content,
"status": "ok"
})
print(f"[{i+1}/{len(code_snippets)}] 完成")
except Exception as e:
results.append({
"index": i,
"review": None,
"status": f"error: {e}"
})
print(f"[{i+1}/{len(code_snippets)}] 失败: {e}")
return results
# 模拟 50 个代码片段的批量审查
snippets = [f"def func_{i}():\n return {i} * 2" for i in range(50)]
results = batch_review(snippets)
success = sum(1 for r in results if r["status"] == "ok")
print(f"\n完成:{success}/{len(snippets)} 成功")
50 个请求跑下来零 429,总耗时约 75 秒(RPM=40 的话平均 1.5s 一个请求)。比之前不限流然后疯狂重试反而快——之前那种方式跑 50 个请求要 3 分多钟,重试等待的时间累积起来很夸张。
方案四:用聚合 API 绕开单一供应商瓶颈
这是我现在的日常方案。
原理不复杂:聚合平台后面挂了多个供应商节点(Azure、Bedrock、VertexAI 等),请求会被分发到不同节点,相当于把流量天然打散了,单一节点的 Rate Limit 很难被触发。
ofox.ai 是一个 AI 模型聚合平台,一个 API Key 可以调用 Claude Opus 4.6、GPT-5、Gemini 3、DeepSeek V3 等 50 多个模型,低延迟直连无需代理,支持支付宝付款。它后面有多供应商冗余备份,实测高频调用下 429 的概率比直连 Anthropic 官方低很多。
改造成本极低,就改一行 base_url:
from openai import OpenAI
# 官方直连(容易 429)
# client = OpenAI(api_key="sk-ant-xxx", base_url="https://api.anthropic.com/v1")
# 换聚合平台(改这一行就行)
client = OpenAI(
api_key="your-ofox-key",
base_url="https://api.ofox.ai/v1"
)
response = client.chat.completions.create(
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "解释一下 429 状态码"}],
max_tokens=256
)
print(response.choices[0].message.content)
用同样的批量脚本(50 个请求,不加任何限流)测了一下,全部 200,零 429。当然聚合平台也有限制,只是阈值高很多,日常开发基本碰不到。
踩坑记录
坑 1:并发 + 重试 = 雪崩
一开始用 asyncio 开了 10 个并发,每个协程各自有重试逻辑。结果 429 一触发,10 个协程同时等 retry-after 秒,然后同时重试,又同时 429……来回震荡了好几轮。解决办法是重试时加随机抖动(jitter):
import random
wait_time = min(2 ** attempt * 1.5, 60) + random.uniform(0, 1)
坑 2:Streaming 模式下 429 的表现不同
非 Streaming 模式 429 会直接抛异常,但 Streaming 模式下有时候连接能建立,前几个 chunk 能收到,然后中途断掉抛 APIConnectionError。一开始没把这个归类到限流问题,排查了半天以为是网络问题。
坑 3:不同模型的 Rate Limit 是独立的
Claude Opus 4.6 和 Claude Sonnet 4.6 的 RPM 限制是分开算的。混合调用不同模型时,别按总量算限流,要按模型分别算。
小结
四种方案怎么选,看场景:
- 偶尔 429:方案一(指数退避)就够了,几行代码的事
- 长期高频调:方案二(升 Tier)+ 方案三(客户端限流)组合用
- 不想折腾、多模型切换:方案四(聚合平台),改一行
base_url搞定 - 最佳实践:方案三 + 方案四叠加,客户端限流兜底,聚合平台扛峰值
我现在就是方案三和方案四叠着用,跑了两周批量任务再没遇到过 429。