跳转到内容

限流

有限制才能让共享的资源保持可用,所以限制几乎全落在免费共享端点上。一共四组,各自独立生效。

链路上有两层,一个请求两层都得过。平台先决定放不放行,网关再按你的账户计量。

限制范围典型值
每分钟请求数每个 API 密钥30
每分钟请求数每个 IP 地址120,仅在该部署的边缘能提供可信客户端地址时生效
并发请求数每个 API 密钥8
并发请求数每个模型按该模型后端集群实际能扛的并发来定
并发请求数每个服务进程共享池
并发请求数全平台共享池
限制范围典型值
每分钟请求数每个账户20,60 秒滑动窗口
花费上限每个账户一个滚动周期:从你第一次产生计费开始起算,到期自动重置——不是固定的午夜边界

列出模型不占并发槽位,但确实计入每分钟限制。

429 加一个 Retry-After 头。响应体取决于是哪一层拒的你。

平台准入返回一个包在 detail 里的 OpenAI 形状错误:

{
"detail": {
"error": {
"message": "Model API rate limit exceeded; please retry later",
"type": "rate_limit_error",
"code": "token_rate_limit_exceeded"
}
}
}

code 告诉你撞的是哪道关:

代码含义
token_rate_limit_exceeded这个密钥每分钟请求太多。
ip_rate_limit_exceeded这个 IP 每分钟请求太多。
token_concurrency_rate_limit_exceeded这个密钥同时在飞的请求太多。
model_concurrency_rate_limit_exceeded这个模型撞到了它自己的并发上限,换个模型可能还有余量。
process_concurrency_rate_limit_exceeded服务进程已饱和。
global_concurrency_rate_limit_exceeded平台已满载。

每分钟限制返回 Retry-After: 60。并发限制返回 Retry-After: 1——你手上的请求一跑完就解除了。

网关计量返回顶层的 OpenAI 形状错误,code 是通用的 rate_limit_exceeded 而不是分门别类的那几个,Retry-After 按窗口算出来:

{
"error": {
"message": "Rate limit exceeded: maximum 20 requests per minute for this OneClick user. Please try again later.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limit_exceeded"
}
}

花费上限用完是同样的形状,消息变成 Daily usage limit exceeded: maximum $N per period for this OneClick user.Retry-After 是本周期剩余的秒数。

/v1/messages 上,网关改用 Anthropic 的信封:{"type": "error", "error": {"type": "rate_limit_error", "message": "..."}}

上面那些一条都不适用。独占端点前面没有网关:代理核对密钥跟实例、端口对得上,就转发。请求路径上没有每分钟限制、没有并发额度、也没有花费上限。

真正卡你的是实例本身——vLLM 或 SGLang 自己的队列和 --max-running-requests,以及你启动的那块卡。超过之后请求是排队,而不是回 429。只要实例在跑就持续扣额度,有没有请求都一样。

启动按滑动窗口节流:大致每分钟一次、每十分钟三次、每小时五次。这是冲着重试循环去的,正常使用碰不到——一个人启动实例干活,永远不会注意到它。

超了返回 429Retry-After

登录尝试和新账户注册按 IP 限流。只有你在驱动控制台时才相关,调 API 不涉及。

Retry-After 来,别自己拍一个间隔,并在此基础上做带抖动的指数退避——一群客户端全都在正好 60 秒后重试,只会把造成限流的那个尖峰再造一遍。

在你这边把并发压到每个密钥的额度以内,而不是猛发请求然后接 429。一个容量 8 的信号量比重试循环更简单也更快。

除了 429,别重试其他 4xx400401 重试多少次都是一样的失败。

import time, random, requests
def call_with_retry(payload, attempts=5):
for i in range(attempts):
r = requests.post(URL, headers=H, json=payload, timeout=600)
if r.status_code != 429:
r.raise_for_status()
return r.json()
wait = float(r.headers.get("Retry-After", 60))
time.sleep(wait + random.uniform(0, 2) * (2 ** i))
raise RuntimeError("rate limited after retries")

如果你长期需要的余量超过共享端点能给的,那就是该转向独占端点的信号了——在那儿唯一的限制是你的实例能扛多少。