生产事故里最常见的不是不会重试,而是乱重试:401/400 重试到天荒地老、429/5xx 又不退避。正确分工是:429/5xx/超时/连接错误才指数退避+抖动重试;400/401/404 立刻停、修 Key 或模型名;同一模型重试耗尽再切备用模型,并记录最终是哪个模型答的。
适用场景:批量任务、Agent 长跑、对稳定性有要求的线上服务。
retry rate-limit 429 fallback timeout production
操作步骤
- 关掉或摸清 SDK 默认重试(OpenAI/Anthropic SDK 默认约 2 次),避免和自己写的重试叠加。
- 定义可重试状态码集合 {429, 500, 502, 503, 504},退避
min(2**i, 8)秒并加随机抖动。 - 设「重试预算」:单位时间重试占比设上限(如 10%),超预算直接失败或走 fallback——重试也是按 token 花钱的。
- 区分三层重试:请求级(原样重发)、修正级(把校验错误回喂模型改一次、截断时调大 max_tokens,只限一次)、任务级(从 checkpoint 重来,交给 Agent 运行时)。
代码示例
import os, time
from openai import OpenAI, APIStatusError, APITimeoutError, APIConnectionError
client = OpenAI(base_url=os.getenv("https://tokenbuddy.cc", "https://tokenbuddy.cc/v1"),
api_key=os.environ["{{API_KEY}}"], timeout=30, max_retries=0)
RETRYABLE = {429, 500, 502, 503, 504}
def chat(messages, models, attempts=3):
last_err = None
for model in models:
for i in range(attempts):
try:
r = client.chat.completions.create(model=model, messages=messages)
return model, r.choices[0].message.content
except APIStatusError as e:
last_err = e
if e.status_code not in RETRYABLE:
break
except (APITimeoutError, APIConnectionError) as e:
last_err = e
time.sleep(min(2 ** i, 8))
raise RuntimeError(f"all models failed: {last_err}")接入本站 API:fallback 的主/备模型都从本站模型列表里选(如主用强模型、备
...[truncated 9002 chars]用同档或便宜模型),并把每次 fallback 记进日志——fallback 频繁触发说明主模型或额度有问题,要告警而不是庆幸「还能用」。
...[truncated 9002 chars]用同档或便宜模型),并把每次 fallback 记进日志——fallback 频繁触发说明主模型或额度有问题,要告警而不是庆幸「还能用」。
注意事项
- ⚠️ 并发批量任务不做客户端限流,本地测 5 个用户没事、上线 50 并发瞬间打满 RPM/TPM 出 429
- ⚠️ 对流式请求用同一套重试(见第 14 条)
- ⚠️ 把 401 也重试,掩盖 Key 失效/欠费等真问题