乐于分享
好东西不私藏

AI 协议问题

AI 协议问题

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 件事:

#
翻译内容
说明
1
/v1/responses
 → /v1/chat/completions
端点路径改写
2
input
 + instructions → messages[]
请求体结构重组
3
input
 变成 role:"user"instructions 变成 role:"system"
角色映射
4
output[0].content[0].text
 ← choices[0].message.content
返回体结构重组
5
Responses SSE 事件 ↔ Chat Completions delta chunk
流式事件格式互转
6
function_call (Responses item) ↔ tool_calls (Chat msg)
工具调用格式互转

七、各大厂商真实支持的协议矩阵

厂商                 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

baseUrl 配置
CCX 实际拼接的 URL
结果
https://api.deepseek.com...deepseek.com/v1/chat/completions
✅ DeepSeek 兼容
https://ai-api-gateway.app.baizhi.cloud/api/openai...baizhi.cloud/api/openai/v1/chat/completions
❌ 404

这就是百智云配置 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.pypython3 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()

使用方法:

  1. 改 UPSTREAM 为你的厂商地址,改 LISTEN 端口(避免冲突)
  2. nohup python3 strip_v1_proxy.py > /tmp/strip_v1.log 2>&1 & 后台启动
  3. 把 CCX 的 baseUrl 改为 http://127.0.0.1:15722
  4. CCX 拼出的 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
修复 Codex 工具调用格式兼容性
工具调用报错时开
normalizeNonstandardChatRoles
把非标准 role(如 developer)转成 user/assistant
返回 "invalid role" 错误时开
reasoningParamStyle
适配不同厂商的推理参数名
使用带推理的模型时注意
stripCodexClientTools
去除 Codex 内置工具的声明
上游厂商不认某些内置工具时开
stripBillingHeader
去除计费相关 HTTP 头
上游厂商拒绝请求时尝试
insecureSkipVerify
跳过 TLS 证书验证
自签名证书或代理环境下
autoBlacklistBalance
API Key 自动故障转移
多个 Key 轮换时开
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
OpenAI 新协议,主流厂商基本都不支持
OpenAI 方言
Anthropic Messages
Claude Code 的协议
Claude 方言
协议翻译器
把 A 协议翻译成 B 协议
同声传译
base_url
请求发往哪个地址
收件地址
wire_api
用什么协议格式说话
说哪种语言
/v1/ 前缀
OpenAI 标准的版本路径
邮编格式
CCX
Codex 翻译器的名字
翻译官
CC-Switch
多工具配置管理器 + 翻译器
翻译调度中心

十三、参考资料

类别
链接
适合
协议对比
Portkey: 三协议横向对比
深入了解字段级差异
协议对比
OpenAI 官方: 为什么做 Responses
理解 Responses 设计意图
协议对比
CSDN: OpenAI 三代 API 对比
中文详解
协议演进
微信公众号: LLM API 三代演进
历史脉络
厂商文档
DeepSeek API 官方文档
查 DeepSeek 端点
厂商文档
Anthropic Messages API 文档
查 Claude 端点
工具配置
Codex + DeepSeek 教程 (GitHub)
配置实战
工具配置
CSDN: Codex 配置排障全记录
踩坑参考
工具配置
掘金: CC-Switch vs Codex++ 对比
工具选型
翻译器
CCX GitHub
CCX 源码和文档
翻译器
codex-deepseek 翻译器
备选翻译器
生态
Open Responses 开源标准
了解 Responses 开放化进展