什么是 OpenAI 兼容接口
最后更新: 2026-07-16
OpenAI 兼容接口是一个实现了 OpenAI API 请求响应契约的服务端——核心是 POST /v1/chat/completions——所以写给 OpenAI 的代码只改一个值就能对着它跑:base_url。正是这一条约定,让一份集成能打通所有厂商的模型,也是几乎每个 AI 工具都留一个 base URL 字段的原因。
先说结论:一份契约,不是一个品牌
OpenAI 的 API 成了行业事实标准,路径和 HTTP 动词变成通用约定的过程差不多:写给它的软件足够多之后,实现同一套契约就成了所有其它厂商的自然选择。一个端点是 OpenAI 兼容的,意味着它遵守这套契约:同样带 /v1 前缀的路由、同样的 JSON 请求字段、同样的响应结构、同样的流式格式、Bearer token 鉴权。 结果就是可互换性。OpenAI SDK 不知道自己在跟 OpenAI 说话;它只知道自己在往 base_url 加 /chat/completions 拼出来的地址发 JSON,带一个 Authorization 头。任何正确应答的服务端,在 SDK 眼里就是 OpenAI。这就是全部的窍门,也是为什么 DeepSeek、月之暗面、智谱这些厂商,vLLM、Ollama 这类自部署运行时,还有像 kkaiapi 这样的多厂商中转,都对外暴露同一套接口。
/v1 的具体约定
以上这些是客户端可以依赖的部分。留意契约里没说的东西:存在哪些模型、怎么定价、限速规则是什么、每个模型都支持哪些可选参数,这些都在兼容承诺之外,正是下面"兼容不等于承诺什么"这一节要讲的。
- 路由:POST /v1/chat/completions 是核心;GET /v1/models 列出可寻址的 ID;常见的搭配是 /v1/embeddings 和 /v1/images/generations。/v1 前缀是契约的一部分,漏掉它的 base URL 会以 404 收场
- 鉴权:Authorization: Bearer <key>。兼容端点接受自己的 Key,放在同一个请求头里
- 请求:model 是纯字符串,messages 是一份带 role/content 的对象数组,加上标准的可选字段(temperature、max_tokens、tools、stream、response_format 等)
- 响应:一个 id、一个 choices 数组(每项带 message 和 finish_reason)、一个带 prompt_tokens、completion_tokens、total_tokens 的 usage 对象
- 流式:stream: true 把响应切成 server-sent events,每个分块带 choices[].delta 片段,以一个 [DONE] 哨兵结束
- 工具:tools[] 里的函数定义,模型在 assistant 消息上产出 tool_calls,结果作为 role: "tool" 的消息传回去
base_url 机制:为什么改一行能挪动整个技术栈
每一个官方 OpenAI SDK,以及建在它们之上的每一个工具,都是靠拼接构造请求地址的:base_url 加路由。默认的 base URL 指向 OpenAI;覆盖它,SDK 之后发的每一次调用都会跟着走。Key 在同一个客户端构造函数里传。这就是全部的迁移面:两个值,通常是两个环境变量。 同样的机制驱动着终端用户工具里的 base URL 字段。当 Cherry Studio、LobeChat、Chatbox 或酒馆之类的工具问你要一个 OpenAI API 的 base URL 时,暴露的就是这个构造参数。填一个兼容端点,配上这个端点的 Key,工具的整个模型列表就来自这个端点的 /v1/models。 两个反复出现的机械性坑:/v1 后缀在 base URL 里要恰好出现一次,漏了路由会打不中,重复了日志里会看到 /v1/v1 的 404。还有,model 字段必须是端点真正提供的 ID,/v1/models 的列表是权威依据,ID 是精确字符串,不是模糊匹配的名字。
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["KKAIAPI_KEY"], # 值二
base_url="https://api.kkaiapi.com/v1", # 值一
)
# 同一份代码,任意目录模型:字符串决定厂商
for model in ("gpt-5.5", "claude-sonnet-4-6", "deepseek-v4-flash"):
r = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "用一个词回复:ok"}],
max_tokens=8,
)
print(model, "->", r.choices[0].message.content)兼容不等于承诺什么
兼容是一份形状上的保证,不是语义上的保证,两者之间的落差正是集成真正会出问题的地方。模型的表现是不一样的:同一个提示词在一个 Claude ID 和一个 GPT ID 上,输出风格、工具调用的积极程度、拒答的边界都不同;契约承载的是请求,不会把模型的行为拉平。参数支持也是按模型来的:新一代推理模型会拒绝或忽略老模型支持的参数,temperature 限制和 token 字段改名是有名的例子,一个兼容端点会把这些厂商规则原样传下去,而不是抹平。 覆盖范围也不一样:兼容几乎总是指 chat completions 加模型列表,OpenAI 产品的其它部分——Assistants、微调、Realtime,以及更新的 Responses API——要么按端点各自实现,要么完全没有。延迟、限速、可用性、日志策略这些运营属性,完全是端点运营方自己的事,和契约无关。 实际的应对方式是:把"兼容"当成尽调的起点,不是终点。契约保证你的代码能说得通;端点的文档和一次冒烟测试才能告诉你这场对话顺不顺利。
| 兼容承诺什么 | 不承诺什么 |
|---|---|
| 你的 OpenAI-SDK 代码原样能跑 | 每个模型都表现得像 OpenAI 模型 |
| 请求响应形状一致 | 每个可选参数在每个模型上都有效 |
| 流式和工具调用格式能解析 | Assistants、Realtime 或 Responses 的完整覆盖 |
| /v1/models 告诉你能寻址什么 | 任何具体的延迟、限速或可用性 |
| 一行迁移进出 | 迁移之后输出完全一致 |
三个请求验证一个端点
把任何真实业务接到一个兼容端点之前,先跑这个三步冒烟测试。列出模型:证明鉴权通过,也能看到精确的 ID。用打算用的那个 ID 跑一次完整的聊天补全:端到端证明核心契约没问题。跑一次流式:证明 SSE 这条路径没问题,这是薄弱实现最先晃动的地方。如果自己的场景用工具调用或 JSON 模式,加第四个请求,在具体模型上验证那个功能,因为功能支持是按模型的,不是按端点的。 一分钟的 curl 能省下几层工具之上一个下午的排查,因为这里的失败是无歧义的:端点、Key、或者 ID,应用代码还没登场就先定位到了问题。
# 1) 鉴权 + 目录
curl -s https://api.kkaiapi.com/v1/models \
-H "Authorization: Bearer $KKAIAPI_KEY" | head -40
# 2) 用打算跑的具体 ID 跑一轮
curl -s https://api.kkaiapi.com/v1/chat/completions \
-H "Authorization: Bearer $KKAIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-4-6",
"messages":[{"role":"user","content":"回复:准备好了"}],
"max_tokens":8}'
# 3) 流式路径
curl -sN https://api.kkaiapi.com/v1/chat/completions \
-H "Authorization: Bearer $KKAIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-4-6","stream":true,
"messages":[{"role":"user","content":"从一数到三。"}]}'枢纽页:从这里往下看
这一页是一整簇内容的定义性起点。如果是从某个具体工具的 base URL 字段找过来的,下面的按工具教程走完了上面这套机制在 LlamaIndex、AutoGen、n8n、Langflow、Activepieces、Goose、Perplexica、Khoj、STORM 这些工具里的具体填法。如果想知道这类端点该放在架构里的什么位置,Chat Completions 和 Messages API 区别那篇是配套的协议对比。 如果只是想要一个能直接用的端点:kkaiapi 提供这套兼容接口,/v1/chat/completions、/v1/models、/v1/images/generations,加上 Anthropic 的 /v1/messages 方言,覆盖多厂商目录,一个 Key。上面的冒烟测试对着它原样能跑。
- LlamaIndex OpenAILike 接入配置
- AutoGen 自定义 base_url 接入配置
- n8n 接 OpenAI 兼容 API 配置
- Langflow 自定义模型接入配置
- Activepieces 自定义 AI 供应商配置
- Goose 桌面 Agent 自定义供应商配置
- Perplexica 自建搜索接入配置
- Khoj 第二大脑接入配置
- STORM 研究报告生成配置
常见问题
OpenAI 兼容接口具体是什么意思?
一个实现了 OpenAI API 契约的服务端:/v1 路由、请求响应 JSON 形状、Bearer 鉴权、SSE 流式,所以写给 OpenAI 的软件只改 base URL 和 Key 就能对着它跑。这是一份线上格式标准,不是 OpenAI 的产品。
怎么让 OpenAI SDK 指向别的端点?
给客户端构造函数传 base_url 和 api_key(或者设对应的环境变量)。SDK 用 base_url 加路由拼出每一次请求,所有调用都会跟着走。base URL 里的 /v1 要恰好出现一次。
OpenAI 兼容端点能提供 Claude 或 Gemini 模型吗?
能,这正是多厂商网关的意义所在:model 字段是纯字符串,一个端点能把 claude-sonnet-4-6 路由给 Anthropic,把 gpt-5.5 路由给 OpenAI,都在同一份契约背后。/v1/models 的列表能准确显示一个端点提供哪些 ID。
兼容端点上 OpenAI 的每个功能都能用吗?
不能。兼容可靠地意味着 chat completions 加模型列表,常见的还有 embeddings 和 images。Assistants、微调、Realtime,以及更新的 Responses API,要么按端点各自实现,要么完全没有,可选参数依然是按模型的。查具体端点的文档确认它的真实覆盖范围。
设了自定义 base URL 之后工具报错,可能是什么原因?
反复出现的三件套:URL 里 /v1 缺失或重复(404,或日志里的 /v1/v1 路径)、模型 ID 和端点目录对不上、Key 粘贴时带了空白字符。上面的三请求 curl 冒烟测试能在一分钟内把这三者都定位出来。
OpenAI 兼容和聚合中转是一回事吗?
不是,这是两个正交的概念。兼容描述的是接口;中转描述的是谁在做路由、持有哪家厂商的账号。厂商自己、自建的路由器、托管的多厂商网关都可以对外暴露同一套兼容接口,这也是让你在几者之间的选择保持可逆的原因。