限制属于哪个服务
这些名称很容易混淆。Groq 是一家在其自有硬件上托管模型的公司。Grok 是 xAI 的模型系列。本网站不是:它是一个针对单一开放权重模型(模型 ID uncensored)的 OpenAI 兼容 API,由独立提供商运行。因此,对于 groq api rate limit 本身,例如给定计划下的每分钟请求数或 token 数,请打开 Groq 的控制台或文档并阅读你账户的数字。它们会变化,我不会猜测。
以下内容适用于我们的 API,这些习惯也适用于任何提供商:尊重限制标头,仅在正确的错误上重试,并在服务器之前限制你自己的并发。如果你来这里是为了 Grok NSFW 设置,我们的 集成指南也涵盖了相关错误。
限制概览
| 限制 | 完整密钥 | 试用密钥 |
|---|---|---|
| 并发请求 | 8 | 2 |
| 每分钟请求数 | 300 | 60 |
| 请求体 | 8 MB | 8 MB |
| 上下文窗口(提示词加补全) | 100,000 个 token | 100,000 个 token |
其中两个是严格意义上的速率限制:每分钟请求数和并发数。另外两个是单个请求的大小限制,它们与速率限制无关。带有 90,000 token 提示词的一个请求算作一个请求,计入每分钟 300 个的限制,与单行提示词相同,尽管它需要更长的时间并占用更长的槽位。
$0.50 的试用额度在注册后通过 API 密钥页面 一键领取,并使用试用限制。完整密钥的限制在充值后生效。
三种 429 错误
所有限制错误都以 HTTP 429 形式出现,但它们含义不同,需要不同的处理方式。
rate_limited:你发送的请求超过了每分钟请求配额。放慢速度;窗口是一分钟,因此均匀分布请求比长时间暂停更有效。concurrency:同时进行的请求过多。等待较早的请求完成。这在流式输出中很常见,因为每个请求贯穿整个生成过程。- 临时过载:也是 429,带有
Retry-After: 5标头。这不是你的错,也不与你的密钥限制相关。等待指定的 5 秒并重试。
失败的请求不收费,因此重试循环的成本仅为最终成功的那个请求。响应还包含 X-RateLimit-Limit-Requests 和 X-RateLimit-Limit-Concurrency,以便你的客户端可以读取自己的上限,而不是硬编码它们,以及 X-Balance-USD 用于剩余额度,以及 X-Request-Id,你应该记录并在联系 技术支持 时引用。
吞吐量计算:为什么每分钟 300 次很难达到
这两个限制相互作用。使用 8 个并发槽位,每分钟完成的最大请求数是 8 x 60 除以请求的平均持续时间(秒)。要实际达到每分钟 300 次请求,你需要请求的平均完成时间为 8 x 60 / 300 = 1.6 秒。较慢的请求首先受并发限制。
| 平均请求时间 | 完整密钥每分钟最大(8 个槽位) | 试用密钥每分钟最大(2 个槽位) |
|---|---|---|
| 2 秒 | 240 | 60 |
| 10 秒 | 48 | 12 |
| 20 秒 | 24 | 6 |
这些是针对假设请求时间的算术上限,而不是我们服务的测量值;请测量你自己的请求。要点是,完整密钥下的 20 秒长文本创意生成最多只能达到每分钟 24 个请求,远低于允许的 300 个。如果你需要更高的吞吐量,请使用 max_tokens 缩短回复,或在每次调用中要求更少的文本,而不是希望获得更高的请求限制。
处理所有三种情况的客户端
此 Python 客户端使用信号量限制其自身的并发,读取存在的 Retry-After,否则使用小抖动进行退避。它使用官方的 openai 包。
import random
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from openai import OpenAI, RateLimitError
client = OpenAI(
base_url="https://api.groknsfw.top/v1",
api_key="YOUR_KEY",
max_retries=0, # we handle retries ourselves
)
slots = threading.BoundedSemaphore(8) # use 2 on the trial key
def ask(prompt, tries=6):
for attempt in range(tries):
with slots:
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
)
return r.choices[0].message.content
except RateLimitError as e:
wait = e.response.headers.get("retry-after")
body = e.response.text
# sleep outside the slot so others can proceed
delay = float(wait) if wait else min(2 ** attempt, 30)
if "rate_limited" in body:
delay = max(delay, 5)
time.sleep(delay + random.random())
raise RuntimeError("still rate limited after retries")
with ThreadPoolExecutor(max_workers=8) as pool:
results = list(pool.map(ask, ["Write one line about the sea."] * 20))
print(len(results))
Node 中的相同思路是一个小队列,最多允许 8 个待处理的 Promise,下面的 curl 检查打印限制头,以便你确认密钥的上限:
curl -s -D - -o /dev/null https://api.groknsfw.top/v1/models \
-H "Authorization: Bearer YOUR_KEY" | grep -i "x-"流式输出、长提示词和上下文
带有 stream: true 的流式请求会保留其并发槽位,直到最后一个事件到达。这意味着读取速度慢的客户端会占用你的资源:如果你的代码在处理每个块时暂停,该槽位将保持忙碌。请尽快消费流。
长提示词通过两种方式与限制相互作用。首先,它们需要更多时间处理,因此通过上述公式降低你的吞吐量。其次,它们必须与回复一起容纳在 100,000 token 的窗口内,因此请保留余量。修剪旧的聊天轮次有助于解决这两个问题,并且相同的修剪也会减少你的账单:每 1M 输入 token 收费 $0.15,20,000 token 的历史记录每次重新发送时花费 $0.003。
向你的用户显示限制
速率限制也是一种产品决策。如果你的应用位于最终用户和 API 之间,原始 429 绝不应到达他们。提前决定他们看到的内容。
- 对于聊天应用,显示简短的“正在输入”状态并排队消息。如果屏幕上正在发生某些事情,几秒的等待对大多数用户来说是不可见的。
- 对于批处理工具,以已完成项目的数量显示进度,并让作业在后台运行。重试是内部的,不应显示为错误。
- 对于共享部署,在你的代码中为每个用户提供少量用户配额,以便一个高频用户不会占用其他用户的所有 8 个槽位。
记录失败的三个内容:X-Request-Id、错误代码,以及你的应用当时正在处理的请求数量。有了这些,你可以在几分钟内区分行为不端的客户端和真实负载。如果问题看起来是服务器端的,请求 ID 是 技术支持 首先要求的内容。
最后,故意测试故障路径。使用故意低的信号量运行你的客户端,然后使用高的信号量运行,并观察日志显示的内容。从未触发的重试循环是一个你无法信任的重试循环。试用密钥是进行此操作的方便位置,因为由于只有 2 个并发请求,使用简短脚本很容易触发 concurrency 错误,并查看你的代码如何反应,每次请求成本仅为零点几美分。
常见错误
一些模式导致了大部分 429 问题。
- 立即重试。 每次失败都重新发送的循环会将一次超限时刻变成风暴。等待,添加抖动,并限制尝试次数。
- 重试所有内容。 只有 429 和临时服务器错误值得重试。格式错误的请求或错误的密钥每次都会以相同的方式失败。
- 在计数中忘记流。 完整密钥上的十个打开聊天窗口可能是十个流,这比 8 个槽位多两个。
- 不设置超时。 挂起的连接会占用槽位。在你的 HTTP 客户端中为每个请求设置合理的超时。
- 按平均值调整大小。 流量以突发形式出现。计划你最繁忙的一分钟,而不是你的日均值。
在启动前规划容量
从峰值倒推。如果你预计有 30 个用户同时聊天,每个回复流式传输约 15 秒,你需要在它们同时发送的瞬间拥有 30 个槽位,而完整密钥只有 8 个。将其余任务排入你自己的应用中,显示短暂等待,并在槽位空闲时处理它们。使用 8 个槽位和 15 秒的回复,你可以每分钟完成 8 x 60 / 15 = 32 个回复。
对于批处理作业,运行等于并发限制的固定工作池,并让重试逻辑处理偶尔的过载。与其绕过限制,不如构建队列:它提供可预测的行为,并允许你向用户显示真实的等待时间。
