跳到主要内容
AIRouter
关于我们
登录免费注册
AIRouter

统一接入全球大模型,按量计费,无最低消费。

support@airouter.hk

产品

  • 模型广场
  • 计费口径
  • 免费开始

开发者

  • 文档
  • 快速开始
  • 服务状态
  • API Key 管理

公司

  • 关于我们
  • 服务条款
  • 隐私政策

支持

  • 帮助中心
  • 登录
  • 进入控制台

© 2026 AIRouter. 保留所有权利。AIRouter 是模型聚合与路由服务,模型能力由各供应商提供。

所有系统运行正常

开发者文档

文档目录

入门

  • 平台介绍
  • 快速开始
  • 鉴权

API 参考

  • 对话补全
  • 图像生成
  • 文本向量化
  • 重排
  • 视频生成
  • 搜索与阅读
  • 模型与路由

平台机制

  • 计费口径
  • 错误码与排查

入门

  • 平台介绍
  • 快速开始
  • 鉴权

API 参考

  • 对话补全
  • 图像生成
  • 文本向量化
  • 重排
  • 视频生成
  • 搜索与阅读
  • 模型与路由

平台机制

  • 计费口径
  • 错误码与排查

错误码与排查

统一错误信封、全部错误码,以及该重试哪些、不该重试哪些。

错误信封#

错误信封按入站方言给,两种形状。OpenAI 方言(/v1/chat/completions、/v1/videos、/v1/models):

json
{  "error": {    "message": "账户余额不足",    "type": "insufficient_quota",    "code": "insufficient_balance",    "param": "model"  },  "request_id": "01JQ8Z3P9K7V2M4X6B8N0C1D3E"}

Anthropic 方言(/v1/messages):

json
{  "type": "error",  "error": {    "type": "invalid_request_error",    "message": "账户余额不足"  },  "request_id": "01JQ8Z3P9K7V2M4X6B8N0C1D3E"}
  • code 是机器可读的稳定标识,请以它为分支依据。注意 Anthropic 方言里没有 code——那条端点上只能按 HTTP 状态与 error.type 分支。
  • type 是为兼容 SDK 的重试逻辑而映射的官方取值,不要用它区分具体原因。
  • param 只在参数类错误上出现,给出出错的字段名。
  • request_id 与响应头 X-Request-Id 一致,报障时提供它即可直达明细。
  • 更细的结构化信息(命中的限流键、被剔除的线路、上游状态码等)不在响应体里,按 request_id 去 调用日志 查。

错误码总表#

鉴权与令牌

codeHTTP含义
missing_credential401没带 API Key。
invalid_credential401Key 无效(也包括拿控制台 JWT 来调网关)。
key_disabled403该 Key 已被禁用。
key_expired403该 Key 已过期。
key_quota_exhausted402该 Key 的额度用尽。
ip_not_allowed403来源 IP 不在该 Key 的白名单内。
model_not_allowed403该 Key 不允许访问这个模型。

请求与参数

codeHTTP含义
invalid_request400参数不合法,出错字段名在 error.param。
unsupported_feature400所选模型或线路不支持该功能。
context_too_long400输入超出上下文窗口。
model_not_found404模型不存在或已下线。
request_too_large413请求体过大,通常是内联 base64 图片太大。

幂等键(带了 Idempotency-Key 才会出现)

codeHTTP含义
idempotency_key_in_use409同一个键的上一次请求还在跑。退避几秒后用同一个键重试,这一刻没有被扣第二次钱。
idempotency_key_replayed409同一个键已经执行过一次,本次没有再调上游也没有再计费。原请求 ID 在 error.details 里,正文去调用日志取。
idempotency_key_reused400同一个键这次的请求内容变了。换一个键——改了内容就是一个新请求。

计费与额度

codeHTTP含义
insufficient_balance402余额不足。所需与可用金额在调用日志里。
billing_unavailable503计费服务暂时不可用,可退避重试。
quota_lease_exhausted503区域额度租约暂时不可用,可退避重试。

限流

codeHTTP含义
rate_limited429命中 RPM / TPM 限速。
concurrency_limited429并发数超限,流式长连接会长时间占用并发位。

路由与上游

codeHTTP含义
no_candidate503过滤后没有可用线路。最常见的原因是 provider 写得太严。
all_candidates_failed502所有候选都试过仍失败——网关已经替你重试过了。
upstream_timeout504上游超时。卡在连接、首字还是总时长,看调用日志的路由轨迹。
upstream_error502上游返回错误。上游状态码在调用日志里。
upstream_rate_limited429上游限流,网关已尝试换线。
upstream_overloaded503上游过载,高峰期常见。
circuit_open503目标线路熔断中,探测成功后自动放回。
empty_completion502上游 200 但零产出。本次不收费。
content_filtered400内容被审核拦截。

客户端与内部

codeHTTP含义
client_closed_request499客户端主动断开。
internal_error500平台内部错误,请带 request_id 报障。
not_found404资源不存在。
conflict409状态冲突,例如取消一个已经在跑的视频任务。
region_denied403该请求不允许在当前区域处理。

搜索阅读是另一条产品线(sk-srp- 密钥),错误码是独立的 serp_* 一族,不与上表混用:拿推理 Key 调搜索接口会拿到 serp_key_invalid,反之亦然。

重试策略#

不要对所有错误统一重试。下面三档是按「重发整个请求有没有意义」分的。

档位错误码
不要重试(配置或请求本身的问题)missing_credential invalid_credential key_disabled key_expired key_quota_exhausted ip_not_allowed model_not_allowed invalid_request unsupported_feature context_too_long model_not_found request_too_large insufficient_balance content_filtered no_candidate
尊重 Retry-After 后重试rate_limited concurrency_limited upstream_rate_limited
指数退避重试(初始 1s,×2,最多 3 次,加 ±20% 抖动)billing_unavailable quota_lease_exhausted upstream_timeout upstream_error upstream_overloaded circuit_open empty_completion
已经产出过 token 的请求不要整体重发——那部分已经计费,重发会重复付钱。empty_completion 相反:它不计费,直接重试的成本是零。

Python:只重试该重试的,并且尊重 Retry-After

python
import random, time, requests
# 429 是限流,5xx 是我方或上游的临时故障:这两类值得重试。# 4xx 里的其余错误是请求本身有问题,重试多少次结果都一样。RETRIABLE = {429, 500, 502, 503, 504}

def call_with_retry(url, body, headers, attempts=4):    for attempt in range(attempts):        response = requests.post(url, json=body, headers=headers, timeout=120)        if response.status_code not in RETRIABLE:            return response        if attempt == attempts - 1:            break
        # 服务端说了等多久就等多久,没说才自己退避。        # 随机抖动是为了避免一批客户端在同一毫秒一起重来。        wait = response.headers.get("Retry-After")        delay = float(wait) if wait else (2**attempt) + random.random()        time.sleep(delay)
    return response

限流#

限流有 RPM、TPM、并发三个维度。RPM 与 TPM 按 API Key 与账户两级判定,并发按账户判定。

  • RPM 与 TPM 超限都返回 rate_limited(429),并发占满返回 concurrency_limited(429)。
  • TPM 扣的是估算的输入 token——真实用量要等上游返回,那时限流已经来不及了。
  • 429 一律带 Retry-After(秒,至少 1)。请按它退避,盲目重试只会把自己限得更死。
  • 流式长连接会一直占着并发位直到流结束,所以并发限额通常比你以为的更早撞上。
  • 限流组件自身故障时选择放行:限流不该成为可用性的单点。

怎么排查一次失败#

  1. 1

    拿到 request_id

    响应头 X-Request-Id,或错误体里与 error 同级的 request_id,两者一致。

  2. 2

    在调用日志里搜它

    调用日志 支持按 request_id 精确查,能看到请求参数摘要、路由轨迹与计费明细。

  3. 3

    看路由轨迹

    它列出每次尝试用了哪条线路、上游状态码与耗时。all_candidates_failed 基本都能在这里看出是哪一环挂了。

  4. 4

    还是不清楚就提工单

    带上 request_id 开 工单,不用附完整请求体。

两个高频误报
把视频模型发到 /v1/chat/completions 会返回 400 并提示改用 POST /v1/videos;no_candidate 绝大多数不是「没模型」,而是 provider 的约束把所有线路都筛掉了——去 调用日志 看路由轨迹,每条线路是被哪个条件筛掉的都写着。
上一篇计费口径

本页目录

  • 错误信封
  • 错误码总表
  • 重试策略
  • 限流
  • 怎么排查一次失败