重试逻辑

Swarmix 内部已经有多层重试,但客户端仍需要做外层兜底 —— 本章讲怎么分层不重复。

服务端已经做的重试

不用你重复实现的部分:

  • Deployment 级 — 同一 model 存在多个已配置候选时,失败后可尝试后续候选
  • Provider 级 — 只有候选链里配置了多个 provider 时,才可能在失败后尝试其它 provider
  • 上游瞬时错误重试 — 429 / 5xx / timeout 按 Router 配置做有限重试
  • 请求级重试 — 瞬时 502/503/504 自动重试,可配次数(默认 2 次)
这些处理对客户端**透明**。你收到 200 的响应时,可能已经经过内部有限重试或失败候选处理。

客户端需要做的重试

以下情况服务端不会帮你重试,需要客户端兜底:

HTTP含义重试策略
429Rate limit做指数退避;当前不要假设一定有 Retry-After header
500Router 内部错误立刻重试 1-2 次,仍失败则提醒用户
502当前模型没有可用上游候选退避 10s+ 后重试,或检查模型、provider 控制和上游状态
504上游超时退避 3-5s 重试
401 / 402 / 403认证 / 余额 / 权限不要重试 — 重试无意义还浪费配额
400请求格式错不要重试
连接级错误timeout / connection reset立刻重试 1 次(可能是客户端 → CDN 抖动)

推荐的客户端退避函数

python
import time
import random
from openai import OpenAI, APIError, RateLimitError, APIStatusError

client = OpenAI(
    api_key="sk-swx-xxxx",
    base_url="http://router.swarmixtoken.com/v1",
    max_retries=0,   # 关闭 SDK 自带重试 — 我们自己实现
)

RETRYABLE = {429, 500, 502, 503, 504}

def chat_with_retry(**kwargs):
    max_attempts = 4
    for attempt in range(max_attempts):
        try:
            return client.chat.completions.create(**kwargs)

        except RateLimitError as e:
            # 如果服务端返回 Retry-After 则使用,否则按 1 秒起步退避
            retry_after = int(e.response.headers.get("retry-after", 1))
            wait = retry_after + random.uniform(0, 0.5)
            print(f"429, 等 {wait:.1f}s 后重试 (attempt {attempt+1})")
            time.sleep(wait)

        except APIStatusError as e:
            if e.status_code not in RETRYABLE:
                raise   # 永久性错误,不重试
            wait = min(60, (2 ** attempt) + random.uniform(0, 1))
            print(f"{e.status_code}, 等 {wait:.1f}s 后重试")
            time.sleep(wait)

        except (ConnectionError, TimeoutError):
            wait = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(wait)

    raise RuntimeError(f"达到最大重试次数 {max_attempts}")

重试的幂等性

Chat Completions 不是幂等的
同一个 request 重试会**生成两个不同的响应**(不同 token 不同 content)。如果你在做 "消息发送"类业务,注意对用户只展示第一次成功的结果,丢弃重试产生的副本。

流式请求的重试

流式请求中途断开的处理:

  • 连接建立前失败(收不到第一个 chunk)—— 安全重试
  • 流式途中断开 —— 已经给用户展示了一半内容,重试会重复生成。 建议:把已收到的内容展示给用户,标红"生成中断",让用户决定是否重新生成

在 Swarmix 配置上游重试次数

企业私有部署的 router_config.yaml 里可以调 retry policy:

yaml
router_settings:
  retry_policy:
    rate_limit: 3        # 429 重试 3 次
    timeout: 2           # 超时重试 2 次
    internal_server: 2   # 5xx 重试 2 次
    bad_request: 0       # 400 不重试
    auth: 0              # 401 不重试
  cooldown_time: 60      # 失败候选冷却 60s