错误处理与重试

本文从实践角度讲怎么处理 Routic API 的错误和重试。完整的错误码列表见 HTTP 语义与错误载荷

核心原则

  1. 始终记录 request_id——每个错误响应都带这个字段,联系支持时必带。
  2. 区分可重试和不可重试——429、500、503 可以重试;400、401、402、422 修了再发,不要傻重试。
  3. 用指数退避——不要立即重试,不要固定间隔重试。

可重试 vs 不可重试

状态码能重试吗原因
400你的请求有问题,重试一样会失败
401API Key 不对,重试没用
402余额不足,先充值
422参数组合有问题,改了再发
429速率限制,等一会儿就好
500服务端临时故障
503模型提供商暂时不可用

重试怎么做

推荐带抖动的指数退避

延迟 = min(1秒 × 2^尝试次数 + 随机抖动, 60秒)
  • 基础延迟 1 秒
  • 最多重试 3 次
  • 最大延迟 60 秒
  • 抖动范围 0–500 毫秒(防止雪崩)

Python(OpenAI SDK 自带重试)

OpenAI SDK 内置了自动重试,只需配置:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.routic.ai/v1",
    api_key="sk-xxxxxxxx",
    max_retries=3,      # 最多重试 3 次
    timeout=30.0,       # 单次请求超时 30 秒
)

# 429/500/503 会自动重试,你不用写任何重试逻辑
response = client.chat.completions.create(
    model="deepseek-r1",
    messages=[{"role": "user", "content": "你好"}],
)

Python(手动重试)

如果不用 SDK 或需要更精细的控制:

import time
import random
from openai import OpenAI

client = OpenAI(
    base_url="https://api.routic.ai/v1",
    api_key="sk-xxxxxxxx",
    max_retries=0,  # 关闭 SDK 自动重试,自己控制
)

def call_with_retry(messages, max_retries=3):
    for attempt in range(max_retries + 1):
        try:
            return client.chat.completions.create(
                model="deepseek-r1",
                messages=messages,
            )
        except Exception as e:
            # 非可重试错误,直接抛出
            if hasattr(e, 'status_code') and e.status_code in (400, 401, 402, 422):
                raise

            # 可重试错误,退避
            if attempt < max_retries:
                delay = min(1 * (2 ** attempt) + random.uniform(0, 0.5), 60)
                print(f"第 {attempt + 1} 次失败,{delay:.1f} 秒后重试...")
                time.sleep(delay)
            else:
                raise

Node.js(OpenAI SDK)

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.routic.ai/v1",
  apiKey: "sk-xxxxxxxx",
  maxRetries: 3,
});

幂等性

Routic 的对话接口不是幂等的——同样的请求发两次,会消耗两次 token。所以:

  • 不要在重试时发一模一样的请求——除非是 429/500/503(这些是因为服务端问题,第一次请求大概率没有成功处理)
  • 400/401/402/422 不要重试——这些错误说明第一次请求已经到达服务端并被拒绝,重试只会白费

429 速率限制的特殊处理

429 响应可能包含 Retry-After 响应头,告诉你需要等多少秒:

except RateLimitError as e:
    retry_after = e.response.headers.get("retry-after")
    if retry_after:
        wait = int(retry_after)
    else:
        wait = 5  # 默认等 5 秒
    time.sleep(wait)

如果业务对延迟敏感,可以考虑:

  • 多个 API Key 轮换(每个 Key 独立限速)
  • 用智能路由名(auto/chat),让网关自动选更空闲的模型
  • 联系支持提高速率限制

常见坑

问题原因解决
重试越重越慢没有抖动,所有客户端同时重试加随机抖动 0–500ms
401 反复重试Key 过期了还在重试401 不重试,换 Key
429 雪崩限速后立即重试等待 Retry-After 或至少 5 秒
流式输出中断网络抖动,不是服务端错误用 SDK 的流式重连,或降级为非流式重试

相关文档