用 DeepSeek v4 驱动 OpenAI Codex CLI:自制代理实现 gpt-5.5 → deepseek-v4-pro 透明映射
本文介绍如何通过一个轻量 Python 代理,将 Codex CLI 配置的
gpt-5.5请求无感代理到 DeepSeek API,实现用国产大模型跑 OpenAI 官方 AI 编程工具。
背景
OpenAI 在 2025 年发布了 Codex CLI,这是一个运行在终端里的 AI 编程助手,支持直接读写文件、执行命令、调用工具,体验比 ChatGPT 网页版好很多。
但问题来了------Codex CLI 默认只支持 OpenAI 自家的模型(gpt-5.5、o4-mini 等),API 费用不低。而 DeepSeek 的 deepseek-chat / deepseek-reasoner 性价比极高,能力也不弱。
能不能把 Codex 的请求转发给 DeepSeek?
可以,但有一个协议障碍:
-
Codex CLI v0.80.0+ 使用 OpenAI Responses API
-
DeepSeek 只提供 Chat Completions API
两者不兼容,不能直接替换 base_url 了事。

解决思路
写一个本地代理服务,在中间做协议翻译:
Codex CLI 代理(本机 :4000) DeepSeek API
─────────────────────────────────────────────────────────────────────
POST /v1/responses → 翻译为 Chat Completions → POST /chat/completions
model: gpt-5.5 model: deepseek-v4-pro model: deepseek-chat
Codex 以为自己在跟 gpt-5.5 说话,实际上背后是 DeepSeek。
项目地址
本项目已开源到 Gitee,参考了 deepseek-cursor-proxy 的思路并针对 Codex CLI 做了适配:
Gitee: https://gitee.com/FrancizTest_admin/codex_deepseek_proxy
技术实现细节
1. 协议翻译
Responses API 和 Chat Completions API 的消息格式差异很大:
| Responses API(Codex 发送) | Chat Completions(DeepSeek 接收) |
|---|---|
input: [{role, content}] |
messages: [{role, content}] |
content[].type = "input_text" |
content: "文本" |
content[].type = "tool_use" |
tool_calls: [...] |
content[].type = "tool_result" |
{role: "tool", content: "..."} |
type = "function_call" output item |
assistant tool_calls 消息 |
type = "function_call_output" input item |
{role: "tool"} 消息 |
SSE 流式事件也需要一一对应翻译,包括:
-
response.output_text.delta←→choices[0].delta.content -
response.function_call_arguments.delta←→tool_calls[].function.arguments -
response.function_call_arguments.done(Codex 依赖此事件判断工具调用结束) -
response.output_item.done(Codex 依赖此事件关闭流)
2. 工具调用消息合并
这是最容易踩坑的地方。
Codex 执行任务时会同时调用多个工具(比如同时读多个文件)。它会把每个 function_call 作为独立的 output item 发回来。
而 DeepSeek Chat Completions 要求:多个工具调用必须合并在同一条 assistant 消息里,后面紧跟对应数量的 role: "tool" 结果,顺序不能错,否则报 400:
An assistant message with 'tool_calls' must be followed by tool messages
responding to each 'tool_call_id'.
代理会自动把连续的 function_call 合并为一条带 tool_calls 数组的 assistant 消息。
3. reasoning_content 缓存
使用 deepseek-reasoner 时,DeepSeek 会在 thinking 模式下返回 reasoning_content(思考过程)。多轮工具调用时,每次请求都必须带上完整的 reasoning_content 链,否则 DeepSeek 会报:
The reasoning_content in the thinking mode must be passed back to the API.
Codex 不会自动携带这个字段。代理将历史 reasoning_content 存入本地 SQLite,下轮请求时自动注入,按对话哈希隔离避免串台。
4. reasoning_effort 参数过滤
Codex 配置 model_reasoning_effort = "medium" 后,请求里会带 reasoning_effort 字段。不同模型的处理规则:
| 上游模型 | reasoning_effort | temperature 等采样参数 |
|---|---|---|
deepseek-chat |
自动丢弃(不支持) | 正常透传 |
deepseek-reasoner |
映射后透传(medium→high) | 自动丢弃(互斥) |
5. gpt-5.5 别名映射
代理内置别名:gpt-5.5 → deepseek-v4-pro(对 Codex 暴露的名字),上游实际用 DEEPSEEK_MODEL 环境变量指定的模型(默认 deepseek-chat)。
这样 Codex 侧不需要做任何特殊配置,直接用 gpt-5.5 即可。

📷 [代理协议翻译流程图]
快速部署
环境要求
-
Python 3.10+
-
uv(推荐)或 pip
-
DeepSeek API Key(https://platform.deepseek.com 申请)
安装
git clone https://gitee.com/FrancizTest_admin/codex_deepseek_proxy
cd codex-deepseek-proxy
uv venv && uv sync
配置 CC Switch

启动代理
# Windows PowerShell
$env:DEEPSEEK_API_KEY = "sk-你的key"
uv run codex-deepseek-proxy --verbose
# Linux / macOS
export DEEPSEEK_API_KEY="sk-你的key"
uv run codex-deepseek-proxy --verbose
启动成功会看到:
Codex DeepSeek Proxy running at http://127.0.0.1:4000
Model advertised: deepseek-v4-pro -> DeepSeek upstream: deepseek-chat
Alias: gpt-5.5 -> deepseek-v4-pro
配置 Codex CLI
编辑 ~/.codex/config.toml:
model_provider = "custom"
model = "gpt-5.5"
model_reasoning_effort = "medium"
[model_providers.custom]
name = "custom"
wire_api = "responses"
requires_openai_auth = true
base_url = "http://127.0.0.1:4000/v1"
编辑 ~/.codex/auth.json(填 DeepSeek Key):
{ "OPENAI_API_KEY": "sk-你的DeepSeek Key" }
运行
codex


📷 [Codex 成功通过代理调用 DeepSeek 执行任务的截图]
切换 deepseek-reasoner(推理模型)
如果想用 DeepSeek 的思维链推理模型:
uv run codex-deepseek-proxy --deepseek-model deepseek-reasoner --verbose
推理模型响应更慢但质量更高,适合复杂编程任务。
常见问题
Q:纯对话正常,一开始干活(执行工具)就断?
A:通常是工具调用 SSE 事件不完整或消息结构不符合 DeepSeek 要求导致的。确认使用了最新版代理,并用 --verbose 查看具体报错。
Q:出现"insufficient tool messages following tool_calls message"报错?
A:Codex 并发调用了多个工具,旧版代理将它们拆成多条 assistant 消息,DeepSeek 拒绝了。升级到最新版代理(已修复自动合并)。
Q:reasoning_effort 导致 400 错误?
A:deepseek-chat 不支持该参数,最新版代理会自动过滤,无需手动处理。
项目结构
src/codex_deepseek_proxy/
├── config.py # 配置管理(模型别名、参数解析)
├── reasoning_store.py # reasoning_content SQLite 缓存
├── server.py # HTTP 代理服务器(SSE 翻译、工具调用)
└── translator.py # Responses API ↔ Chat Completions 翻译层
小结
| 特性 | 说明 |
|---|---|
| 模型 | deepseek-chat / deepseek-reasoner |
| 协议翻译 | Responses API ↔ Chat Completions |
| 工具调用 | 并行工具调用自动合并 |
| 推理缓存 | reasoning_content SQLite 持久化 |
| 参数过滤 | reasoning_effort 按模型自动处理 |
| 部署 | 纯 Python,无额外依赖,本机运行 |
有问题欢迎在 Gitee 提 Issue,也欢迎 Star 和 Fork。