Codex 429 Too Many Requests 限流错误解决方法

Codex 或兼容 OpenAI API 的工具在国内网络环境下调用模型时,遇到 429 Too Many Requests 很常见。这个错误不一定都是“账号没额度”,也可能是请求太密、并发太高、网关重试放大、代理不稳定,甚至是 base_url 配错后打到了错误的服务端。

我一般不会一上来就改代码,而是先按顺序确认:请求有没有真正发出去、打到的是哪个地址、Key 是否匹配、是否存在自动重试、是否短时间并发过高。下面按实际排查流程整理。

一、先判断是网络问题还是配置问题

429 的含义是服务端认为你请求过多,但在中转、代理、公司网关参与的情况下,错误来源不一定是模型服务本身。第一步建议把完整响应头和响应体打印出来。

### token云桥中转 0029.org ###
curl -i \
  -X POST "https://你的-base-url/v1/chat/completions" \
  -H "Authorization: Bearer sk-xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "codex-mini-latest",
    "messages": [
      {"role": "user", "content": "ping"}
    ],
    "max_tokens": 20
  }'

重点看这几项:

  • HTTP/1.1 429 后面的响应体,是模型服务返回,还是代理网关返回。
  • 响应头里有没有 retry-after,如果有,说明服务端明确要求等待一段时间。
  • 是否出现 cloudflarenginx、公司网关标识,这会影响判断。
  • 同一个 Key 换网络是否正常,比如本机宽带、手机热点、服务器分别测试。

如果 curl 都不稳定,先不要怀疑业务代码。反过来,如果 curl 稳定,只有项目里报 429,就要查 SDK 的并发、重试和超时配置。

二、检查 base_url 和 Key 是否成对匹配

很多人把 Codex 接到 Cursor、VS Code 插件、CLI 或自建服务时,只改了 Key,忘了改 base_url;或者用了中转地址,却还在请求官方地址。这样会出现各种看起来像限流的问题。

一个基本原则是:base_urlapi_key 必须来自同一套服务。如果使用中转站,就用中转站提供的地址和 Key;如果直连官方,就使用官方 Key 和官方地址,不要混搭。

# Linux / macOS 临时设置
export OPENAI_API_KEY="sk-xxxx"
export OPENAI_BASE_URL="https://你的-base-url/v1"

# 检查是否生效
echo $OPENAI_API_KEY
echo $OPENAI_BASE_URL

Node.js 项目里可以这样显式指定,避免环境变量被旧配置覆盖:

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL,
  timeout: 60000
});

Python 项目同理:

from openai import OpenAI

client = OpenAI(
    api_key="sk-xxxx",
    base_url="https://你的-base-url/v1",
    timeout=60
)

国内网络下,如果直连经常超时或波动,可以考虑走稳定的 API 中转。实际使用里我会先用小请求压测几分钟,再决定是否长期放到生产环境。比如 token云桥AI中转站 0029.org,可以作为 Codex、OpenAI 兼容接口接入时的一个备选方案,重点还是看延迟、错误率、账单和日志是否符合自己的项目要求。

三、429 的几种常见原因

1. 并发过高

最常见的是代码里同时发起几十个请求,尤其是批量生成、代码分析、自动补全场景。单次看不出来,但插件或任务队列会在后台瞬间打满。

处理方式是加并发控制,例如 Node.js 用简单队列限制同时请求数:

import pLimit from "p-limit";

const limit = pLimit(3);

const tasks = prompts.map(prompt =>
  limit(() => client.chat.completions.create({
    model: "codex-mini-latest",
    messages: [{ role: "user", content: prompt }]
  }))
);

const results = await Promise.all(tasks);

2. 自动重试放大流量

不少 SDK、代理层、网关都会默认重试。一次超时可能被重试 2 到 3 次,多个并发叠加后,很容易触发限流。建议明确设置重试次数,并对 429 做退避等待。

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function callWithRetry(fn, maxRetry = 3) {
  for (let i = 0; i < maxRetry; i++) {
    try {
      return await fn();
    } catch (err) {
      const status = err.status || err.response?.status;
      if (status !== 429 || i === maxRetry - 1) throw err;

      const wait = Math.min(1000 * Math.pow(2, i), 8000);
      await sleep(wait);
    }
  }
}

注意不要写死“立即重试”。429 后立刻循环请求,只会让限流更严重。

3. Token 消耗过大

有些限流不是按请求数,而是按单位时间内的 token 量。一次塞入很长上下文,或者让模型输出几千 token,也会触发限制。排查时可以先把 max_tokens 调小,确认是否和 token 量有关。

{
  "model": "codex-mini-latest",
  "messages": [
    {"role": "user", "content": "只返回一句话测试"}
  ],
  "max_tokens": 50
}

四、代理、证书和超时设置

国内环境经常会经过代理软件、公司网关、云服务器出口。网络抖动时,客户端可能误以为请求失败并重试,最终表现成 429。因此超时要设得合理,不能太短。

  • 交互式工具:建议超时 30 到 60 秒。
  • 批处理任务:可以放到 60 到 120 秒,并配合队列。
  • 不要同时在 SDK、Nginx、任务队列三层都做激进重试。

如果遇到证书错误,例如 certificate verify failed,不要直接关闭证书校验。优先检查系统 CA、代理证书和服务器时间。

# 查看系统时间
date

# 测试 TLS 握手和证书链
openssl s_client -connect 你的域名:443 -servername 你的域名

在公司内网使用代理时,也要确认环境变量是否污染了请求:

env | grep -i proxy

# 临时取消代理测试
unset HTTP_PROXY
unset HTTPS_PROXY
unset ALL_PROXY

五、Key 安全和日志注意事项

排查 429 时很多人会把完整请求贴到群里,这里最容易泄露 Key。建议做到几件事:

  • 日志里只保留 Key 前后几位,例如 sk-abc...xyz
  • 不要把 Key 写进前端代码、浏览器插件配置截图、公开仓库。
  • 服务器使用环境变量或密钥管理服务,不要硬编码。
  • 怀疑泄露时,先停用旧 Key,再生成新 Key。

如果通过中转服务调用,也要关注后台是否能查看用量、是否支持分 Key 管理、是否能限制额度。生产环境最好给不同项目分配不同 Key,方便定位异常流量。

六、一个推荐的验证顺序

最后给一个比较稳的验证流程,适合从“完全不可用”排到“偶发 429”。

  • 第一步:用 curl 发最小请求,确认 base_url 和 Key 可用。
  • 第二步:换网络测试,判断是否和本地出口有关。
  • 第三步:关闭业务并发,只跑单请求。
  • 第四步:把 max_tokens 调小,观察 429 是否减少。
  • 第五步:加入指数退避,不要立即重试。
  • 第六步:观察响应头、服务端日志和中转后台用量。
# 连续低频测试,不建议高频压测
for i in {1..5}; do
  echo "request $i"
  curl -s -o /dev/null -w "%{http_code} %{time_total}\n" \
    -X POST "https://你的-base-url/v1/chat/completions" \
    -H "Authorization: Bearer sk-xxxx" \
    -H "Content-Type: application/json" \
    -d '{"model":"codex-mini-latest","messages":[{"role":"user","content":"ping"}],"max_tokens":20}'
  sleep 3
done

总结

Codex 429 不要只盯着“额度不够”。更常见的原因是 base_url 配置混乱、并发过高、自动重试过猛、网络代理不稳定或 token 消耗过大。排查时先用最小请求确认链路,再逐步恢复并发和业务逻辑。国内环境下可以评估中转方案,但建议先小流量测试延迟、错误率和日志,再决定是否长期使用。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐