错误处理与重试
本文从实践角度讲怎么处理 Routic API 的错误和重试。完整的错误码列表见 HTTP 语义与错误载荷。
核心原则
- 始终记录
request_id——每个错误响应都带这个字段,联系支持时必带。 - 区分可重试和不可重试——429、500、503 可以重试;400、401、402、422 修了再发,不要傻重试。
- 用指数退避——不要立即重试,不要固定间隔重试。
可重试 vs 不可重试
| 状态码 | 能重试吗 | 原因 |
|---|---|---|
| 400 | ❌ | 你的请求有问题,重试一样会失败 |
| 401 | ❌ | API 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 的流式重连,或降级为非流式重试 |
相关文档
- HTTP 语义与错误载荷 — 完整错误码表
- 速率限制 — 限速细节
- 可观测性与请求 ID — 怎么追踪问题