重试逻辑

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

服务端已经做的重试

不用你重复实现的部分:

  • 服务节点间自动容错 — 同一 model 在平台内有多个可用服务节点时,失败后会自动尝试后续节点
  • 模型提供方级容错 — 当一个模型可由多个模型提供方承载时,失败后会自动尝试其它提供方
  • 瞬时错误重试 — 429 / 5xx / timeout 由平台按内部策略做有限重试
  • 请求级重试 — 瞬时 502/503/504 自动重试,默认 2 次
这些处理对客户端透明。你收到 200 的响应时,可能已经经过平台内部的有限重试或服务节点间自动容错。

客户端需要做的重试

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

HTTP含义重试策略
429Rate limit做指数退避;当前不要假设一定有 Retry-After header
500平台内部错误立刻重试 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="https://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)—— 安全重试
  • 流式途中断开 —— 已经给用户展示了一半内容,重试会重复生成。 建议:把已收到的内容展示给用户,标红"生成中断",让用户决定是否重新生成

平台侧的容错策略

平台会在服务节点间自动容错,下面是默认的重试与冷却策略(仅作说明,对客户端透明,无需你自行配置):

yaml
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 后再纳入容错