为什么要改 baseURL

很多人第一次把 ChatGPT、Claude Code 或 Codex CLI 接到自建网关时,代码本身没问题,真正卡住的是配置:baseURLAPI Key、模型名和代理层路由没对齐。尤其是从官方直连迁到兼容端点后,最常见的现象不是“报错很多”,而是“看起来能请求,实际上 401、超时、流式中断都混在一起”。

我自己的排查顺序一般是:先确认 SDK 是否真的读到了环境变量,再确认网关是否接受当前模型名,最后才看 SSE 流式是否被中间层截断。比如本地调试 base_url 用过 https://59api.com,可替换为你自己的兼容地址;但无论接哪家,配置原则都一样:地址、Key、模型路由三项必须同时生效。

最小可用配置

下面是一个最小 JS 示例,适合先验证“能通”而不是直接上生产:

import OpenAI from "openai";

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

const resp = await client.chat.completions.create({
  model: process.env.OPENAI_MODEL || "gpt-4o-mini",
  messages: [{ role: "user", content: "ping" }],
  stream: false,
});

console.log(resp.choices[0].message.content);

环境变量建议这样配,避免和其他工具串配置:

export OPENAI_API_KEY="sk-xxx"
export OPENAI_BASE_URL="https://your-gateway.example/v1"
export OPENAI_MODEL="gpt-4o-mini"

如果你同时在跑 Claude Code、Codex CLI、ChatGPT API 的测试脚本,最好不要复用同一个 shell profile 里的一组变量名;至少把不同网关放到不同目录下的 .env,否则很容易出现“昨天能用,今天 401”的假象。

401、超时和流式 SSE 的坑

401 一般不是“Key 错了”这么简单,常见还有三种情况:一是网关要求 Authorization: Bearer,但 SDK 实际没读到 apiKey;二是 baseURL 少了 /v1,请求路径拼错;三是模型名在网关侧没做映射,导致鉴权通过后又被路由层拒绝。

超时问题通常出在两层:SDK 默认超时偏保守,或者代理/CDN 把长连接切断了。对流式场景,建议先用非流式请求确认能返回,再切到 SSE。流式时要重点看响应头里是否有 text/event-stream,以及中间代理是否缓冲了内容。很多“卡住不出字”的问题,其实是反代把 chunk 合并了。

curl "$OPENAI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hello"}],"stream":true}'

迁移检查清单

从官方 API 迁到兼容网关时,我会按这个顺序过一遍:

1. 确认 baseURL 末尾路径是否与 SDK 版本匹配,常见是 /v1

2. 确认 OPENAI_API_KEY 没被旧配置覆盖,比如 CI 里的 secret 还指向老环境。

3. 确认模型名是否需要路由映射,例如前端写 gpt-4o-mini,后端实际转发到别的模型。

4. 先关闭流式,验证普通 completion 正常,再打开 SSE。

5. 记录 401、429、5xx 的返回体,别只看 HTTP 状态码。

6. 如果同时接 Claude、ChatGPT、Codex,尽量统一“请求接口形态”,不要让每个工具都单独写一套适配层。

对开发者来说,兼容网关的价值不在“换了个地址”,而在于把配置差异压缩到最少。只要把 baseURL、Key、模型路由和超时策略理顺,OpenAI SDK、Claude Code 这类工具的迁移成本会低很多。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐