OpenAI SDK 迁移指南:一行 base_url 切换到 EXAIV
OpenAI SDK 迁移指南:一行 base_url 切换到 EXAIV
你已经有一套跑在 OpenAI SDK 上的应用,想换到 EXAIV 的模型池,最关心的通常不是「能不能用」,而是「要改多少代码」。答案是:绝大多数应用只需要改两处——base_url 和 API Key。请求格式、消息结构、流式处理、错误类型都不变,因为 EXAIV 提供的就是 OpenAI Chat Completions 兼容端点。
这篇指南按迁移的实际顺序展开:先改哪里、怎么验证改对了、model 字段怎么映射、哪些行为要重新测,以及出问题时怎么回滚。全程不需要改你的业务逻辑。
30 秒版本
Python 里把 OpenAI(api_key=..., base_url="https://exaiv.com/api/ai/v1") 两个参数换掉,model 字段填平台目录里的模型 ID,其余代码原样保留。
改动清单:先看全局
| 位置 | 原值(OpenAI) | 新值(EXAIV) |
|---|---|---|
| base_url | https://api.openai.com/v1 | https://exaiv.com/api/ai/v1 |
| API Key | sk-...(OpenAI 密钥) | 平台控制台生成的 Key |
| model | OpenAI 模型名 | 目录模型 ID(如 kimi-k3) |
| 请求/响应结构 | — | 不变 |
| SDK 版本 | — | 不变 |
注意 base_url 以 /v1 结尾:SDK 会自己在后面拼 /chat/completions。如果你把完整路径写进 base_url,实际请求会变成 /chat/completions/chat/completions,返回 404。这是迁移中最常见的第一个错误。
Python:openai SDK
先确认 SDK 版本足够新(v1.x 以上),旧版写法差异较大:
pip install --upgrade openai
改动前后的对比:
# 之前
from openai import OpenAI
client = OpenAI() # 读 OPENAI_API_KEY,指向 api.openai.com
# 之后
const client = new OpenAI({
apiKey: process.env.EXAIV_API_KEY,
baseURL: "https://exaiv.com/api/ai/v1",
});
const resp = await client.chat.completions.create({
model: "qwen3.8-max",
messages: [{ role: "user", content: "用一句话介绍你自己。" }],
max_tokens: 128,
});
console.log(resp.choices[0].message.content);
字段名差异提醒:Python 参数是 base_url,npm 包是 baseURL。混用是最常见的笔误来源。
先用 curl 验证,再动代码
改代码之前,先用 curl 确认 Key 和端点是通的。这样后面出问题时可以确定「端点侧没问题,是代码侧的问题」:
curl -sS https://exaiv.com/api/ai/v1/chat/completions \
-H "Authorization: Bearer ${EXAIV_API_KEY}" \
-H "content-type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [{"role": "user", "content": "Reply with OK."}],
"max_tokens": 8
}'
返回 200 且 choices[0].message.content 有内容,端点侧验证就完成了。
model 字段:唯一的「翻译」工作
OpenAI 的模型名(deepseek-v4.1-flash、deepseek-v4.1-flash-mini 等)在 EXAIV 上不能直接使用,需要映射到目录里的真实 ID。选型按原模型的用途对号入座:
| 原用途 | 建议起步 ID | 说明 |
|---|---|---|
| 日常对话/轻任务 | qwen3.7-flash、glm-5.3-flash | 响应快、成本低 |
| 主力生成 | kimi-k3、gpt-6-sol | 1M 上下文,质量主力 |
| 推理/复杂任务 | glm-5.3-flash | 快速编排与工具调用 |
| 代码任务 | gpt-6-sol、glm-5.3 | 代码理解与生成 |
映射表建议放在配置里而不是散落在代码中:
MODEL_MAP = {
"deepseek-v4.1-flash-mini": "qwen3.7-flash",
"deepseek-v4.1-flash": "kimi-k3",
"o1": "glm-5.3-flash",
}
model = MODEL_MAP.get(requested_model, "kimi-k3")
ID 列表以模型目录实时数据为准,新模型上架和下架都会反映在那里。
迁移后必测五项
base_url 换掉之后,五件事要重新过一遍,每一项都可能暴露一个协议细节差异:
- 基本请求:短 prompt、小 max_tokens,确认 200 与正常文本。
- 流式输出:
stream=True的 SSE 分帧、data: [DONE]结束标记、断连行为。 - max_tokens 边界:不同模型的默认输出上限不同,长输出任务确认不会被静默截断。
- 错误处理:确认你的 except 分支能接住新端点的错误结构(401/404/429 的响应体格式)。
- 并发与限速:压测一次你真实的并发水位,确认限速阈值满足业务峰值。
测试通过的标志不是「能跑」,而是「错误路径也验证过」:故意用错 Key 确认 401 路径、故意用错模型 ID 确认错误提示、故意把 max_tokens 设为 1 确认截断行为。
推理模型的一个差异点:reasoning 字段
部分模型会把思考过程放在单独字段。当你映射到的模型支持时,思考过程在 message.reasoning_content,正文在 message.content——但不是每个模型都会填充该字段,把它当可选处理,依赖前先查模型卡:
msg = resp.choices[0].message
print(msg.content) # 正文(最终答案)
# print(msg.reasoning_content) # 思考过程,仅推理模型有
你的展示层如果只读 content,不需要任何改动;但统计 token 用量时要把 reasoning 部分也计入,它的消耗可能不小。
出问题时怎么回滚
回滚是配置变更:把 base_url 和 Key 改回原值即可,模型映射表留着不影响。为了让回滚足够快,建议:
- base_url 和 Key 走环境变量,不硬编码
- 保留原 OpenAI 配置的注释版本或备用 env 文件
- 回滚后跑一次基本请求验证
这也意味着迁移可以灰度进行:先切一个非核心接口到 EXAIV,观察一两周的错误率和延迟,再切核心链路。
常见报错速查
| 报错 | 原因 | 处理 |
|---|---|---|
| 404 | base_url 拼了完整路径,或拼错域名 | 确认是 https://exaiv.com/api/ai/v1,SDK 负责拼接后半段 |
| 401 | Key 错误、未加 Bearer 前缀、Key 失效 | 重新生成 Key,确认 header 是 Authorization: Bearer <Key> |
| model not found | model 用了 OpenAI 原名或拼错 | 从目录复制真实 ID |
| 400 | 请求体含端点不支持的字段 | 删掉可选字段,从最小请求开始加回 |
| 429 | 触发限速 | 降低并发,按 429 响应里的提示退避 |