500 和 502 表示故障,而不是限制。因此,在这类错误中,它们是几乎可以立即重试的错误类型——不同于 429(你自己的速率限制)和 529(服务商已满负荷)。错误地重试这三者中的某一种,会把一次小故障变成你自己的事故。
错误
// Straight from the model provider (HTTP 500)
{
"type": "error",
"error": { "type": "api_error", "message": "Internal server error" }
}
// From a gateway or proxy in between (HTTP 502)
{
"error": {
"message": "Failed to reach upstream provider",
"type": "upstream_error",
"code": "upstream_error",
"param": null
}
}原因和解决方法一览
| 原因 | 解决方法 |
|---|---|
| 提供商侧的暂时性故障 | 使用指数退避和抖动重试,最多约 5 次。 |
| 连接已接受,但之后始终没有响应 | 这是卡住,不是错误。将首字节到达时间与总时长分别设限。 |
| 中间层返回了自己的 502 | 与模型无关。检查响应体是提供商的格式,还是代理的格式。 |
| 真实事故期间盲目重试 | 限制尝试次数并退避——否则你的重试会成为中断的一部分。 |
在选择补救措施前,区分 500、529 和 429
429 表示你超出了速率限制——请减速。529 表示提供商已达到容量上限——退避幅度要大得多、时间也要长得多。500/502 表示故障,通常持续时间很短,而且往往只影响某个请求。只有第三种适合快速重试,而把三者一视同仁,正是重试循环让事故恶化的原因。
重试 5xx,绝不重试 4xx
使用带抖动的指数退避,最多五次尝试。同一个辅助函数适用于所有提供商——400 或 422 下一次尝试仍会以同样方式失败,因此重试只是在付出延迟后得到同一个错误。
import time, random
from openai import OpenAI, APIStatusError
client = OpenAI(base_url="https://api.kunavo.com/v1", api_key="sk-kn-...")
def with_backoff(fn, max_retries=5):
for attempt in range(max_retries):
try:
return fn()
except APIStatusError as e:
if e.status_code not in (429, 500, 529):
raise # don't retry auth/validation errors
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else min(2 ** attempt, 30)
time.sleep(delay + random.uniform(0, 0.5)) # jitter avoids herds
raise RuntimeError("retries exhausted")
resp = with_backoff(lambda: client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "ping"}],
max_tokens=32,
))
print(resp.choices[0].message.content)将首字节时间与总时长分别限制
整个请求只设置一个超时,无法区分生成时间较长和连接已失效。为首字节设置较短的截止时间,为后续内容设置宽裕的截止时间;这样卡住时会快速失败,而真正缓慢的回答可以继续等待。
记录每次尝试的状态和延迟
没有每次尝试的记录,事后提供商事故和你自己的超时看起来完全一样。状态码、延迟和尝试次数就足以让你第二天区分两者。
如果你通过 Kunavo 调用
截至 2026 年 9 月,Kunavo 上的每个 Claude 模型都通过单一上游通道提供服务,因此该通道返回的 5xx 不会在请求内部重试:它会作为携带消息“Upstream provider error”的 502 返回给你(在 /v1/messages 上类型为 api_error),并且该请求按零成本记录。Kunavo 的请求内重试仅适用于配置了第二通道的模型:此时,超时、5xx、429 或 Kunavo 自有上游密钥被拒绝,都会在任何结果返回给你之前,先通过第二通道重试。这一机制适用于 /v1/messages、/v1/responses,以及 /v1/chat/completions 上的 Claude 模型。流式响应会在首段内容到达前暂缓发送,因此尚未开始传输的流中发生的错误也会重试;内容开始传输后,流传输中途的失败则由你处理。无论哪种情况,都请在你这一端保留本页所述的重试策略。 该行为背后的路由机制详见 我们的 AI 网关指南.
常见问题
返回 500 的请求会计费吗?
在 Kunavo 上不会——失败的请求按零成本记录。直接向提供商付费时情况各异,但 5xx 通常不会收费。
重试 500 会产生两个完成结果吗?
会。请求可能在模型已经生成内容后才失败。如果工作包含副作用,请先在你的服务层实现幂等,再添加重试。
500、502 和 529 的一句话区别是什么?
500 表示提供商发生故障,502 表示其前方的某个组件无法联系提供商,529 表示提供商达到容量上限——前两者应尽快重试,第三者要晚得多再试。