如果你在调用 Claude API 时遭遇 HTTP 429 Too Many Requests,或者并发批量任务跑到一半就开始失败,本文是你需要的完整工程化手册。
本文基于 Anthropic 官方文档(docs.anthropic.com,截至 2026-06-30)梳理了 Claude API 的三维限流机制,给出可直接复用的 Python / Node.js 重试代码,并结合 Claude API 价格与模型层级 提供模型分层调度建议,适合正在生产环境接入或优化 Claude API 吞吐量的开发者。
ClaudeAPI 为独立第三方技术服务商。Claude、Anthropic 等名称归其各自权利方所有,本文仅基于 Anthropic 公开文档进行技术解读,不代表 ClaudeAPI 与相关权利方存在官方授权、代理或背书关系。
一、Claude API Rate Limit 的三个维度
据 Anthropic 官方文档(docs.anthropic.com/en/api/rate-limits ),Claude API 的限流体系由以下三个维度共同约束:
| 维度 | 全称 | 说明 |
|---|---|---|
| RPM | Requests Per Minute | 每分钟允许的请求次数上限 |
| TPM | Tokens Per Minute | 每分钟允许的 Token 消耗上限(输入 + 输出合计) |
| TPD | Tokens Per Day | 每日 Token 消耗上限 |
三个维度任意一个触顶,均会触发 429 响应,响应头中会包含 retry-after 字段,告知客户端需要等待多少秒。
不同账户层级(Tier 1 ~ Tier 4 及 Enterprise)的配额存在显著差异,例如据 Anthropic 官方文档,Tier 1 账户 claude-opus-4 系列默认 RPM 为 50,而 Tier 4 账户可达 4000(数据来源:Anthropic 官方文档 docs.anthropic.com/en/api/rate-limits,截至 2026-06-30)。在接入前请务必登录 Anthropic Console 确认自己账户的实际配额层级。
响应头中的关键字段
HTTP/1.1 429 Too Many Requests
anthropic-ratelimit-requests-limit: 50
anthropic-ratelimit-requests-remaining: 0
anthropic-ratelimit-requests-reset: 2026-06-30T12:01:00Z
anthropic-ratelimit-tokens-limit: 40000
anthropic-ratelimit-tokens-remaining: 0
anthropic-ratelimit-tokens-reset: 2026-06-30T12:01:00Z
retry-after: 30
HTTP/1.1 429 Too Many Requests
anthropic-ratelimit-requests-limit: 50
anthropic-ratelimit-requests-remaining: 0
anthropic-ratelimit-requests-reset: 2026-06-30T12:01:00Z
anthropic-ratelimit-tokens-limit: 40000
anthropic-ratelimit-tokens-remaining: 0
anthropic-ratelimit-tokens-reset: 2026-06-30T12:01:00Z
retry-after: 30
建议在客户端主动读取 anthropic-ratelimit-*-remaining 字段,在配额耗尽前主动降速,而不是等 429 再重试。
二、为什么你的 429 一直触发:常见误判场景
在实际工程中,以下四种场景最容易引发持续 429:
1. 高并发场景下的 RPM 耗尽
业务代码里同时起 100 个异步任务,即便每个请求消耗 Token 量不大,RPM 仍会在几秒内被打满。
2. 长上下文场景下的 TPM 耗尽
单条对话携带数万 Token 的上下文,3-5 个并发就能把 TPM 耗尽,即使 RPM 还剩余配额。
3. 批量任务在凌晨集中跑,TPD 被提前耗尽
日常业务 TPD 充裕,但报表生成或数据处理脚本在非业务时间集中运行,导致第二天业务高峰时配额已耗尽。
4. 多服务共用同一 API Key
微服务架构下,多个服务共享一个 API Key,各自都没有全局限速,合计请求量超限。
上线前容量估算:先算安全水位,再写并发
很多 429 问题不是代码 bug,而是上线前没有把配额换算成可执行的吞吐预算。建议在接入前先做一张小表:
| 指标 | 计算方式 | 用途 |
|---|---|---|
| 安全 RPM | 账户 RPM × 0.7 |
预留 30% 抖动空间,避免瞬时峰值触顶 |
| 单请求平均 Token | 平均输入 Token + 平均输出 Token |
判断 TPM 是否会先于 RPM 触顶 |
| 安全 TPM 任务量 | (账户 TPM × 0.7) ÷ 单请求平均 Token |
估算每分钟可处理多少个任务 |
| 建议并发上限 | min(安全 RPM, 安全 TPM 任务量) × P95 请求耗时 / 60 |
把每分钟吞吐换成在途请求数 |
举例:如果某任务平均输入 3000 Token、输出 500 Token,单请求约 3500 Token。即使 RPM 看起来足够,只要 TPM 较低,真正的瓶颈也可能是 Token,而不是请求次数。此时盲目增加并发只会更快触发 429。
HowTo:生产环境落地顺序
- 记录基线:上线前抽样 50-100 个真实请求,统计平均输入 Token、平均输出 Token、P95 请求耗时和失败率。
- 计算安全并发:按上表把 RPM、TPM 都换算成安全水位,取更保守的值作为初始
MAX_CONCURRENCY。 - 接入退避重试:只对 429、529 和少量临时 5xx 做有限次重试;401、400、参数错误不要重试。
- 加全局限速:同一个 API Key 被多个服务共用时,优先做共享限速器或按业务拆 Key,避免每个服务都以为自己没有超限。
- 灰度放量:第一天按 30% 并发运行,观察 429 率、TPM 剩余、平均延迟;稳定后再逐步上调到 50%、70%。
- 设置告警:429 率连续 5 分钟超过阈值、
tokens-remaining低于安全线、TPD 消耗异常增长时通知值班。
三、核心解法:指数退避重试
为什么不能用固定间隔重试
固定间隔(如每 1 秒重试一次)在高并发场景下会造成"重试风暴"——所有客户端同时等待相同时间后同时重发,再次集中打满配额。指数退避(Exponential Backoff)配合随机抖动(Jitter)可有效分散重试压力。
Python 实现(anthropic SDK)
import anthropic
import time
import random
client = anthropic.Anthropic(
api_key="YOUR_API_KEY",
base_url=" ", # ClaudeAPI 兼容 Anthropic SDK 格式
)
def call_with_retry(
messages: list,
model: str = "claude-sonnet-4-6",
max_tokens: int = 1024,
max_retries: int = 5,
base_delay: float = 1.0,
max_delay: float = 60.0,
) -> anthropic.types.Message:
"""
带指数退避重试的 Claude API 调用封装。
仅对 429(Rate Limit)和 529(Overloaded)进行重试,
4xx 认证/参数错误不重试。
"""
for attempt in range(max_retries):
try:
response = client.messages.create(
model=model,
max_tokens=max_tokens,
messages=messages,
)
return response
except anthropic.RateLimitError as e:
if attempt == max_retries - 1:
raise
retry_after = getattr(e, "retry_after", None)
if retry_after:
wait = float(retry_after)
else:
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f"[Retry {attempt + 1}/{max_retries}] Rate limited. Waiting {wait:.1f}s...")
time.sleep(wait)
except anthropic.APIStatusError as e:
if e.status_code == 529 and attempt < max_retries - 1:
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f"[Retry {attempt + 1}/{max_retries}] Overloaded. Waiting {wait:.1f}s...")
time.sleep(wait)
else:
raise
response = call_with_retry(
messages=[{"role": "user", "content": "请用 100 字总结大语言模型的发展历史。"}],
model="claude-sonnet-4-6",
)
print(response.content[0].text)
import anthropic
import time
import random
client = anthropic.Anthropic(
api_key="YOUR_API_KEY",
base_url=" ", # ClaudeAPI 兼容 Anthropic SDK 格式
)
def call_with_retry(
messages: list,
model: str = "claude-sonnet-4-6",
max_tokens: int = 1024,
max_retries: int = 5,
base_delay: float = 1.0,
max_delay: float = 60.0,
) -> anthropic.types.Message:
"""
带指数退避重试的 Claude API 调用封装。
仅对 429(Rate Limit)和 529(Overloaded)进行重试,
4xx 认证/参数错误不重试。
"""
for attempt in range(max_retries):
try:
response = client.messages.create(
model=model,
max_tokens=max_tokens,
messages=messages,
)
return response
except anthropic.RateLimitError as e:
if attempt == max_retries - 1:
raise
retry_after = getattr(e, "retry_after", None)
if retry_after:
wait = float(retry_after)
else:
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f"[Retry {attempt + 1}/{max_retries}] Rate limited. Waiting {wait:.1f}s...")
time.sleep(wait)
except anthropic.APIStatusError as e:
if e.status_code == 529 and attempt < max_retries - 1:
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f"[Retry {attempt + 1}/{max_retries}] Overloaded. Waiting {wait:.1f}s...")
time.sleep(wait)
else:
raise
response = call_with_retry(
messages=[{"role": "user", "content": "请用 100 字总结大语言模型的发展历史。"}],
model="claude-sonnet-4-6",
)
print(response.content[0].text)
Node.js 实现(@anthropic-ai/sdk)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: " ",
});
async function callWithRetry(
messages: Anthropic.MessageParam[],
model = "claude-sonnet-4-6",
maxRetries = 5
): Promise<Anthropic.Message> {
const baseDelay = 1000;
const maxDelay = 60000;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.messages.create({
model,
max_tokens: 1024,
messages,
});
} catch (err: unknown) {
const isRateLimit =
err instanceof Anthropic.RateLimitError ||
(err instanceof Anthropic.APIStatusError && err.status === 529);
if (!isRateLimit || attempt === maxRetries - 1) throw err;
const jitter = Math.random() * 1000;
const wait = Math.min(baseDelay * Math.pow(2, attempt) + jitter, maxDelay);
console.log(`[Retry ${attempt + 1}/${maxRetries}] Waiting ${(wait / 1000).toFixed(1)}s...`);
await new Promise((resolve) => setTimeout(resolve, wait));
}
}
throw new Error("Max retries exceeded");
}
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: " ",
});
async function callWithRetry(
messages: Anthropic.MessageParam[],
model = "claude-sonnet-4-6",
maxRetries = 5
): Promise<Anthropic.Message> {
const baseDelay = 1000;
const maxDelay = 60000;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.messages.create({
model,
max_tokens: 1024,
messages,
});
} catch (err: unknown) {
const isRateLimit =
err instanceof Anthropic.RateLimitError ||
(err instanceof Anthropic.APIStatusError && err.status === 529);
if (!isRateLimit || attempt === maxRetries - 1) throw err;
const jitter = Math.random() * 1000;
const wait = Math.min(baseDelay * Math.pow(2, attempt) + jitter, maxDelay);
console.log(`[Retry ${attempt + 1}/${maxRetries}] Waiting ${(wait / 1000).toFixed(1)}s...`);
await new Promise((resolve) => setTimeout(resolve, wait));
}
}
throw new Error("Max retries exceeded");
}
前置条件:需已在 ClaudeAPI 控制台 创建 API Key 并完成充值。
base_url填写https://gw.claudeapi.com,兼容 Anthropic SDK 格式,无需修改其他参数。
四、并发控制:信号量限速模式
指数退避解决的是"触顶后如何恢复",而**主动限速(Pre-throttling)**是更好的策略——在发出请求前就控制并发数,避免触发 429。
Python asyncio + Semaphore
import asyncio
import anthropic
# 根据你的账户 RPM 配额调整 MAX_CONCURRENCY
MAX_CONCURRENCY = 10
client = anthropic.AsyncAnthropic(
api_key="YOUR_API_KEY",
base_url="https://gw.claudeapi.com",
)
async def process_single(sem: asyncio.Semaphore, text: str) -> str:
async with sem:
response = await client.messages.create(
model="claude-haiku-4-5-20251001", # 高并发场景优先用 Haiku 降低 TPM 消耗
max_tokens=256,
messages=[{"role": "user", "content": text}],
)
return response.content[0].text
async def batch_process(texts: list[str]) -> list[str]:
sem = asyncio.Semaphore(MAX_CONCURRENCY)
tasks = [process_single(sem, t) for t in texts]
return await asyncio.gather(*tasks)
# 运行
results = asyncio.run(batch_process(["摘要任务1", "摘要任务2", "摘要任务3"]))
import asyncio
import anthropic
# 根据你的账户 RPM 配额调整 MAX_CONCURRENCY
MAX_CONCURRENCY = 10
client = anthropic.AsyncAnthropic(
api_key="YOUR_API_KEY",
base_url="https://gw.claudeapi.com",
)
async def process_single(sem: asyncio.Semaphore, text: str) -> str:
async with sem:
response = await client.messages.create(
model="claude-haiku-4-5-20251001", # 高并发场景优先用 Haiku 降低 TPM 消耗
max_tokens=256,
messages=[{"role": "user", "content": text}],
)
return response.content[0].text
async def batch_process(texts: list[str]) -> list[str]:
sem = asyncio.Semaphore(MAX_CONCURRENCY)
tasks = [process_single(sem, t) for t in texts]
return await asyncio.gather(*tasks)
# 运行
results = asyncio.run(batch_process(["摘要任务1", "摘要任务2", "摘要任务3"]))
MAX_CONCURRENCY 的设定建议:以账户 RPM 的 70% 作为并发上限,留出余量应对请求时间不均匀的情况。例如 RPM = 50,则 MAX_CONCURRENCY 建议不超过 35。
如果你有多个消费者进程,不要只在单进程里设置 Semaphore。单进程并发为 10、同时部署 8 个副本,实际全局并发就是 80。生产环境更稳的做法是把限速状态放到 Redis、队列或网关层,让所有服务共享同一套令牌桶。
监控指标建议
| 指标 | 建议记录方式 | 为什么重要 |
|---|---|---|
429_rate |
429 数 / 总请求数,按 1 分钟窗口聚合 | 判断限流是否从偶发变成系统性问题 |
retry_count |
每次请求最终重试次数 | 重试次数上升通常早于整体失败率上升 |
tokens_remaining_min |
每分钟最低剩余 TPM | 能提前发现长上下文任务正在挤占配额 |
p95_latency |
成功请求的 P95 耗时 | 并发上限应结合请求耗时调整 |
daily_token_burn |
当日累计 Token 消耗 | 防止离线任务提前消耗 TPD |
五、模型分层调度:用对模型节省配额
并非所有任务都需要 Opus 级别的模型。合理的分层调度可以在相同配额下处理更多请求:
| 模型 | 适用场景 |
|---|---|
| claude-haiku-4-5-20251001 | 分类、摘要、格式化、简单问答 |
| claude-sonnet-4-6 | 代码生成、多步推理、内容创作 |
| claude-opus-4-7 | 复杂分析、长文档、高精度任务 |
分层策略示例:
- 第一轮用 Haiku 做意图分类,置信度低于阈值的任务升级到 Sonnet;
- 仅最终需要深度推理的任务才调用 Opus;
- Haiku 的 TPM 消耗约为 Opus 的 1/20,相同配额下可处理更多并发。
六、Prompt Caching:减少 TPM 消耗的直接手段
对于含有大量重复上下文的请求(如固定系统提示 + 文档 + 多轮对话),Prompt Caching 可将缓存部分的 Token 消耗降至约 10%,显著延缓 TPM 触顶。
适用条件(据 Anthropic 官方文档,截至 2026-06-30):
- 系统提示或文档 Token 数 ≥ 1024(claude-haiku)或 ≥ 2048(claude-sonnet/opus);
- 相同前缀在 5 分钟内重复调用;
- 在对应 content block 中添加
"cache_control": {"type": "ephemeral"}。
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{
"type": "text",
"text": "你是一名专业的代码审查助手。以下是项目的全量代码库上下文:\n\n" + large_codebase_context,
"cache_control": {"type": "ephemeral"}, # 启用 Prompt Caching
}
],
messages=[{"role": "user", "content": "请审查 src/auth.py 中的安全问题。"}],
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{
"type": "text",
"text": "你是一名专业的代码审查助手。以下是项目的全量代码库上下文:\n\n" + large_codebase_context,
"cache_control": {"type": "ephemeral"}, # 启用 Prompt Caching
}
],
messages=[{"role": "user", "content": "请审查 src/auth.py 中的安全问题。"}],
)
七、常见错误排查清单
| 错误 | 可能原因 | 处理建议 |
|---|---|---|
429 RateLimitError |
RPM/TPM/TPD 任意一个触顶 | 读 retry-after 头,指数退避重试 |
529 OverloadedError |
服务端过载(非账户限流) | 同样可指数退避重试 |
401 AuthenticationError |
API Key 错误或已失效 | 检查 Key,不重试 |
400 InvalidRequestError |
参数格式错误 | 检查 model ID、max_tokens,不重试 |
408 RequestTimeout |
请求超时 | 可有限次重试,建议检查网络或降低 max_tokens |
更完整的错误码说明见 Claude API 常见错误码处理方法。
常见问题(FAQ)
Q:Claude API 429 报错的 retry-after 是多少秒?
响应头中的 retry-after 值由服务端动态决定,通常在 1 到 60 秒之间,具体取决于配额重置时间。建议客户端优先读取该字段,而非使用固定等待时间。
Q:我的账户 RPM/TPM 配额是多少,在哪里查?
登录 Anthropic Console(console.anthropic.com),在 “Plans & Billing” → “Rate Limits” 页面可查看当前账户层级及各模型的配额上限。如使用 ClaudeAPI 中转,请登录 ClaudeAPI 控制台 查看用量与配额信息。
Q:多服务共用一个 API Key 会叠加限流吗?
是的。Rate Limit 是按 API Key 计算的,所有使用同一 Key 的服务共享同一配额。建议为不同业务线分配独立 API Key,并在各服务内分别实施并发控制。
Q:Prompt Caching 命中后 TPM 消耗会减少吗?
是的。缓存命中部分(cache read)的 Token 消耗约为正常输入 Token 的 10%(数据来源:Anthropic 官方文档 docs.anthropic.com/en/docs/build-with-claude/prompt-caching,截至 2026-06-30)。对于含大型固定上下文的请求,这是在不升级配额的前提下提升吞吐量最直接的手段。
Q:Claude API 支持 Message Batches API 异步批量处理吗?
claudeapi.com 当前不支持 Message Batches API,因此本文的成本优化建议以 Prompt Caching、模型分层和流式输出为主。如需大批量异步处理,建议联系 ClaudeAPI 技术支持了解替代方案。
Q:流式输出(Streaming)能缓解 Rate Limit 问题吗?
流式输出不直接降低 RPM 或 TPM 消耗,但它可以让单次请求更早开始返回内容,改善用户体验;同时配合 max_tokens 上限设置,可以更精准地控制每次请求的 Token 消耗。详见 Claude API 流式输出(Streaming SSE)接入指南。
下一步
- 创建 API Key:访问 ClaudeAPI 控制台,创建并管理你的 API Key;
- 确认接入参数:
base_url:https://gw.claudeapi.com(Anthropic SDK)或https://gw.claudeapi.com/v1(OpenAI 兼容路径)- 推荐 Model ID:
claude-sonnet-4-6(均衡)、claude-haiku-4-5-20251001(高并发低成本)
- 接入流式输出:高并发场景下流式输出可提升体验,见 Streaming SSE 接入指南;
- 配置 Prompt Caching:有大型固定上下文的项目,按 Prompt Caching 指南 开启可立即降低 TPM 消耗;
- 排查接入问题:遇到 4xx/5xx 错误先查 Claude API 错误码指南。
数据与事实声明
-
RPM/TPM/TPD 三维限流机制及响应头字段说明:来自 Anthropic 官方文档 docs.anthropic.com/en/api/rate-limits,读者可访问原链接二次核证;
-
Prompt Caching 缓存命中 Token 消耗约为正常输入 10%:来自 Anthropic 官方文档 docs.anthropic.com/en/docs/build-with-claude/prompt-caching;
-
不同账户层级配额差异:原始数据在 Anthropic Console 及官方文档中,本文数值仅为示意,请以账户实际显示为准;
-
代码示例为作者基于官方 SDK 文档编写的工程化参考实现,非 Anthropic 官方代码,使用前请结合实际业务场景测试。



