AI 协议问题
这是一篇 AI 写的爽文.
一、先说人话:什么是"协议"
协议 = 说好的格式。
就像寄快递要按格式写地址、收件人、电话号码一样。AI API 协议就是你和 AI 厂商之间约定的"请求格式"和"返回格式":
你: "喂,帮我写段代码" ← 想说的话
↓
协议: {"model":"xxx", "messages":[{"role":"user","content":"帮我写段代码"}]} ← 必须这么说
↓
厂商: 收到,理解,返回结果 ← 按约定的返回格式给你
换协议 = 换了一套字段名、请求路径、返回结构。格式不对,对方直接不理你(404/400)。
二、AI API 协议的"三国演义"(时间线)
2020 ────────────────────────────────────────────────────── 2026
│
│ 【第一代】Completions API — 已淘汰
│
├── 2020.06 GPT-3 API 发布
│ POST /v1/completions
│ 请求: {"prompt": "今天天气"}
│ 返回: {"choices": [{"text": "不错"}]}
│ 问题: 太简陋,不能区分"你是助手"和"用户的问题"
│
│ ★ 2022.11 ChatGPT 爆火(但 API 还是老格式)
│
│ 【第二代】两个协议同年诞生,从此分道扬镳
│
├── 2023.03 ★ Chat Completions API 发布 — OpenAI 第二代
│ POST /v1/chat/completions
│ 引入 system/user/assistant 三种角色,对话结构化了
│ 请求: {"messages": [{"role": "user", "content": "今天天气"}]}
│ 返回: {"choices": [{"message": {"content": "不错"}}]}
│
├── 2023.06 Function Calling 加入 Chat Completions(工具调用时代开启)
│
├── 2024.03 ★ Anthropic Messages API 正式成为 Claude 主力协议
│ POST /v1/messages(Anthropic 的第二代,替代了老式 Text Completions)
│ 另一套体系,理念不同但定位类似
│ 请求: {"messages": [{"role": "user", "content": "今天天气"}], "max_tokens": 1024}
│ 返回: {"content": [{"type": "text", "text": "不错"}]}
│
│ ★ 2024-2025 Chat Completions 成为全行业标准
│ DeepSeek、千问、豆包、Gemini、Kimi……全部厂商跟进
│
│ 【第三代】OpenAI 独家新协议
│
└── 2025.03 ★ Responses API 发布 — OpenAI 第三代
POST /v1/responses
"智能体专用",内置工具 + 服务端状态管理 + MCP
请求: {"input": "今天天气", "model": "gpt-5"}
返回: {"output": [{"type": "message", "content": [{"text": "不错"}]}]}
现状: 只有 OpenAI 自己完整支持。阿里百炼是罕见的例外。DeepSeek/Gemini/豆包等主流厂商均未跟进
三、三种协议到底长什么样 —— 真实请求/返回对照
这是最重要的章节。看一遍 JSON,比看十遍概念都管用。
3.1 Chat Completions(行业标准)
# 端点
POST https://api.deepseek.com/chat/completions
# (也可能是 /v1/chat/completions,不同厂商路径不同,见第七章)
# 请求
{
"model": "deepseek-v4-flash",
"messages": [
{"role": "system", "content": "你是一个编程助手"},
{"role": "user", "content": "用 Python 写一个 hello world"}
],
"temperature": 0.7,
"max_tokens": 1000,
"stream": true
}
# 返回(非流式)
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"model": "deepseek-v4-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "print(\"Hello, World!\")"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 10,
"total_tokens": 30
}
}
# 返回(流式 SSE)
data: {"choices":[{"delta":{"content":"print"},"index":0}]}
data: {"choices":[{"delta":{"content":"(\"Hello"},"index":0}]}
data: {"choices":[{"delta":{"content":", World!\")"},"index":0}]}
data: {"choices":[{"delta":{},"finish_reason":"stop","index":0}]}
data: [DONE]
3.2 Anthropic Messages(Claude 专用)
# 端点
POST https://api.anthropic.com/v1/messages
# 请求(注意:必须有 max_tokens!)
{
"model": "claude-sonnet-4-6",
"system": "你是一个编程助手", ← system 是顶层字段,不在 messages 里
"messages": [
{"role": "user", "content": "用 Python 写一个 hello world"}
],
"max_tokens": 1000, ← 必填!不填直接报错
"stream": true
}
# 返回(非流式)
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-6",
"content": [
{
"type": "text",
"text": "print(\"Hello, World!\")"
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 15,
"output_tokens": 8
}
}
# 返回(流式 SSE)— 有命名事件类型
event: message_start
data: {"type":"message_start","message":{"id":"msg_xxx",...}}
event: content_block_start
data: {"type":"content_block_start","content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"print"}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"(\"Hello, World!\")"}}
event: content_block_stop
data: {"type":"content_block_stop"}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":8}}
event: message_stop
data: {"type":"message_stop"}
3.3 Responses(OpenAI 独家,Codex 专用)
# 端点
POST https://api.openai.com/v1/responses
# 请求
{
"model": "gpt-5",
"instructions": "你是一个编程助手", ← 不叫 system,叫 instructions
"input": "用 Python 写一个 hello world", ← 不叫 messages,叫 input
"max_output_tokens": 1000,
"stream": true
}
# 返回(非流式)
{
"id": "resp_xxx",
"object": "response",
"status": "completed",
"model": "gpt-5",
"output": [ ← 不叫 choices,叫 output
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text", ← 不叫 content,叫 output_text
"text": "print(\"Hello, World!\")"
}
]
}
],
"usage": {
"input_tokens": 15,
"output_tokens": 8,
"total_tokens": 23
}
}
# 返回(流式 SSE)— OpenAI 第三代的命名事件
event: response.output_text.delta
data: {"delta":"print"}
event: response.output_text.delta
data: {"delta":"(\"Hello, World!\")"}
event: response.output_text.done
data: {"text":"print(\"Hello, World!\")"}
3.4 并排对比 —— 同一个对话,三种写法
假设要给 AI 发出这条消息:「你是编程助手。帮我写个 hello world。」
三份请求放在一起:
┌── Chat Completions ──────────────────────────────────────────────┐
│ POST /v1/chat/completions │
│ { │
│ "model": "...", │
│ "messages": [ │
│ {"role": "system", "content": "你是编程助手"}, ← 系统提示 │
│ {"role": "user", "content": "帮我写个 hello world"} ← 用户 │
│ ] │
│ } │
│ │
│ 回复路径: choices[0].message.content │
│ 流式事件: data: {"choices":[{"delta":{"content":"..."}}]} │
│ 结束标志: finish_reason: "stop" │
└───────────────────────────────────────────────────────────────────┘
┌── Anthropic Messages ───────────────────────────────────────────────┐
│ POST /v1/messages │
│ { │
│ "model": "...", │
│ "system": "你是编程助手", ← 系统提示在顶层 │
│ "messages": [ │
│ {"role": "user", "content": "帮我写个 hello world"} ← 用户 │
│ ], │
│ "max_tokens": 1000 ← 必填! │
│ } │
│ │
│ 回复路径: content[0].text │
│ 流式事件: event: content_block_delta + data: {"delta":{"text":...}}│
│ 结束标志: stop_reason: "end_turn" │
└─────────────────────────────────────────────────────────────────────┘
┌── Responses ────────────────────────────────────────────────────────┐
│ POST /v1/responses │
│ { │
│ "model": "...", │
│ "instructions": "你是编程助手", ← 不叫 system │
│ "input": "帮我写个 hello world" ← 不叫 messages │
│ } │
│ │
│ 回复路径: output[0].content[0].text │
│ 流式事件: event: response.output_text.delta + data: {"delta":"..."}│
│ 结束标志: status: "completed" │
└─────────────────────────────────────────────────────────────────────┘
翻译器做的最核心的事,一句话说就是:
instructions ──→ messages[0] {"role":"system", ...}
input ──→ messages[1] {"role":"user", ...}
output[0].content[0].text ←── choices[0].message.content
status: "completed" ←── finish_reason: "stop"
response.output_text.delta ←── choices[0].delta.content
四、三大协议核心差异速查表
┌────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ │ Chat Completions │ Anthropic Messages │ Responses │
│ │ (行业标准 ★) │ (Claude 专属) │ (OpenAI 独家) │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 端点 │ /chat/completions │ /v1/messages │ /v1/responses │
│ │ 或 /v1/chat/ │ 或 /anthropic/ │ │
│ │ completions │ messages │ │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 诞生年 │ 2023.03 │ 2024.03 (主力协议) │ 2025.03 │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 设计理念 │ 无状态,每次重新描述 │ 无状态,每次重新描述 │ 有状态,服务端记历史 │
│ │ 完整对话 │ 完整对话 │ │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 用户输入放哪 │ messages[] │ messages[] │ input │
│ │ role: "user" │ role: "user" │ (字符串或数组) │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 系统提示放哪 │ messages[] │ 顶层 system 字段 │ 顶层 instructions │
│ │ role: "system" │ │ │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 回复文本从这里取 │ choices[0].message │ content[0].text │ output[0].content │
│ │ .content │ │ [0].text │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 结束标志 │ finish_reason: │ stop_reason: │ status: "completed" │
│ │ "stop" / "length" │ "end_turn" │ │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 工具调用 │ tool_calls 嵌套在 │ tool_use 独立 │ function_call 是 │
│ │ message 里面 │ content block │ output[] 的独立项 │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 流式事件格式 │ 简单 delta: │ 命名事件类型: │ 命名事件类型: │
│ │ data: {"choices": │ event: content_ │ event: response. │
│ │ [{"delta":{...}}]} │ block_delta │ output_text.delta │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Token 用量字段 │ usage.prompt_tokens │ usage.input_tokens │ usage.input_tokens │
│ │ usage.completion_ │ usage.output_tokens │ usage.output_tokens │
│ │ tokens │ │ │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 必填特殊参数 │ messages (最少一条) │ max_tokens (必填!) │ model │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 服务端内置工具 │ ❌ 无 │ ❌ 无 │ ✅ web_search/ │
│ │ │ │ code_interpreter │
│ │ │ │ file_search/MCP │
├────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 谁支持 │ ★ 全行业所有厂商 │ Anthropic 官方 │ OpenAI 官方 │
│ │ │ DeepSeek V4 (兼容) │ 阿里百炼 (唯一) │
│ │ │ 百智云 (兼容) │ Open Responses(开源) │
│ │ │ llama.cpp (社区) │ │
└────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘
五、工具 ↔ 协议 ↔ 厂商 的完整链路
5.1 谁说什么语言
┌──────────────────────┬───────────────────────────────────────────┬──────────────────────────┐
│ 工具 │ 要求的协议 │ 协议端点路径 │
├──────────────────────┼───────────────────────────────────────────┼──────────────────────────┤
│ Claude Code │ Anthropic Messages │ /v1/messages │
│ Claude Desktop │ Anthropic Messages │ /v1/messages │
│ Codex CLI │ Responses │ /v1/responses │
│ Codex Desktop │ Responses │ /v1/responses │
│ ChatGPT 网页 │ Chat Completions │ /v1/chat/completions │
│ Gemini CLI │ Gemini (generateContent) │ /v1beta/models/... │
│ Cursor / Cline │ Chat Completions │ /v1/chat/completions │
│ OpenCode / OpenClaw │ Chat Completions 或 Anthropic Messages │ 取决于配置 │
│ 大多数开源前端 │ Chat Completions │ /v1/chat/completions │
└──────────────────────┴───────────────────────────────────────────┴──────────────────────────┘
5.2 你能不能直连 —— 协议匹配表
工具 ──────────────▶ 厂商 直接能用? 为什么
──── ──── ──────── ────
Claude Code ──────▶ Anthropic ✅ 直连 原生协议,完全匹配
Claude Code ──────▶ DeepSeek V4 ✅ 直连 DeepSeek V4 兼容 Anthropic Messages
Claude Code ──────▶ 百智云 ✅ 直连 百智云有 /api/anthropic 端点
Claude Code ──────▶ OpenAI ❌ 需翻译 OpenAI 不说 Anthropic 协议
ChatGPT/Cursor ───▶ 任何厂商 ✅ 直连 几乎所有厂商都支持 Chat Completions
Codex ────────────▶ OpenAI ✅ 直连 原生协议,完全匹配
Codex ────────────▶ DeepSeek ❌ 需翻译 DeepSeek 不兼容 Responses
Codex ────────────▶ 百智云 ❌ 需翻译 百智云不兼容 Responses
Codex ────────────▶ 任何非OpenAI ❌ 需翻译 目前只有 OpenAI 支持 Responses
核心矛盾一目了然:
Claude Code → 除了 OpenAI,大多数厂商都能直连 ChatGPT/Cursor → 所有厂商都能直连 Codex → 只有 OpenAI 能直连(因为 Responses 太新,没人跟进)
六、协议不匹配怎么办 —— 翻译层原理
6.1 直连为什么失败
Codex ──POST /v1/responses──▶ DeepSeek
{"input": "hello"} │
│ DeepSeek: "我只会 Chat Completions,
│ 你发的这个 /v1/responses 我不认识"
│
└──▶ 404 Not Found ❌
6.2 加翻译层
┌──────┐ Responses ┌──────────────┐ Chat Completions ┌──────────┐
│ │ ──────────────────▶│ │ ────────────────────────▶│ │
│ Codex│ │ CCX / │ │ DeepSeek │
│ │ │ CC-Switch │ │ │
│ │ ◀──────────────────│ (翻译器) │ ◀────────────────────────│ │
└──────┘ Responses └──────────────┘ Chat Completions └──────────┘
6.3 翻译器到底做了什么(真实 JSON 对照)
进来的请求(Codex → 翻译器):
POST /v1/responses
{
"model": "feature/deepseek",
"input": "用 Python 写 hello world",
"instructions": "你是编程助手",
"tools": [{"type": "function", "name": "read_file", "parameters": {...}}]
}
翻译后发出(翻译器 → DeepSeek):
POST /v1/chat/completions
{
"model": "feature/deepseek",
"messages": [
{"role": "system", "content": "你是编程助手"},
{"role": "user", "content": "用 Python 写 hello world"}
],
"tools": [{"type": "function", "function": {"name": "read_file", "parameters": {...}}}]
}
DeepSeek 返回(Chat Completions 格式):
{
"choices": [{
"message": {"role": "assistant", "content": "print(\"Hello, World!\")"},
"finish_reason": "stop"
}]
}
翻译后返回给 Codex(Responses 格式):
{
"output": [{
"type": "message",
"role": "assistant",
"content": [{"type": "output_text", "text": "print(\"Hello, World!\")"}]
}],
"status": "completed"
}
翻译器做的 6 件事:
/v1/responses/v1/chat/completions | ||
inputinstructions → messages[] | ||
inputrole:"user",instructions 变成 role:"system" | ||
output[0].content[0].textchoices[0].message.content | ||
七、各大厂商真实支持的协议矩阵
厂商 Chat Completions Anthropic Messages Responses
──── ──────────────── ───────────────── ─────────
OpenAI ✅ 原生 ❌ ✅ 原生
端点: /v1/chat/completions 端点: /v1/responses
Anthropic ❌ 不支持 OpenAI 格式 ✅ 原生 ❌
端点: /v1/messages
DeepSeek ✅ 原生 ✅ V4 新增 ❌
端点: /chat/completions 端点: /anthropic/messages
(也支持 /v1/chat/completions)
Google Gemini ✅ 兼容模式 ❌ ❌
端点: /v1beta/models/...
或 /v1/chat/completions
阿里通义千问 ✅ 原生 ❌ ✅ (百炼平台唯一)
端点: /v1/chat/completions 端点: /v1/responses
字节豆包 ✅ 原生 ❌ ❌
百度千帆 ✅ 原生 ❌ ❌
腾讯混元 ✅ 原生 ❌ ❌
月之暗面 Kimi ✅ 原生 ❌ ❌
智谱 GLM ✅ 原生 ❌ ❌
xAI Grok ✅ 原生 ❌ ❌
百智云 (API 网关) ✅ 原生 ✅ 原生 ❌
端点: /api/openai/ 端点: /api/anthropic/
chat/completions messages
结论:Chat Completions 是全行业通用语。Anthropic Messages 排第二(DeepSeek V4 刚加入)。Responses 只有 OpenAI + 阿里百炼。
八、URL 路径的隐藏陷阱 —— 同一个协议,不同厂商路径不同
这是配置失败最常见的坑。 协议是一样的(Chat Completions),但 URL 路径不一样。
8.1 URL 的结构解剖
https://api.openai.com/v1/chat/completions
└────┬────┘ └──┬──┘ └──────┬──────┘
域名 版本前缀 操作路径
(通常是 /v1)
不同厂商对"版本前缀"的处理不同:
8.2 各厂商实际 URL
标准 OpenAI:
https://api.openai.com/v1/chat/completions ← 标准带 /v1
DeepSeek(宽松,两种都行):
https://api.deepseek.com/chat/completions ← 不带 /v1 ✅
https://api.deepseek.com/v1/chat/completions ← 带 /v1 ✅
Anthropic(严格带 /v1):
https://api.anthropic.com/v1/messages ← 必须带 /v1
百智云(严格自定义前缀):
https://ai-api-gateway.app.baizhi.cloud/api/openai/chat/completions ← ✅ 正确
https://ai-api-gateway.app.baizhi.cloud/api/openai/v1/chat/completions ← ❌ 404
https://ai-api-gateway.app.baizhi.cloud/v1/chat/completions ← ❌ 405
阿里 DashScope(自定义前缀):
https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions ← 非标准 /v1 位置
Google Gemini(完全不按这个套路):
https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent
8.3 为什么会踩坑
翻译器(CCX)按标准 OpenAI 格式拼接 URL:{baseUrl}/v1/chat/completions。
https://api.deepseek.com | ...deepseek.com/v1/chat/completions | |
https://ai-api-gateway.app.baizhi.cloud/api/openai | ...baizhi.cloud/api/openai/v1/chat/completions |
这就是百智云配置 Codex 时遇到的真实问题。CCX 多拼了一个 /v1,网关不认。解决方案见 8.5 节。
8.4 怎么自己验证
# 终极测试:直接 curl 打厂商,看哪个路径通
curl -s -o /dev/null -w "不带/v1: %{http_code}\n" \
https://你的厂商/chat/completions \
-H "Authorization: Bearer 你的key" \
-H "Content-Type: application/json" \
-d '{"model":"你的模型","messages":[{"role":"user","content":"hi"}]}'
curl -s -o /dev/null -w "带/v1: %{http_code}\n" \
https://你的厂商/v1/chat/completions \
-H "Authorization: Bearer 你的key" \
-H "Content-Type: application/json" \
-d '{"model":"你的模型","messages":[{"role":"user","content":"hi"}]}'
# 哪个返回 200,就用哪个路径配置翻译器
8.5 实战:百智云 URL 兼容 —— 极简路径改写代理
如果厂商不支持带 /v1 的路径,CCX 又没法改拼接逻辑,最简单的方法是在本地起一个路径改写代理。
原理:
CCX ──▶ http://127.0.0.1:15722/v1/chat/completions
│
▼
┌─────────────────────┐
│ 路径改写代理 (:15722) │
│ │
│ 去掉请求路径中的 /v1 │
│ /v1/chat/completions│
│ ↓ │
│ /chat/completions │
└─────────┬───────────┘
│
▼
百智云 /api/openai/chat/completions ✅
完整脚本: 保存为 strip_v1_proxy.py,python3 strip_v1_proxy.py 即可运行。
"""极简路径改写代理: 去掉请求路径中的 /v1 前缀,其余原样转发"""
import http.server
import urllib.request
import urllib.error
import ssl
import sys
UPSTREAM = "https://ai-api-gateway.app.baizhi.cloud/api/openai"# ← 改成你的上游地址
LISTEN = ("127.0.0.1", 15722) # ← 改端口号
classProxy(http.server.BaseHTTPRequestHandler):
defdo_one(self, method):
# 去掉路径中的 /v1: /v1/chat/completions → /chat/completions
path = self.path.replace("/v1/", "/", 1)
url = UPSTREAM + path
body = None
if method in ("POST", "PUT", "PATCH"):
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length) if length elseNone
req = urllib.request.Request(url, data=body, method=method)
for k, v in self.headers.items():
if k.lower() in ("host", "content-length"):
continue
req.add_header(k, v)
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
try:
resp = urllib.request.urlopen(req, context=ctx, timeout=120)
self.send_response(resp.status)
for k, v in resp.headers.items():
if k.lower() notin ("transfer-encoding", "content-length"):
self.send_header(k, v)
self.end_headers()
self.wfile.write(resp.read())
except urllib.error.HTTPError as e:
body = e.read()
self.send_response(e.code)
for k, v in e.headers.items():
if k.lower() notin ("transfer-encoding", "content-length"):
self.send_header(k, v)
self.end_headers()
self.wfile.write(body)
except Exception as e:
self.send_response(502)
self.end_headers()
self.wfile.write(str(e).encode())
do_GET = lambda s: s.do_one("GET")
do_POST = lambda s: s.do_one("POST")
do_PUT = lambda s: s.do_one("PUT")
do_DELETE = lambda s: s.do_one("DELETE")
do_PATCH = lambda s: s.do_one("PATCH")
do_OPTIONS = lambda s: s.do_one("OPTIONS")
deflog_message(self, fmt, *args):
sys.stderr.write("[strip_v1] %s\n" % (fmt % args))
if __name__ == "__main__":
srv = http.server.HTTPServer(LISTEN, Proxy)
print(f"路径改写代理已启动: http://{LISTEN[0]}:{LISTEN[1]} → {UPSTREAM}")
srv.serve_forever()
使用方法:
改 UPSTREAM为你的厂商地址,改LISTEN端口(避免冲突)nohup python3 strip_v1_proxy.py > /tmp/strip_v1.log 2>&1 &后台启动把 CCX 的 baseUrl改为http://127.0.0.1:15722CCX 拼出的 http://127.0.0.1:15722/v1/chat/completions经代理改写后变成https://你的厂商/chat/completions
这个方法不仅适用于百智云,任何厂商如果路径不规范,都可以用这个代理做一层改写。
九、怎么看厂商文档判断支持什么协议
拿到一个新厂商的 API 文档,按这三步走:
第 1 步:找端点路径
在文档里搜索这些关键词:
chat/completions或chat→ Chat Completions 协议/messages→ Anthropic Messages 协议/responses→ Responses 协议generateContent→ Gemini 协议
第 2 步:看快速开始代码
文档里的示例代码直接暴露协议:
# 看到这个 → Chat Completions 协议
from openai import OpenAI
client = OpenAI(base_url="...")
client.chat.completions.create(...)
# 看到这个 → Anthropic Messages 协议
from anthropic import Anthropic
client = Anthropic(base_url="...")
client.messages.create(...)
# 看到这个 → Responses 协议
client.responses.create(...)
第 3 步:看 base_url 推荐值
文档里通常会直接写出 base_url:
# DeepSeek 官方推荐:
base_url = "https://api.deepseek.com"
# → 说明端点就是 https://api.deepseek.com/chat/completions
# 百智云:
base_url = "https://ai-api-gateway.app.baizhi.cloud/api/openai"
# → 说明端点就是 .../api/openai/chat/completions(注意没有 /v1)
这三步走完,你就能确定:
✅ 厂商支持什么协议 ✅ 实际端点 URL 是什么 ✅ base_url 应该怎么填
十、CCX / CC-Switch 技术详解
10.1 架构图
┌─────────────────────────────────────────────────────┐
│ 你的电脑 │
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ Codex │──Responses──▶│ │ │
│ │ │ │ CCX (:3000) │ │
│ │ │◀──Responses──│ 或 CC-Switch│ │
│ └──────────┘ │ (:15721) │ │
│ │ │ │
│ │ 翻译器: │ │
│ │ 1.协议互转 │ │
│ │ 2.URL 拼接 │ │
│ │ 3.Key 管理 │ │
│ │ 4.流式适配 │ │
│ │ 5.多路热备 │ │
│ └──────┬───────┘ │
│ │ │
└─────────────────────────────┼────────────────────────┘
│ Chat Completions
▼
┌──────────────────┐
│ DeepSeek / 百智云 │
│ / 其他厂商 │
└──────────────────┘
10.2 CCX 配置速查
{
"responsesUpstream": [ // ← Codex 走这个
{
"baseUrl": "https://api.deepseek.com", // 上游地址
"apiKeys": ["sk-xxx"], // 上游 API Key
"serviceType": "openai", // 协议类型
"name": "我的渠道", // 显示名
"priority": 1, // 优先级(越小越优先)
"status": "active", // active / suspended / disabled
"codexToolCompat": true, // 工具调用兼容修复
"normalizeNonstandardChatRoles": true, // 非标 role 修复
"supportedModels": ["feature/*"] // 模型白名单
}
]
}
10.3 CCX 配置项详解
codexToolCompat | ||
normalizeNonstandardChatRoles | developer)转成 user/assistant | |
reasoningParamStyle | ||
stripCodexClientTools | ||
stripBillingHeader | ||
insecureSkipVerify | ||
autoBlacklistBalance | ||
fuzzyModeEnabled |
十一、完整排障流程(建议收藏)
Codex 发请求 → 报错了
│
├── "connection refused" / "error sending request"
│ 翻译器没启动!
│ → lsof -i :3000 或 :15721,确认 CCX/CC-Switch 在跑
│
├── 404 Not Found
│ 路径不对!
│ → curl 直接打上游验证(见第八章)
│ → 带 /v1 和不带 /v1 都试一遍
│ → 都 404?看厂商文档,确认正确的路径
│
├── 401 Unauthorized
│ Key 错了或没传过去!
│ → 检查 CCX 里的 apiKeys 是否填写正确
│ → 检查 Codex auth.json 里是否有 OPENAI_API_KEY(Codex 硬编码要求)
│ → 注意:CCX 入口 Key(your-proxy-access-key)≠ 上游 Key(sk-xxx)
│ → curl 直接打上游验证 Key 是否有效
│
├── 400 Bad Request
│ 请求格式不对!
│ → 可能是模型名不匹配
│ → 可能是必填参数缺失(Anthropic 必须带 max_tokens)
│ → 可能是厂商要求特定字段格式
│
├── "All upstream channels are currently unavailable"
│ 翻译器连不上上游!
│ → 检查 CCX 的 upstream 状态(是不是 suspended)
│ → 检查上游 URL 是否可达
│ → 检查 CCX 日志(circuit breaker 可能熔断了)
│ → 查看 promotionUntil 是否过期
│
└── 能对话但工具调用失败
协议翻译不完整!
→ 确认 codexToolCompat: true
→ 确认 reasoningParamStyle 配置正确
→ 查看 CCX 日志定位具体哪一步翻译出错
十二、核心概念速查表
| Chat Completions | ||
| Responses API | ||
| Anthropic Messages | ||
| 协议翻译器 | ||
| base_url | ||
| wire_api | ||
| /v1/ 前缀 | ||
| CCX | ||
| CC-Switch |
十三、参考资料
| 协议对比 | ||
| 协议对比 | ||
| 协议对比 | ||
| 协议演进 | ||
| 厂商文档 | ||
| 厂商文档 | ||
| 工具配置 | ||
| 工具配置 | ||
| 工具配置 | ||
| 翻译器 | ||
| 翻译器 | ||
| 生态 |
夜雨聆风