生产事故里最常见的不是不会重试,而是乱重试:401/400 重试到天荒地老、429/5xx 又不退避。正确分工是:429/5xx/超时/连接错误才指数退避+抖动重试;400/401/404 立刻停、修 Key 或模型名;同一模型重试耗尽再切备用模型,并记录最终是哪个模型答的。

适用场景:批量任务、Agent 长跑、对稳定性有要求的线上服务。

retry rate-limit 429 fallback timeout production

操作步骤

  1. 关掉或摸清 SDK 默认重试(OpenAI/Anthropic SDK 默认约 2 次),避免和自己写的重试叠加。
  2. 定义可重试状态码集合 {429, 500, 502, 503, 504},退避 min(2**i, 8) 秒并加随机抖动。
  3. 设「重试预算」:单位时间重试占比设上限(如 10%),超预算直接失败或走 fallback——重试也是按 token 花钱的。
  4. 区分三层重试:请求级(原样重发)、修正级(把校验错误回喂模型改一次、截断时调大 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 频繁触发说明主模型或额度有问题,要告警而不是庆幸「还能用」。

注意事项

  • ⚠️ 并发批量任务不做客户端限流,本地测 5 个用户没事、上线 50 并发瞬间打满 RPM/TPM 出 429
  • ⚠️ 对流式请求用同一套重试(见第 14 条)
  • ⚠️ 把 401 也重试,掩盖 Key 失效/欠费等真问题

来源:https://dev.to/lucky_wang_52b64623a6001a/retries-timeouts-and-model-fallback-for-openai-compatible-apis-in-40-lines-of-python-3d9j