直接答案
遇到 HTTP 429,先减少同时未完成的请求,再做有限重试。官方限速页按账号统计并发,换同账号 API Key 不会增加配额;错误码页还提及 TPM / RPM,需结合接入渠道与返回信息判断。402 是余额不足,应先处理余额。
关键要点
- 确认官方还是第三方渠道
- 统计未完成请求,先降低并发
- 最多尝试 3 次并设总预算
- 超时或网络中断不盲目重放
看见什么错误,再决定做什么
错误展示示例:HTTP 429 Too Many Requests。这是用于识别状态码的示意文本,不是虚构的线上事故记录;实际响应字段和措辞以服务端为准。
| 响应 | 优先处理 | 本示例自动重试 |
|---|---|---|
| 429 | 检查并发与渠道限额,减速 | 最多共尝试 3 次 |
| 500 / 503 | 检查服务状态,短暂等待 | 最多共尝试 3 次 |
| 401 / 402 | 修复密钥 / 账户余额 | 否 |
| 400 / 422 | 修正请求体 / 参数 | 否 |
| 网络中断 / 超时 | 确认原请求是否已完成 | 否 |
按这个顺序检查并发
先确认 base URL 和密钥所属平台。官方按账号合并计算并发;第三方代理可能另有限额。不要把官方配额直接套到第三方渠道。
统计从发出到响应完成的所有请求,包括流式连接。单个进程并发很低,也可能被其他实例或定时任务占满账号配额。
把批任务改为有限工作池,先从单个工作任务验证,再逐步调高;多实例需共享配额和队列。积压达到上限时拒绝或延后新任务,避免内存里无限排队。
可下载运行的 Node.js 重试示例
需要 Node.js 20 或更新版本,无第三方依赖。下载下方文件,在终端通过环境变量 DEEPSEEK_API_KEY 提供密钥,然后运行 node deepseek-retry.mjs。真实运行会调用 API 并可能产生费用。
示例只处理无外部副作用的文本生成:最多 3 次尝试、单次最长 10 秒、整体 30 秒预算。收到 Retry-After 时同时支持秒数和 HTTP 日期;等待超出预算就停止。这里的超时是教学示例选择,复杂推理任务应按业务时延调整。
若使用 SDK,不要再叠加 SDK 默认重试;否则实际尝试次数会放大。此文件直接使用 fetch,未额外引入 SDK 重试。
// Node.js 20+. Run: DEEPSEEK_API_KEY=... node deepseek-retry.mjs
import { pathToFileURL } from 'node:url';
export async function callDeepSeek(messages, {
apiKey = process.env.DEEPSEEK_API_KEY,
fetchImpl = fetch,
sleep = ms => new Promise(resolve => setTimeout(resolve, ms)),
now = Date.now,
random = Math.random,
} = {}) {
if (!apiKey) throw new Error('请设置 DEEPSEEK_API_KEY');
const deadline = now() + 30_000;
for (let attempt = 0; attempt < 3; attempt++) {
const remaining = deadline - now();
if (remaining <= 0) throw new Error('已超过 30 秒总预算');
// 网络中断、超时直接抛出:请求是否完成不明确,不自动重放。
const response = await fetchImpl('https://api.deepseek.com/chat/completions', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'deepseek-v4-flash', messages, stream: false, max_tokens: 256 }),
signal: AbortSignal.timeout(Math.min(10_000, remaining)),
});
if (response.ok) return await response.json();
const status = response.status;
const retryAfter = response.headers.get('retry-after');
await response.body?.cancel();
// 401 / 402 / 400 / 422 等错误必须先修复;最多共尝试 3 次。
if (![429, 500, 503].includes(status) || attempt === 2) {
throw new Error(`HTTP ${status},停止自动重试`);
}
const seconds = retryAfter === null ? NaN : Number(retryAfter);
const serverWait = retryAfter === null ? 0 : Number.isFinite(seconds)
? Math.max(0, seconds * 1000)
: Math.max(0, Date.parse(retryAfter) - now());
const backoff = 1000 * 2 ** attempt + random() * 1000;
const waitMs = Math.max(backoff, Number.isFinite(serverWait) ? serverWait : 0);
if (waitMs >= deadline - now()) throw new Error('等待时间超过剩余预算,请排队后再试');
await sleep(waitMs);
}
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
const result = await callDeepSeek([{ role: 'user', content: '用一句话解释指数退避。' }]);
console.log(result.choices?.[0]?.message?.content ?? '响应未包含文本');
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
何时必须停止,如何验证修复
401、402、400、422 不会靠多等几秒自行修好。网络超时可能发生在服务端已经完成请求之后,所以示例直接抛出,不自动重放。
发送邮件、写库、支付等工具副作用应由业务层做幂等与去重;不要直接重试整段 Agent 工作流。持续 429 时暂停批任务、检查账号总并发,再根据实际需求申请扩容。
使用模拟响应测试:429 → 200 应恢复;连续 429 应在第 3 次停止;402 只请求一次;Retry-After 超过预算应直接退出。上线后比较 429 占比、完成率、队列等待时间和每个任务的实际调用次数。
来源与核验
核验于 2026-09-09,服务规则和价格可能调整。
常见问题
多建几个 API Key 能绕过限制吗?
官方并发按账号统计,同一账号增加 Key 不增加并发配额。
429 是不是余额不足?
官方余额不足对应 402。429 应排查限速或并发;第三方渠道需按其响应说明判断。
本示例能直接当完整生产队列吗?
不能。它是单次调用的有限重试示例。生产环境还需要有界队列、跨实例并发协调、取消机制和业务去重。