测试时 API 一切正常,上线后却频繁出现 429 Too Many Requests:这种情况不一定是用户突然变多了。长提示词可能耗尽 Token 限额,多个服务可能共享同一份容量,自动重试也可能把一次短暂拥堵变成持续报错。
遇到 429,先读取错误正文,确认限制来自哪里,再决定降低请求速率、减少 Token,还是处理配额问题。 本文解释 RPM、TPM 与并发的区别,梳理常见原因,并给出带指数退避、随机抖动和 Retry-After 处理的 Python 示例。
429 报错快速排查:先检查这六项
- 保留状态码和错误详情。 记录时间、模型、请求 ID、错误类型及响应头。排查时使用脱敏日志,不记录 API Key。
- 判断是否属于临时限流。 如果正文明确提示余额、计费或配额不足,持续重试通常没有帮助,应先处理对应问题。
- 确认限流范围。 查清限制按账号、项目、模型、API Key、IP,还是上游服务共享计算。
- 同时检查 RPM 和 TPM。 请求少也可能因为单次输入或输出太长而触发限制。
- 检查突发流量和重试叠加。 多个 Worker 同时启动、定时任务集中执行、SDK 与业务层重复重试,都可能放大流量。
- 按照服务端提示等待。 如果有有效的
Retry-After,至少等待指定时间;没有时再采用有上限的指数退避与随机抖动。仍持续触发限制时,调整队列、用量或容量。
HTTP 429 的含义和限制范围可以参考 MDN 的 429 说明。具体原因仍应结合当前服务返回的错误正文判断。
为什么大模型 API 需要多种限流指标?
请求次数不能完整反映大模型任务的计算需求。
一次短文本分类可能只输入 200 个 Token,返回一个标签;一次代码库分析可能输入数千个 Token,再生成长篇回答。两者都算一次请求,但消耗的 Token、处理时间和计算资源差别很大。
不同限制分别应对不同的流量特征:
- 短而频繁的请求更容易耗尽请求次数额度。
- 长提示词和大上下文可能在请求不多时耗尽 Token 额度。
- 较长的输出增加 Token 消耗,也让请求保持更长的执行时间。
- 集中到达的流量可能在平均用量正常时触发短时限制。
- 通过实时接口执行大量离线任务会占用在线容量,即使任务并不需要立即返回。
常见指标包括 RPM、TPM,以及按小时、按天统计的请求或 Token 限额。图片服务还可能使用 IPM、IPD,分别表示每分钟、每天的图像数量。只要其中一项适用限制达到上限,请求就可能被限制。 并非每个平台都会使用全部指标。
RPM 和 TPM 有什么区别?
RPM 和 TPM 衡量的是不同维度。
| 指标 |
含义 |
常见瓶颈 |
| RPM |
每分钟请求数 |
高频小请求 |
| TPM |
每分钟 Token 数 |
长提示词、大上下文、长输出 |
| RPH |
每小时请求数 |
小时级使用上限 |
| RPD |
每天请求数 |
每日请求额度 |
| TPD |
每天 Token 数 |
每日 Token 消耗 |
RPM 限制什么?
RPM 限制的是一定范围内每分钟可发送的请求次数。这里的范围可能是账号、项目、模型或其他资源,取决于服务规则。
即使每次请求都很短,也可能触发 RPM 限制。自动补全、聊天程序、Agent 循环,以及把一次用户操作拆成多次模型调用的工作流,都容易遇到这种情况。
例如,一个 Agent 任务分别调用模型完成规划、工具选择、结果验证和最终回答。用户只提交了一次任务,后台却发出了四次或更多请求。
TPM 限制什么?
TPM 限制的是每分钟计入限流的 Token 数量。系统提示词、历史对话、检索文档、代码、推理内容和长输出,都可能增加消耗。
排查时记录实际返回的 prompt_tokens、completion_tokens、total_tokens,或当前协议中的对应字段。用于限流的计算口径不一定与最终账单完全相同:有些服务会参考预估输入量、输出上限等信息,具体以服务文档为准。
假设两个应用每分钟都发送 10 次请求:
- 应用 A 每次使用 300 个总 Token,约为 3,000 TPM。
- 应用 B 每次使用 8,000 个总 Token,约为 80,000 TPM。
两者都是 10 RPM,但应用 B 更容易先达到 TPM 上限。
限流按账号、模型还是 API Key 计算?
接入前要确认限制的作用范围。部分服务按账号或项目共享容量,部分会按模型、模型组、Key 或其他维度进一步限制。
多创建几个 API Key,不等于一定获得更多容量。 如果这些 Key 共享同一账号、项目或上游限额,总容量可能完全不变。
同样,不要默认不同模型拥有独立额度,也不要默认套餐升级会同时增加所有指标。部署前核对目标模型、当前账号等级和实际限额。
为什么请求不多,还是收到 429?
429 通常提示请求触及适用的使用限制,但只看状态码,无法确定究竟是哪种限制。应继续查看错误代码、正文和响应头。
请求次数过多
集中发送的短请求可能超过 RPM。Agent 一次用户操作触发多次调用,会让前台看到的任务数远低于实际请求数。
Token 消耗过高
少量长请求也可能超过 TPM。常见原因包括重复发送系统提示词、携带完整历史记录、返回过多检索内容、输入长代码文件,以及设置不必要的输出上限。
多个服务共享同一限额
多个应用、后端服务、Worker 或 Key 可能共享账号、项目、模型或上游容量。单独观察每个服务时流量不大,加总后却已经达到上限。
流量集中到达
每小时或每天平均用量不高,不代表某一分钟内没有突发。定时任务同时启动、队列一次释放大量任务,都会造成短时峰值。
因此,排查 429 应同时查看队列积压、请求释放速率和分钟级用量,而不是只看全天总量。
自动重试放大了负载
立即重试会向已经受限的系统继续发送请求。多个 Worker 同时失败、同时重试,可能产生重试风暴,让问题持续更久。
模型还有小时级或每日限制
部分模型或套餐还设置小时级、每日请求数或 Token 上限。RPM 和 TPM 没有达到上限,也不代表其他配额仍有剩余。
专属部署的接入配置不匹配
使用专属部署时,还要确认目标地址、部署名、模型 ID 和 Key 权限是否匹配。请求误入共享接口时,可能触发另一套限流规则。
专属容量是否免除某些共享限制、还受哪些网关或实例限制,取决于部署方案。不要将“专属”理解为无限吞吐。
如果错误明确指向余额、账单、权限或已耗尽的长期配额,应先处理这些条件,再重试。没有足够错误信息时,向服务方提供请求 ID、时间和脱敏错误详情。
429、503、504 有什么区别?
不是所有临时 API 故障都属于限流。先区分状态码,再阅读具体错误详情。
| 状态码 |
常见含义 |
首先怎么处理 |
| 429 |
请求速率、Token 或其他使用限制;部分服务也用它报告配额问题 |
确认限制类型;临时限流降低速率并退避,配额问题先处理配额 |
| 503 |
服务暂时不可用,可能涉及负载或维护 |
检查服务状态,仅对适合重试的任务做有限重试或使用已验证的备用方案 |
| 504 |
网关未及时收到上游响应 |
检查任务状态、耗时和超时设置,避免重复提交已在执行的任务 |
| 400 |
请求格式或参数不符合要求 |
按错误正文修改请求;模型 ID 错误也可能返回其他状态码 |
| 401 |
身份认证失败或凭据缺失 |
检查 Key、认证头和目标服务是否匹配 |
| 403 |
没有相应权限 |
检查账号、项目和模型访问权限 |
| 404 |
接口路径、模型或目标资源不存在 |
检查 Base URL、路径拼接、接口协议和资源 ID |
长时间的非流式请求如果反复出现 504,原样重试未必有效。对于支持流式的场景,可评估流式返回、减少输出长度,或调整客户端与网关超时。
流式响应有助于持续传输数据,不能增加 RPM、TPM,也不能解决所有上游计算超时。对于异步任务,应先查询任务状态,再决定是否重新提交。
怎样正确处理限流和重试?
只对适合重试的临时故障进行重试,并限制次数、等待时间和整体业务耗时。先确认任务是否允许重复执行,再选择策略。
使用指数退避
连续失败后逐步增加等待时间,例如约 1 秒、2 秒、4 秒、8 秒,同时设置等待上限和尝试次数上限。具体等待策略可参考 AWS 对指数退避和随机抖动的说明。
加入随机抖动
在退避时间上增加随机偏移,避免多个客户端在相同时间再次发起请求。否则,一起失败的请求可能再次一起到达。
用队列控制请求释放速率
队列可以吸收短时突发,再按可承受速率释放任务。交互请求可优先处理,后台任务等待可用容量。
令牌桶、漏桶等机制控制新请求何时发出;并发上限控制同时执行多少请求。两者解决的问题不同,通常需要配合使用。
设置最大尝试次数
某些场景可以从最多 3—5 次总尝试开始,再结合延迟要求和业务成本调整。“尝试 5 次”包含首次请求,不是首次之外再重试 5 次。
最后一次仍失败时,返回明确错误、保留任务等待后续处理,或进入经过验证的备用方案。交互任务还应设置整体截止时间,避免用户离开后仍持续执行。
避免重复执行外部操作
Agent 可能调用付款系统、数据库、文件操作等外部工具。重试模型请求,不应自动重复已经成功的业务操作。
使用幂等键、操作 ID、任务状态和去重机制保护下游。网络超时也不等于服务端没有执行;重新发起生成可能造成额外费用。
只保留一层重试,并处理 Retry-After
SDK 和业务层如果都在重试,总尝试次数可能相乘。使用应用层策略时,应关闭 SDK 重试,或把两层行为一起纳入预算。相关原则可参考 OpenAI 官方限流处理文档。
Retry-After 可以表示等待秒数,也可以表示一个 HTTP 日期。服务端提供有效提示时,至少等待指定时间;如果超出当前任务能接受的等待预算,应停止并延后任务,不能擅自缩短等待后继续发送。字段格式见 MDN 的 Retry-After 说明。
下面的 Python 示例用于 OpenAI 兼容的 Chat Completions 接口。它关闭 SDK 重试,限制总尝试次数与累计重试等待,并对已识别的配额或计费错误直接退出。
运行前安装 openai,设置 API_KEY、API_BASE_URL 和 MODEL_ID。使用服务文档给出的完整 Base URL;按实际模型要求调整 max_tokens 等参数。示例使用 Python 3.10 或更高版本。
import math
import os
import random
import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
from openai import APIConnectionError, APIStatusError, OpenAI
client = OpenAI(
api_key=os.environ["API_KEY"],
base_url=os.environ["API_BASE_URL"],
max_retries=0,
timeout=30.0,
)
# Extend this set with the documented error codes of your API provider.
NON_RETRYABLE_CODES = {
"insufficient_quota",
"billing_hard_limit_reached",
"billing_not_active",
}
def parse_retry_after(value: str | None) -> float | None:
if not value:
return None
try:
seconds = float(value)
return max(0.0, seconds) if math.isfinite(seconds) else None
except ValueError:
pass
try:
retry_time = parsedate_to_datetime(value)
if retry_time.tzinfo is None:
retry_time = retry_time.replace(tzinfo=timezone.utc)
seconds = (retry_time - datetime.now(timezone.utc)).total_seconds()
return max(0.0, seconds)
except (TypeError, ValueError, OverflowError):
return None
def create_chat_completion(
messages: list[dict[str, str]],
max_attempts: int = 5,
max_retry_wait: float = 60.0,
):
if max_attempts < 1 or max_retry_wait < 0:
raise ValueError("Invalid retry limits")
waited = 0.0
for attempt in range(max_attempts):
try:
return client.chat.completions.create(
model=os.environ["MODEL_ID"],
messages=messages,
max_tokens=800,
)
except APIStatusError as error:
if (
error.status_code not in {429, 503, 504}
or error.code in NON_RETRYABLE_CODES
or attempt == max_attempts - 1
):
raise
backoff = min(30.0, 2.0 ** attempt)
server_delay = parse_retry_after(
error.response.headers.get("retry-after")
)
delay = server_delay if server_delay is not None else backoff
delay += random.uniform(0.0, min(1.0, delay * 0.25))
if waited + delay > max_retry_wait:
raise
except APIConnectionError:
if attempt == max_attempts - 1:
raise
delay = min(30.0, 2.0 ** attempt) + random.uniform(0.0, 1.0)
if waited + delay > max_retry_wait:
raise
time.sleep(delay)
waited += delay
raise RuntimeError("The request failed after all retry attempts.")
max_attempts=5 表示最多发起五次尝试;max_retry_wait=60 只限制累计休眠等待,不包含网络调用耗时。timeout=30.0 也不等于整个业务只能运行 30 秒;完整的截止时间与取消机制应由上层应用控制。
服务方的错误代码可能不同,应按照实际文档补充 NON_RETRYABLE_CODES。示例不适合直接重放已经输出部分内容的流,也不会替你判断异步任务或外部操作是否已经成功。
如何估算 API 的初始并发上限?
RPM、TPM 衡量吞吐量,并发衡量同时执行的请求数量,不能互相直接替代。
在限额以总 Token 为统计口径的假设下,可以用观测数据粗估起点:
RPM 允许的请求速率 = RPM ÷ 60
TPM 允许的请求速率 = TPM ÷ 每次请求的观测总 Token 数 ÷ 60
计划释放速率 = min(RPM 速率, TPM 速率) × 安全系数
并发规模参考值 = 计划释放速率 × 请求耗时
假设一个模型的限制和观测值为:
- 1,200 RPM;
- 60,000 TPM;
- 每次请求约 1,200 个总 Token;
- P95 请求耗时约 4 秒;
- 安全系数为 80%。
按 RPM 计算:
1,200 ÷ 60 = 20 次/秒
按 TPM 计算:
60,000 ÷ 1,200 ÷ 60 ≈ 0.83 次/秒
这里 TPM 是更紧的约束。应用安全系数后:
0.83 × 0.8 ≈ 0.67 次/秒
再用 P95 耗时估算并发规模:
0.67 × 4 ≈ 2.68 个同时执行的请求
可以从并发 2 或 3 开始观测,同时将请求释放速率控制在约 0.67 次/秒以内。这是一组演示数据,不代表任何平台的实际限额。
该公式只是容量规划的起点。平均 Token 不能覆盖长请求尾部风险;用 P95 耗时相乘是规划参考,也不是严格的并发保证。请求长度、延迟、服务端窗口及其他限制都会影响结果。
只设置并发上限,不能自动遵守 RPM 或 TPM。 快请求完成后立刻补入新请求,仍可能超出分钟限额。因此还需要请求节流,以及按服务端口径进行 Token 用量控制。
应用架构怎样适应 API 限流?
限流处理应进入日常流量设计,而不是等上线报错后再补一个重试循环。
统计一次用户操作会触发多少次请求
一个界面动作可能包含规划、检索、工具调用和结果验证等多次模型请求。容量估算应以实际调用次数为基础。
观察 Token 消耗的分布
记录输入、输出和总 Token 的中位数、P95 与最大值。平均值正常时,少量超长请求仍可能造成问题。
根据实际限流范围分配队列
模型拥有独立额度时,可以按模型划分队列和并发限制;多个模型共享账号或上游额度时,还需要共同的总量限制。单一全局限制和完全独立的队列,都可能与真实规则不匹配。
限制提示词和输出规模
去掉重复上下文,限制检索结果数量,总结较早的对话,并设置合理的输出上限。这些措施通常能同时降低 Token 压力和调用成本。
按任务要求选择模型
分类、抽取、推理、编程和多模态任务,可以根据质量、延迟、成本与可用容量选择合适的模型。
备用模型必须验证任务效果与接口兼容性。切换模型不应被当成绕过平台限制的方法,也不能保证另一个模型拥有独立容量。
将适合的离线任务移到批处理
评测、文档处理、分类和大规模抽取不一定需要实时结果。如果服务提供批处理 API,可评估其支持的模型、接口、处理时限、费用和独立限额。
如果没有批处理 API,也可以使用自有任务队列按允许速率执行;普通循环请求不会因此自动获得批处理折扣或额外容量。
持续接近上限时申请扩容
提示词优化、队列和有限重试可以缓解短时峰值,但不能解决长期需求超过容量的问题。
当正常业务持续接近限额时,按服务方的流程申请更高 RPM、TPM 或其他容量。准备预计请求量、输入输出分布、峰值、任务类型和延迟要求,帮助判断需要增加的是哪一项资源。申请本身不等于一定获批。
评估专属容量
持续高吞吐或需要更可预测容量的应用,可以评估服务方提供的专属部署方案。比较实际吞吐、延迟、排队时间、成本,以及仍然适用的网关和实例限制,不要默认专属部署没有上限。
AI API 限流常见问题
TPM 是什么意思?
TPM 是每分钟 Token 数,用于限制单位时间的 Token 使用。长提示词、对话历史、检索文档、推理内容和长输出,都可能让应用先达到 TPM,而不是 RPM。
为什么请求很少也会报 429?
少量长请求可能消耗大量 Token;突发流量、共享容量、重试叠加、小时或每日限制,也可能触发 429。先阅读错误正文,不要只看前台用户数。
所有 API 请求失败都应该重试吗?
不应该。适合重试的临时限流、部分 503、504 或连接错误,可以采用有限退避。参数错误、认证失败、权限不足、路径错误,以及需要处理账单或长期配额的问题,应先修正原因。超时后的任务还需要判断是否已经执行。
提高 RPM 会同时提高 TPM 吗?
不一定。它们是不同的约束,可能随模型、账号、项目或部署方案变化。申请扩容时应分别确认。
怎样减少 API 限流错误?
控制请求释放速率,管理并发与 Token 用量,使用队列和带随机抖动的有限重试;缩短不必要的上下文,将适合的离线任务移出实时调用。当持续需求超过容量时,再申请扩容或评估其他部署方案。
准备继续接入时,可从 API 平台进入,按当前接入文档核对 Base URL、模型 ID 和凭据,再用一条最小请求验证配置。排障求助时附上请求时间、请求 ID 和脱敏错误正文,更容易定位问题。
延伸阅读:模型选型专题。