让 Codex CLI 跑上 DeepSeek:用 LiteLLM 做 Responses↔Chat 协议翻译 结论先行Codex CLI实测 v0.143.0只认 OpenAI 的Responses API而 DeepSeek 只提供Chat Completions。两者协议对不上直接配必然 404。中间架一层 LiteLLM 代理做协议翻译Codex 说 Responses、LiteLLM 转成 Chat 转发给 DeepSeek链路就通了。本文给出的配置和命令可以直接照抄所有踩过的坑都标在第四节。一、为什么不能直接配我一开始也以为改改config.toml就行结果在三个坑里来回跳协议层面不兼容。Codex v0.143.0 把wire_api写死为responses它发出的每个请求都是POST /v1/responses。DeepSeek 的 OpenAI 兼容端点里只有/v1/chat/completions没有/v1/responses。直连必 404。wire_api没有可调空间。新版 Codex 已经把chat选项删了你设chat它直接拒绝加载配置设responses配置能加载但请求照样 404。翻这个字段纯属浪费时间。key 的字段名也有坑见 4.1。所以根因不是配置写错是两边协议不兼容必须有个翻译层。二、架构Responses/v1/responsesChat/v1/chat/completionsChat 响应 / SSEResponses 响应 / SSECodex CLIwire_apiresponsesLiteLLM 本地代理127.0.0.1:8787DeepSeek APICodex 全程只跟本地127.0.0.1:8787通信它以为自己在调 OpenAILiteLLM 负责把 Responses 语义翻成 Chat再把 DeepSeek 的回答翻回 Responses。流式SSE和工具调用function_callCodex 跑命令/改文件就靠这个都在翻译范围内。三、前置条件一个本地空闲端口本文用8787。Python 3.12用 venv 隔离别污染全局环境。一个 DeepSeek API key下文记为YOUR_DEEPSEEK_API_KEY。Codex CLI 任意只支持responses的版本v0.143.0 实测通过。四、踩坑记录重点先看这个再动手这些是我实际踩过的照着避能省至少三轮往返4.1env_key不是api_keyCodex 的config.toml里把整串 key 写进env_key是错的——Codex 会把它当环境变量名去getenv()于是报Missing environment variable: sk-...。正确做法是直接内联api_key sk-...。4.2wire_api chat已被新版 Codex 移除设成chat会直接报wire_api chat is no longer supported配置根本加载不了。别试。4.3wire_api responses直连 DeepSeek 必 404这是协议根因不是配置问题。设了能加载但每个请求都打到 DeepSeek 不存在的/v1/responses全部 404。翻wire_api无解。4.4 LiteLLM 模型前缀必须用deepseek/不能用openai/这是最阴的一个坑。如果你在litellm_config.yaml里写model: openai/deepseek-v4-flashLiteLLM 会认为这是个原生支持 Responses 的 OpenAI 兼容端点直接把/responses原样转发给 DeepSeek→ 又 404。只有写model: deepseek/deepseek-v4-flashLiteLLM 才会启用 Responses→Chat 的翻译逻辑。差一个前缀天差地别。4.5 只装litellm不够要litellm[proxy]启动代理时若只pip install litellm会缺backoff等依赖而启动失败。务必装 extraspip install litellm[proxy]。4.6 Codex 启动时的Model metadata not found警告无害每次启动都会看到⚠ Model metadata for deepseek-v4-flash not found. Defaulting to fallback metadata。这是因为deepseek-v4-flash是自定义模型不在 Codex 内置清单里它走兜底元数据。聊天场景实际无影响直接忽略。4.7 代理是常驻后台进程代理一旦退出比如启动它的终端/会话关闭Codex 就 404。下次用 Codex 前先手动把代理拉起来见 3.3 的启动命令。五、实操步骤5.1 建隔离环境并装依赖python-mvenv ~/.codex-proxy/venv# Windows~/.codex-proxy/venv/Scripts/pipinstalllitellm[proxy]uvicorn# macOS / Linux~/.codex-proxy/venv/bin/pipinstalllitellm[proxy]uvicorn注意Windows 的 venv 可执行文件在Scripts/下如Scripts/litellm.exe、Scripts/pip.exe类 Unix 在bin/下。下文脚本按 Windows 路径写类 Unix 自行替换。5.2 写 LiteLLM 配置~/.codex-proxy/litellm_config.yamlmodel_list:-model_name:deepseek-v4-flashlitellm_params:model:deepseek/deepseek-v4-flash# 关键必须是 deepseek/ 前缀见 4.4api_key:YOUR_DEEPSEEK_API_KEYdrop_params:truegeneral_settings:disable_auth:true# 本地代理关掉鉴权telemetry:falsemodel_name是暴露给 Codex 的模型名要和 Codex 配置里的model对齐。drop_params: true让 LiteLLM 丢掉 DeepSeek 不认识的参数避免偶发报错。5.3 启动代理写个启动脚本~/.codex-proxy/start-proxy.shWindows 版#!/usr/bin/env bashset-eVENV$HOME/.codex-proxy/venvCFG$HOME/.codex-proxy/litellm_config.yamlexec$VENV/Scripts/litellm.exe--config$CFG--port8787--host127.0.0.1后台启动nohupbash~/.codex-proxy/start-proxy.sh~/.codex-proxy/proxy.log21等代理就绪健康接口返回 200 即代表起来了最多等 40 秒foriin$(seq140);docode$(curl-s-o/dev/null-w%{http_code}http://127.0.0.1:8787/health/liveliness2/dev/null)[$code200]{echoproxy up after${i}s;break;}sleep1done停掉代理taskkill /IM litellm.exe /FWindows或pkill -f litellm类 Unix。5.4 改 Codex 配置指向代理~/.codex/config.toml里 provider 段改成model deepseek-v4-flash model_provider deepseek preferred_auth_method apikey [model_providers.deepseek] name DeepSeek via local proxy base_url http://127.0.0.1:8787/v1 # 指向本地代理不是 DeepSeek 官网 api_key YOUR_DEEPSEEK_API_KEY # 代理关了鉴权这里随便填也能通但留着不碍事 wire_api responsesbase_url从 DeepSeek 官网换成127.0.0.1:8787/v1是核心改动wire_api保持responses不动。六、验证三条 curl 全过才算通基础补全——应返回标准 Responses 结构output内含messageoutput_textcurl-s-XPOST http://127.0.0.1:8787/v1/responses\-HContent-Type: application/json\-d{model:deepseek-v4-flash,input:Reply with exactly one word: hi}工具调用——应返回function_callname 为ping这是 Codex 执行命令的关键能力curl-s-XPOST http://127.0.0.1:8787/v1/responses\-HContent-Type: application/json\-d{model:deepseek-v4-flash,tools:[{type:function,name:ping,description:return pong,parameters:{type:object,properties:{}}}],input:call the ping tool}流式SSE——应看到response.created→output_item.added→content_part.added事件流curl-s-N-XPOST http://127.0.0.1:8787/v1/responses\-HContent-Type: application/json\-d{model:deepseek-v4-flash,input:say hello in 3 words,stream:true}三条都正常直接codex就能用 DeepSeek 干活了。七、为什么是 LiteLLM 而不是降级 Codex我也考虑过降级到还支持wire_api chat的旧版 Codex但那条路等于把自己锁死在旧版本上以后 Codex 出新能力都用不了。LiteLLM 这层代理的好处是Codex 永远用最新版翻译逻辑独立演进DeepSeek 换成别的 Chat 协议供应商也只是改一行model映射。代价是多跑一个本地进程——对这个场景来说划算。