JuCode 文档

限流与并发

并发限制的语义、模型列表端点的限流,以及计费口径。

生成类端点没有 QPS 限制

/v1/chat/completions/v1/images/generations/v1/videos 这些生成类端点 不受每分钟请求数限制。约束它们的是并发数——同一时刻你能有多少个请求在途。

这两者的区别很重要。QPS 限制下,你应该在收到 429 后退避一段时间;而并发限制下, 正确的做法是等已有请求返回。盲目退避会让吞吐白白降低。

超限时返回:

{
  "error": {
    "type": "rate_limit_error",
    "code": "concurrency_limit",
    "message": "concurrency limit reached",
    "request_id": "..."
  },
  "request_id": "..."
}

HTTP 状态 429,且不带 Retry-After

并发额度从哪来

按优先级取第一个命中的:

  1. 账号上的并发覆盖值(管理员单独配置)
  2. 套餐或用户组自带的并发额度

任一层配成 0 或未配置,即为不限并发。具体额度在控制台可以看到。

重试跨上游只占一个名额

一次请求内部如果发生了上游故障转移(网关自动换一家上游重试),整个过程只占用一个 并发名额,不会因为内部重试而多扣。

建议的客户端做法

用信号量控制并发,而不是靠捕获 429:

import asyncio

sem = asyncio.Semaphore(8)  # 设为你的并发额度,或略低

async def call(payload):
    async with sem:
        return await client.chat.completions.create(**payload)

这样把并发控制在客户端做掉,基本不会触发 concurrency_limit。真的收到了,短暂等待 (1 秒左右)后重试即可,不需要指数退避。

模型列表端点有 QPS 限制

/v1/models/anthropic/v1/models240 次 / 60 秒的用户级限流,固定窗口。

响应头:

说明
X-RateLimit-Limit恒为 240
X-RateLimit-Remaining本窗口剩余次数

Remaining 可能是负数

它是 限额 - 已用计数,而计数在判断之前就已递增,超限后会继续往下减。所以你可能看到 -3 这样的值。判断时用 <= 0 而不是 == 0

超限响应体格式特殊(不是统一信封):

{"error": "rate limit exceeded", "scope": "user"}

实践上这个额度足够启动时拉一次并缓存。不建议每次业务请求前都查模型列表。

请求体大小

端点类型上限
对话类(/v1/chat/completions/v1/responses)100 MiB
multipart 类(图像编辑、音频上传)32 MiB

超限返回 413 + request_body_too_large

传大图做视觉理解时注意:base64 编码会让体积膨胀约 33%,一张 30 MB 的原图编码后接近 40 MB。

超时

场景上限
非流式请求120 秒
流式请求不受上面这条限制
图像端点内部轮询异步上游120 秒

流式请求不受 120 秒总时长限制。 如果你的任务本来就慢(长文生成、深度推理), 用流式能绕开这个上限,顺便还能更早拿到首字。

流式另有几条独立的超时保护:首字超时、总时长超时、中途静默超时,触发时返回 504 并带对应的 code。详见错误码

计费口径

按用量计费

计费维度取决于端点:

端点计费依据
对话、嵌入输入 / 输出 token
图像输出图片张数
视频上游返回的实际时长(秒)
语音合成请求中的输入字符数

语音合成这条值得单独注意:它按你发出去的字符数算,而不是上游报告的用量。所以在 发请求前你就能准确预估成本。

视频完成时才计费

POST /v1/videos 提交时不计费,只做一次余额预检。等任务成功完成后,按上游返回的 实际秒数结算。

任务失败不计费,无需申请退款。

上游 4xx 不计费

上游返回 4xx 时,网关透传错误但不产生费用

服务维护期

实例进入排空(drain)状态时,所有非健康检查路径返回:

{"error": "instance draining"}

HTTP 状态 503。这是短暂的滚动更新窗口,重试即可恢复。注意这个响应体也不遵循统一 错误信封。

On this page