重试
哪些错误该重试、要等多久,以及正确实现重试的代码。
哪些要重试
| 返回 | 重试? | 方法 |
|---|---|---|
429、503、529 | 是 | 等待 Retry-After-Ms 之后 |
500、502、504 | 是 | 短暂退避 1 到 2 秒之后 |
400、401、402、403、404、413 | 否 | 同样的调用会以同样的方式失败。先修正 |
| 收到任何返回之前的网络错误 | 是 | 短暂退避之后 |
| 流式输出中的错误 | 通常是 | 重新发送整个调用。你只需为已生成的内容付费 |
网关自己从不重试调用:由你的 SDK 来重试,这样重试次数不会成倍增加。
官方 SDK 已经帮你做了
OpenAI 和 Anthropic 的 SDK 默认会对 429 和 5xx 返回重试两次,并等待 Retry-After-Ms。对于长时间无人值守的任务,请调高次数:
const client = new OpenAI({
baseURL: "https://binference.io/api/v1",
apiKey: process.env.BINF_API_KEY,
maxRetries: 5,
});自己实现
使用原生 fetch 时,从响应头读取等待时间,再加一点随机性:
async function call(body: unknown, tries = 5): Promise<Response> {
for (let attempt = 1; ; attempt++) {
const response = await fetch("https://binference.io/api/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BINF_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const retryable = response.status === 429 || response.status >= 500;
if (!retryable || attempt >= tries) return response;
const named = Number(response.headers.get("retry-after-ms"));
const wait = Number.isFinite(named) && named > 0 ? named : 1_000 * 2 ** (attempt - 1);
await new Promise((resolve) => setTimeout(resolve, wait + Math.random() * 250));
}
}时间限制
- 流式调用:最长 30 分钟。
- 非流式调用:最长 13 分钟。
- 到达时间限制时,调用会以一个明确的错误结束,并按已生成的内容扣费。
请把客户端的超时时间设得比这些更长,或者使用流式输出:有些 SDK 会在连接 10 分钟没有任何数据后放弃。