重试逻辑
Swarmix 内部已经有多层重试,但客户端仍需要做外层兜底 —— 本章讲怎么分层不重复。
服务端已经做的重试
不用你重复实现的部分:
- 服务节点间自动容错 — 同一 model 在平台内有多个可用服务节点时,失败后会自动尝试后续节点
- 模型提供方级容错 — 当一个模型可由多个模型提供方承载时,失败后会自动尝试其它提供方
- 瞬时错误重试 — 429 / 5xx / timeout 由平台按内部策略做有限重试
- 请求级重试 — 瞬时 502/503/504 自动重试,默认 2 次
这些处理对客户端透明。你收到 200 的响应时,可能已经经过平台内部的有限重试或服务节点间自动容错。
客户端需要做的重试
以下情况服务端不会帮你重试,需要客户端兜底:
| HTTP | 含义 | 重试策略 |
|---|---|---|
| 429 | Rate 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 后再纳入容错