从 OpenAI 官方 SDK 迁移到中转:5 分钟搞定,附完整代码示例
国内开发者怎么把已有的 OpenAI Python / Node.js / Go 代码无缝切到 渡 AI 中转?改 base_url 一行的事,但有几个坑要避开。
一句话:改一行 base_url + 换一个 API Key,其余代码完全不动。但流式、Function Calling、Vision 这三类调用要看清楚。
很多团队迁移卡在”是不是要重写”。答案是不需要。OpenAI 与 Anthropic 官方 SDK 都把 base_url 设成了可配置参数,我们的中转 100% 协议兼容。
Python
# 改之前
from openai import OpenAI
client = OpenAI(api_key="sk-proj-xxxxxxxx")
# 改之后
from openai import OpenAI
client = OpenAI(
api_key="sk-xxxxxxxx", # 你的 渡 AI Key
base_url="https://api.tathr.com/v1", # 我们的端点
)
# 其余代码完全不变
resp = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "你好"}],
)
推荐做法:把 api_key 和 base_url 都从环境变量读:
import os
client = OpenAI(
api_key=os.environ["LLM_API_KEY"],
base_url=os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1"),
)
这样测试环境用我们的中转、CI 里跑官方、生产再切回中转,都不用改代码。
Node.js / TypeScript
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.LLM_API_KEY,
baseURL: 'https://api.tathr.com/v1', // 注意 baseURL(驼峰)
});
const completion = await client.chat.completions.create({
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: '写一首诗' }],
});
Go
import "github.com/sashabaranov/go-openai"
config := openai.DefaultConfig("sk-xxxxxxxx")
config.BaseURL = "https://api.tathr.com/v1"
client := openai.NewClientWithConfig(config)
LangChain / LlamaIndex
# LangChain
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5",
openai_api_key="sk-xxxxxxxx",
openai_api_base="https://api.tathr.com/v1",
)
# LlamaIndex
from llama_index.llms.openai import OpenAI as LIOpenAI
llm = LIOpenAI(
model="claude-opus-4-7",
api_key="sk-xxxxxxxx",
api_base="https://api.tathr.com/v1",
)
Anthropic Python SDK(如果你想用原生协议)
我们也支持 Anthropic 原生协议,base_url 不同:
from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxx", # 同一个 渡 AI Key
base_url="https://api.tathr.com/anthropic",
)
resp = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=[{"role": "user", "content": "你好"}],
)
何时用 OpenAI 兼容协议、何时用 Anthropic 原生?
- 90% 场景用 OpenAI 兼容 —— 一套代码两家模型通吃。
- 需要 Claude 独有特性时用原生:
cache_control显式标记、thinking模式、tool_choice: any。
三个常见迁移坑
坑 1:流式 SSE 的 data: 前缀
OpenAI 流式响应每行是 data: {...},结束以 data: [DONE]。我们完全一致,但如果你用了自己手写的 fetch + ReadableStream(没用 SDK),注意:
- 行尾可能是
\n也可能是\r\n,要兼容。 [DONE]不是 JSON,别JSON.parse它。- 中间可能有空行(heartbeat),跳过即可。
直接用官方 SDK 的 stream=True 就不用管这些。
坑 2:Function Calling 的 schema
OpenAI 的 tools 数组和 Anthropic 的 tools 数组结构不一样:
// OpenAI 风格(兼容协议下统一用这个)
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"parameters": { "type": "object", "properties": {...} }
}
}]
}
// Anthropic 原生
{
"tools": [{
"name": "get_weather",
"input_schema": { "type": "object", "properties": {...} }
}]
}
走 OpenAI 兼容协议时,所有模型(包括 Claude)都用 OpenAI 风格。我们内部会翻译。
坑 3:模型名要严格一致
不要写 gpt5、GPT-5、gpt-5.0,必须严格 gpt-5。错误会返回:
{ "error": { "code": "model_not_found", "message": "The model `gpt5` does not exist" } }
完整模型名列表见 模型矩阵。
测试迁移是否成功
最简单方式:把你现有的一个 e2e 测试跑两次,一次用官方端点、一次用我们的端点,对比结果。
import os
from openai import OpenAI
def test_chat(base_url, api_key):
client = OpenAI(api_key=api_key, base_url=base_url)
resp = client.chat.completions.create(
model="gpt-5-mini",
messages=[{"role": "user", "content": "1+1=?"}],
max_tokens=10,
)
return resp.choices[0].message.content
print(test_chat("https://api.openai.com/v1", os.environ["OPENAI_KEY"]))
print(test_chat("https://api.tathr.com/v1", os.environ["DUAI_KEY"]))
两个都应该返回 2。如果中转返回错误,把 Key、模型名、base_url 三个都重新核对一遍。