
这篇讲什么拿到一把 OpenAI 兼容协议的 API Key 之后代码侧真正要做的只有两件事把base_url指到正确的网关地址把鉴权头写对。听起来简单但实际动手时最容易在路径拼接上翻车——十次报 404九次是/v1多写或少写。这篇按「环境准备 → 三种语言分别跑通 → 统一封装 → 404 定位」的顺序走一遍每一步都有可运行代码和实际输出。环境准备只需要装官方 SDK兼容协议的网关不需要额外依赖pip install openai1.0.0 # Python npm install openai # Node.js另外准备两个环境变量不要把密钥写死在代码里# Linux / macOS export LLM_API_KEYsk-xxxxxxxxxxxxxxxx export LLM_BASE_URLhttps://your-gateway.example.com/openai/v1# Windows PowerShell $env:LLM_API_KEY sk-xxxxxxxxxxxxxxxx $env:LLM_BASE_URL https://your-gateway.example.com/openai/v1这里的LLM_BASE_URL请替换成你所用平台文档里给出的兼容协议地址。有一点要先分清你登录管理密钥的站点域名和实际发起调用的接口域名往往不是同一个。前者是控制台后者才是要填进base_url的值。接入前务必在平台文档里核对这两个地址直接把控制台域名填进代码是新手最常见的第一个错。第一步理解 base_url 该写到哪一层OpenAI 兼容协议的路径结构是固定的网关根地址/v1/chat/completions而不同工具对base_url的处理方式不一样这是 404 的根源调用方式base_url 写到哪说明openai Python SDK.../openai/v1SDK 自动补/chat/completionsopenai Node SDK.../openai/v1同上字段名是baseURLcurl / requests 手写完整端点.../openai/v1/chat/completions没人替你拼路径部分三方框架视文档多数只到根地址框架内部可能已带/v1记一句话就够了SDK 写到/v1手写请求写完整端点。第二步鉴权怎么设置鉴权是标准的 Bearer Token放在 HTTP 请求头里Authorization: Bearer 你的Key Content-Type: application/json因为和官方协议完全一致所以官方 SDK 不需要任何改造只换base_url就能跑。用 SDK 时你甚至不用手写这个头传api_key参数即可SDK 会自动组装。第三步Python 跑通第一个请求import os from openai import OpenAI client OpenAI( api_keyos.environ[LLM_API_KEY], base_urlos.environ[LLM_BASE_URL], # 结尾到 /v1 ) resp client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个简洁的技术助手回答不超过两句话。}, {role: user, content: 用一句话解释什么是 Bearer Token}, ], temperature0.3, ) print(模型:, resp.model) print(回复:, resp.choices[0].message.content) print(用量:, resp.usage.prompt_tokens, , resp.usage.completion_tokens)实际输出内容每次略有不同模型: gpt-4o-mini 回复: Bearer Token 是一种把令牌放在 HTTP Authorization 头里传递的鉴权方式服务端凭这个令牌识别调用方身份。 用量: 42 38跑到这一步说明三件事同时正确了地址对、密钥有效、路径拼接没问题。第四步Node.js 版本import OpenAI from openai; const client new OpenAI({ apiKey: process.env.LLM_API_KEY, baseURL: process.env.LLM_BASE_URL, // 注意是 baseURL驼峰 }); const resp await client.chat.completions.create({ model: gpt-4o-mini, messages: [{ role: user, content: 写一句项目启动的欢迎语 }], }); console.log(resp.choices[0].message.content);Node 端有两个坑字段名是baseURL大写 URL不是base_url以及await顶层使用要求package.json里声明type: module否则改用.mjs后缀或包一层 async 函数。第五步curl 快速验活调试阶段想确认「到底是我的代码有问题还是密钥/地址有问题」用 curl 隔离最快curl $LLM_BASE_URL/chat/completions \ -H Authorization: Bearer $LLM_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 只回复两个字收到}] }返回结构长这样截取关键字段{ id: chatcmpl-xxxxxxxx, object: chat.completion, model: gpt-4o-mini, choices: [ { index: 0, message: { role: assistant, content: 收到 }, finish_reason: stop } ], usage: { prompt_tokens: 18, completion_tokens: 2, total_tokens: 20 } }注意 curl 这里拼的是$LLM_BASE_URL/chat/completions——因为环境变量已经带了/v1所以只补后半段。第六步封装成可复用的客户端真实项目里不会每处都 new 一个客户端。加上启动期校验和超时重试写成一个模块# llm_client.py import os import sys from openai import OpenAI REQUIRED (LLM_API_KEY, LLM_BASE_URL) def _check_env() - None: missing [k for k in REQUIRED if not os.environ.get(k)] if missing: print(f[fatal] 缺少环境变量: {, .join(missing)}, filesys.stderr) sys.exit(78) # 78 EX_CONFIG配置错误 _check_env() client OpenAI( api_keyos.environ[LLM_API_KEY], base_urlos.environ[LLM_BASE_URL], timeout30.0, max_retries2, ) def ask(prompt: str, model: str gpt-4o-mini) - str: resp client.chat.completions.create( modelmodel, messages[{role: user, content: prompt}], ) return resp.choices[0].message.content if __name__ __main__: print(ask(自检通过就回复 OK))两个细节值得说明。一是启动期就校验环境变量缺失直接退出而不是等第一次调用时抛一个语义模糊的鉴权错误退出码用 78 是沿用 sysexits 的约定容器编排和 CI 能据此区分配置问题和运行时问题。二是max_retries2让 SDK 自己处理瞬时网络抖动业务代码不用套一层 try/except 重试。404 定位清单如果上面任一步返回 404按这个顺序查基本一遍就能定位1. 打印实际请求的完整 URLimport httpx, logging logging.basicConfig(levellogging.DEBUG) # 或者手动拼一遍确认 print(os.environ[LLM_BASE_URL].rstrip(/) /chat/completions)2. 数一下/v1出现了几次出现两次/v1/v1/chat/completions说明 SDK 又补了一遍——把base_url里的/v1去掉或确认 SDK 是否需要你带。出现零次说明手写请求漏了。3. 确认没把控制台域名当接口域名这一条单独列出来因为它报的也是 404很容易被误判成路径问题。管理密钥的站点通常没有/v1/chat/completions这个路由。4. 用-v看真实响应头curl -v $LLM_BASE_URL/chat/completions -H Authorization: Bearer $LLM_API_KEY -d {}如果返回的content-type是text/html说明请求根本没进到 API 层八成是地址整个写错了返回 JSON 且带error.message才是 API 在正常回你。顺手记住另外两个常见状态码的区别能省不少排查时间401 是密钥错拼写、多余空格、引号被包进值里404 是路径错429 是频率限制。三者原因完全不重叠别混着试。小结配置 OpenAI 兼容接口本质就是两行base_url指向平台文档给出的网关地址鉴权用 Bearer Token。真正需要肌肉记忆的是路径规则——SDK 写到/v1手写请求写完整端点遇到 404 先数/v1的个数再确认域名有没有把控制台和接口搞混。把本文的llm_client.py复制进项目环境变量配好剩下的调用逻辑和官方写法完全一致不需要为兼容协议做任何额外适配。