1. Codex CLI 升级 Responses API 后,DeepSeek/Kimi 为什么集体“被分手”
Codex CLI 是什么?简单说,它是 OpenAI 官方推出的命令行编码代理,能在终端里读代码、改文件、跑命令,适合习惯在 shell 里干活的开发者。它最近把默认通信协议切到了 Responses API,也就是请求打到/v1/responses这个路径。问题就出在这里:DeepSeek、Kimi、MiniMax、SiliconFlow 这些国内模型厂商,对外统一提供的是 Chat Completions 接口,路径是/chat/completions。两个协议不只是路径不同,请求体字段结构、流式 SSE 事件命名、返回数据结构全都不一样。
你可以把它理解成插头标准变了。Codex CLI 手里拿的是 Responses 这种新插头,而 DeepSeek/Kimi 墙上留的是 Chat Completions 这种老插座。你硬插,要么插不进去,要么插进去了也不通电。我见过最典型的报错有三种:第一种是模型列表加载异常,接口直接返回 404,因为 Codex CLI 去请求/v1/responses,而 DeepSeek 那边根本没有这个路由;第二种是 401,Key 明明是对的,但请求体结构对不上,服务端解析失败后返回鉴权类错误,容易误导你去反复检查 Key;第三种是流式响应崩成一串乱码,因为 Responses 的 SSE 事件名和 Chat Completions 的data:事件对不上,Codex CLI 解析不了。
这时候很多人第一反应是手动改配置,把 DeepSeek 的 base URL 写进 Codex 配置里。我试过,结果就是上面说的 404 加乱码。原因很简单:DeepSeek 支持 OpenAI 兼容格式,但 Codex CLI 要的不是“兼容”,它要的是 Responses API 的原生体验。你拿 Chat Completions 去哄 Codex CLI,就像拿辣条去喂猫,猫不仅不吃,还可能挠你。
那有没有办法让两边“复合”?有,而且不需要你去改 Codex CLI 的源码,也不需要你等 DeepSeek 官方去适配 Responses。核心思路是在本地加一层路由,把 Codex CLI 发出来的 Responses 格式请求,翻译成 Chat Completions 格式发给 DeepSeek/Kimi,等对方返回 Chat 格式响应后,再回译成 Responses 格式还给 Codex CLI。整个过程 Codex CLI 完全不知情,它以为自己还在跟标准的 Responses 端点通信。
这一层本地路由,配合 TaoToken 的统一 Key 接入,就能把 DeepSeek、Kimi 这些模型重新接回 Codex CLI。TaoToken 在这里的角色是统一入口:你不需要为每个模型厂商单独维护一套 Key 和 endpoint,而是通过一个统一的 Key 和 Base URL 去调用多个模型。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。下面我会把本地路由配置、auth.json 字段示例、以及 401/429 报错的验证动作一步步写清楚,目标是你照着做 5 分钟内能跑通。
适合谁看?如果你正在用 Codex CLI,并且想让它调用 DeepSeek 或 Kimi 来做编码任务,但被 Responses API 卡住了,这篇就是给你写的。如果你还没装 Codex CLI,也没关系,我会把前置步骤写全。如果你只是想验证某个模型能不能通,也可以先用模型对话页面测一下,地址在 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。
2. TaoToken 前置准备:统一 Key 与本地路由的定位
在动手改配置之前,先把 TaoToken 这边的准备工作做完。这一步不复杂,但顺序不能乱,否则后面路由起来了也调不通。
首先你需要一个 TaoToken 的 API Key。打开 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite ,在控制台里创建 Key。创建的时候注意两点:一是 Key 只显示一次,复制后先存到安全的地方;二是如果你打算同时用 DeepSeek 和 Kimi,不需要建两个 Key,一个 Key 就能在请求里通过 model 字段切换模型。这就是统一 Key 的意义:入口统一,模型选择交给请求参数。
拿到 Key 之后,你需要确认两件事:Base URL 和 Model ID。Base URL 用 https://taotoken.net/api ,注意这里不加任何 UTM 参数,直接写这个地址就行。Model ID 取决于你要调哪个模型,比如 DeepSeek 系列和 Kimi 系列都有各自的模型标识。你可以在接入文档里查到完整的模型列表和对应的 Model ID,文档地址是 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
这里要强调一个概念:TaoToken 不是让你绕过 Codex CLI 的协议要求,而是给你一个统一的 OpenAI 兼容入口。Codex CLI 要 Responses API,本地路由负责协议转换,TaoToken 负责把转换后的 Chat Completions 请求路由到正确的模型。三者关系是:Codex CLI → 本地路由(协议转换)→ TaoToken(统一入口)→ DeepSeek/Kimi。你不需要在 Codex CLI 里直接填 DeepSeek 的地址,也不需要把 DeepSeek 的 Key 暴露给 Codex CLI。
为什么推荐用 TaoToken 而不是直接连 DeepSeek 官方?两个原因。第一,统一 Key 省事,你换模型不用换 Key,也不用改 auth.json 里的鉴权字段,只改 model 就行。第二,本地路由需要一个稳定的上游 Base URL,TaoToken 的 https://taotoken.net/api 就是干这个的。如果你直接连 DeepSeek 官方,本地路由的配置里就要写 DeepSeek 的地址,换 Kimi 的时候又得改一遍,容易出错。
还有一个前置检查:确认你的 Codex CLI 版本。不同版本的 Codex CLI 对 auth.json 的字段要求略有差异,但核心字段是OPENAI_API_KEY和OPENAI_BASE_URL。你可以先在终端里跑codex --version看一下版本号。如果版本太旧,建议先升级,因为旧版本可能不支持通过环境变量覆盖 Base URL。升级命令取决于你的安装方式,如果是 npm 装的,用npm update -g @openai/codex就行。
最后,把本地路由的端口定下来。我建议用 15721,这个端口不常用,不容易冲突。你后面在 auth.json 和路由配置里都要用这个端口,所以先记住。如果你机器上 15721 已经被占用了,换成 15722 或 15723 也可以,但全文要统一。
准备工作做完,你应该手上有三样东西:TaoToken 的 API Key、Base URL(https://taotoken.net/api)、以及你要调的 Model ID。下面进入配置环节。
3. 可复制配置:本地路由 + auth.json 字段示例
这一节是核心,我会给出可以直接复制的配置片段。你需要改两个地方:一个是本地路由的配置文件,一个是 Codex CLI 的 auth.json。先改哪个都行,但建议先配路由,再配 auth.json,因为 auth.json 里的 Base URL 要指向路由的本地地址。
先说本地路由。我用一个 JSON 配置文件来定义路由规则,文件名就叫codex-router.json,放在你的用户目录下,比如~/.codex-router/codex-router.json。内容如下:
{ "listen": "127.0.0.1:15721", "upstream": { "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "wire_api": "chat_completions" }, "downstream": { "wire_api": "responses" }, "models": { "default": "deepseek-chat", "available": [ "deepseek-chat", "deepseek-reasoner", "kimi-k2", "kimi-latest" ] }, "timeout_seconds": 120, "log_level": "info" }这个配置里几个关键字段解释一下。listen是本地路由监听的地址和端口,Codex CLI 会往这里发请求。upstream.base_url是 TaoToken 的 API 地址,注意这里写的是https://taotoken.net/api,不带任何路径后缀。upstream.api_key_env表示 API Key 从环境变量TAOTOKEN_API_KEY读取,这样你不需要把 Key 明文写在配置文件里。upstream.wire_api设为chat_completions,因为 TaoToken 上游接受的是 Chat Completions 格式。downstream.wire_api设为responses,因为 Codex CLI 发出来的是 Responses 格式。models.default是默认模型,models.available是可选模型列表,你可以按需增减。
配置好路由文件后,设置环境变量。在终端里执行:
export TAOTOKEN_API_KEY="你的TaoToken API Key"如果你用的是 Windows PowerShell,命令是:
$env:TAOTOKEN_API_KEY="你的TaoToken API Key"注意,这个环境变量要在启动本地路由之前设置好,否则路由读不到 Key。如果你想让环境变量永久生效,可以写进~/.bashrc或~/.zshrc,但测试阶段建议先用临时环境变量,避免污染全局配置。
接下来配 Codex CLI 的 auth.json。这个文件的位置通常在~/.codex/auth.json,如果目录不存在就手动创建。内容如下:
{ "OPENAI_API_KEY": "你的TaoToken API Key", "OPENAI_BASE_URL": "http://127.0.0.1:15721/v1", "OPENAI_MODEL": "deepseek-chat" }这里三个字段都要写全。OPENAI_API_KEY填 TaoToken 的 Key,虽然本地路由也会从环境变量读 Key,但 Codex CLI 自己也需要一个非空的 Key 来通过本地校验,填同一个就行。OPENAI_BASE_URL指向本地路由的地址,注意路径是/v1,因为 Codex CLI 会在后面拼接/responses,最终请求打到http://127.0.0.1:15721/v1/responses,本地路由监听到这个请求后做协议转换。OPENAI_MODEL填你要用的模型 ID,比如deepseek-chat或kimi-k2。
如果你用的是 CC Switch 这类工具来管理 Codex CLI 的供应商配置,那么对应的三件套是:Base URL 填http://127.0.0.1:15721/v1,Key 填 TaoToken 的 Key,Model ID 填deepseek-chat或你需要的模型。CC Switch 的 Provider 配置里如果有meta.apiFormat字段,设为openai_chat,告诉它上游是 Chat Completions 格式。
配置写完后,启动本地路由。假设你用的是 Node.js 写的路由程序,启动命令类似:
node codex-router.js --config ~/.codex-router/codex-router.json启动后你应该看到日志里输出listening on 127.0.0.1:15721和upstream base_url https://taotoken.net/api。如果看到EADDRINUSE,说明端口被占用,改listen字段里的端口号,同时把 auth.json 里的OPENAI_BASE_URL也改成对应端口。
到这里,配置部分就完成了。下面进入验证环节,我会给出具体的请求命令和预期结果。
4. 验证请求与成功结果:从 404 到正常流式输出
配置写好了不代表就能跑通,必须做验证。验证分两步:先验证本地路由本身能通,再验证 Codex CLI 能通过路由调到模型。
第一步,用 curl 直接打本地路由的/v1/responses端点,模拟 Codex CLI 的请求格式。命令如下:
curl -sS http://127.0.0.1:15721/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的TaoToken API Key" \ -d '{ "model": "deepseek-chat", "input": "用一句话解释什么是递归", "stream": false }'注意这里的请求体用的是 Responses API 的字段:input而不是messages,stream控制是否流式。如果本地路由工作正常,它会把这个请求转换成 Chat Completions 格式发给 TaoToken,TaoToken 再路由到 DeepSeek,最后把响应回译成 Responses 格式返回。你应该看到类似这样的输出:
{ "id": "resp_abc123", "object": "response", "model": "deepseek-chat", "output": [ { "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "递归就是函数自己调用自己,直到满足某个终止条件。" } ] } ] }如果你看到的是 404,说明本地路由没有正确转发,检查upstream.base_url是不是写成了https://taotoken.net/api/v1这种带路径的形式。TaoToken 的 Base URL 就是https://taotoken.net/api,路径由路由程序自己拼接。如果你看到 401,说明 Key 有问题,检查环境变量TAOTOKEN_API_KEY是否设置成功,以及 auth.json 里的 Key 是否和 TaoToken 控制台里的一致。
第二步,验证流式输出。把上面的stream改成true,命令如下:
curl -sS http://127.0.0.1:15721/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的TaoToken API Key" \ -d '{ "model": "deepseek-chat", "input": "写一个 Python 快速排序", "stream": true }'正常的话你会看到一串 SSE 事件,每个事件以event:和data:开头,最后以data: [DONE]结束。如果流式输出到一半断了,或者事件名对不上,检查路由程序的downstream.wire_api是不是设成了responses。如果设成了chat_completions,Codex CLI 会解析不了。
第三步,验证 Codex CLI 本身。在终端里直接跑:
codex "用 Python 写一个读取 CSV 并统计行数的脚本"如果配置正确,Codex CLI 会通过本地路由调用 DeepSeek,然后返回代码。你应该能看到 Codex CLI 正常输出代码块,而不是报错。如果 Codex CLI 报local proxy failed,说明它连不上http://127.0.0.1:15721,检查路由程序是否在运行,以及端口是否一致。
第四步,换模型验证。把 auth.json 里的OPENAI_MODEL改成kimi-k2,或者直接在 curl 请求里把model改成kimi-k2,再跑一次。如果能正常返回,说明统一 Key 接入多模型是通的。你不需要为 Kimi 单独建 Key 或改 Base URL,只改 model 字段就行。
验证通过后,你可以把 Codex CLI 的默认模型设成你最常用的那个。如果你主要做长文本处理,可以设成 Kimi 系列;如果主要做代码生成,DeepSeek 系列更合适。切换模型只需要改 auth.json 里的OPENAI_MODEL,或者用 Codex CLI 的--model参数临时覆盖。
5. 本篇常见错排查:401、429、local proxy failed 与 reading choices
这一节我把验证过程中最容易遇到的几个报错列出来,每个都给出原因和修复动作。你遇到报错时可以直接对照。
第一个,401 Unauthorized。这个报错最容易误导人,因为 Key 明明是对的。原因通常有两个:一是 auth.json 里的OPENAI_API_KEY和本地路由环境变量里的TAOTOKEN_API_KEY不一致,Codex CLI 用 auth.json 里的 Key 做本地校验,路由用环境变量里的 Key 去请求 TaoToken,两边不一致就会 401。修复动作:把两个地方都设成同一个 TaoToken Key。二是请求体结构不对,比如你把input写成了messages,TaoToken 上游解析失败后返回 401 类错误。修复动作:确认发给本地路由的请求用的是 Responses 格式,input字段而不是messages。
第二个,429 Too Many Requests。这个报错说明请求频率超了,或者账户额度不够。原因可能是你在短时间内发了大量请求,或者 TaoToken 账户的余额不足。修复动作:先降低请求频率,加个sleep或重试间隔;然后去 TaoToken 控制台检查余额和用量。如果你是在跑批量任务,建议在路由配置里加一个rate_limit字段,控制每秒请求数。另外,429 也可能是上游模型厂商的限流,这种情况下换个模型试试,比如从deepseek-chat换成kimi-k2。
第三个,local proxy failed。这个报错是 Codex CLI 发出的,意思是它连不上本地路由。原因有三个:一是路由程序没启动,修复动作是重新启动路由并确认日志里有listening输出;二是端口不一致,auth.json 里写的是 15721,但路由配置里写的是 15722,修复动作是统一端口;三是防火墙拦截了本地回环请求,这种情况比较少见,修复动作是检查系统防火墙设置,确保 127.0.0.1 的 15721 端口允许本地连接。
第四个,reading choices 相关报错。这个报错通常出现在流式响应解析阶段,错误信息里会提到reading 'choices'或cannot read property 'choices' of undefined。原因是本地路由把 Responses 格式的响应回译成 Chat Completions 格式时,字段结构对不上,Codex CLI 在解析时找不到choices字段。修复动作:检查路由程序的downstream.wire_api是不是设成了responses,如果设成了chat_completions,Codex CLI 会按 Responses 格式解析,自然找不到choices。另外,检查路由程序的版本,旧版本可能没有正确处理 Responses 的output字段到 Chat Completions 的choices字段的映射。
第五个,OAuth 相关报错。如果你在 Codex CLI 里看到 OAuth 登录失败的提示,说明 Codex CLI 在尝试用 OAuth 方式鉴权,而不是用 auth.json 里的 API Key。修复动作:确认 auth.json 文件存在且字段完整,然后检查 Codex CLI 的启动参数里有没有--oauth之类的选项,如果有,去掉它。Codex CLI 默认会优先读 auth.json,如果 auth.json 不存在或格式不对,才会走 OAuth 流程。
第六个,模型列表加载异常。这个报错通常发生在 Codex CLI 启动时,它去请求/v1/models端点,但本地路由没有实现这个端点。修复动作:在路由配置里加一个models端点映射,或者直接在 auth.json 里写死OPENAI_MODEL,让 Codex CLI 跳过模型列表加载。如果你用的是 CC Switch,它通常会自动处理模型列表,你只需要在 Provider 配置里填好 Model ID。
排查完这些报错,你应该能跑通整个链路了。如果还有问题,可以去接入文档里查更详细的错误码说明,文档地址是 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。如果你只是想快速验证某个模型能不能通,不想折腾本地路由,可以先用模型对话页面测一下,地址是 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。
6. 长期编码与 Agent 场景:把统一 Key 接入固化下来
跑通一次不算完,如果你打算长期用 Codex CLI 配合 DeepSeek/Kimi 做编码任务,建议把配置固化下来,避免每次重启终端都要重新设置环境变量和启动路由。
第一件事,把环境变量写进 shell 配置文件。如果你用 bash,编辑~/.bashrc,加一行export TAOTOKEN_API_KEY="你的Key";如果你用 zsh,编辑~/.zshrc,加同样的内容。然后执行source ~/.bashrc或source ~/.zshrc让它生效。这样每次打开终端,环境变量都自动就绪。
第二件事,把本地路由做成后台服务。如果你用 macOS,可以写一个 launchd plist 文件,让路由程序开机自启;如果你用 Linux,可以写一个 systemd service 文件。这样你不需要每次手动启动路由,Codex CLI 随时都能连上。如果你不想折腾系统服务,也可以用一个简单的 shell 脚本,在启动 Codex CLI 之前先检查路由是否在运行,不在就启动它。
第三件事,把 auth.json 纳入版本管理时要小心。auth.json 里有 API Key,不要提交到公开的 Git 仓库。你可以把 auth.json 加到.gitignore里,或者用一个模板文件auth.json.example来记录字段结构,实际使用时再复制成 auth.json 并填入真实 Key。
第四件事,如果你同时用多个模型,可以在路由配置里把models.available列全,然后在 Codex CLI 里用--model参数临时切换。比如codex --model kimi-k2 "帮我总结这个文件"。这样你不需要改 auth.json,就能在不同任务之间切换模型。对于长期编码任务,我建议把默认模型设成 DeepSeek 系列,因为它在代码生成上表现稳定;对于需要处理长文档或长上下文的任务,临时切到 Kimi 系列。
第五件事,如果你打算把 Codex CLI 用在 Agent 场景里,比如让它自动读代码、改文件、跑测试,那么本地路由的稳定性就很重要。建议在路由配置里加上重试逻辑和超时控制。timeout_seconds设成 120 或更长,避免长任务被截断。如果上游返回 429,路由应该自动重试而不是直接报错。这些逻辑可以在路由程序里实现,也可以用一个反向代理层来做。
如果你需要更系统的编码 Agent 能力,比如多模型编排、任务队列、长期记忆,可以了解一下 Coding Plan,地址是 https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。它适合需要长期跑编码任务、并且希望统一管理多个模型的场景。对于只是偶尔用 Codex CLI 写写脚本的开发者,上面的本地路由加统一 Key 方案已经够用了。
最后说一个实际经验:本地路由的日志一定要留着。当你遇到 401 或 429 时,日志里会记录完整的请求和响应,比你在 Codex CLI 里看到的报错信息详细得多。我习惯把日志输出到一个文件里,比如~/.codex-router/router.log,出问题时直接tail -f看最后几行,通常一眼就能定位。如果你用的是 CC Switch,它自带的日志面板也能看到请求成功率、活跃连接数这些指标,成功率突然掉到 0% 的时候,先检查路由是否在运行,再检查 Key 是否过期。
配置固化之后,你每次打开终端,Codex CLI 就能直接调用 DeepSeek 或 Kimi,不需要再重复本文的步骤。如果哪天 Codex CLI 又升级了协议,或者你想换一个新的模型厂商,只需要改路由配置里的upstream.base_url和models列表,auth.json 和 Codex CLI 本身都不用动。这就是本地路由加统一 Key 的价值:把变化隔离在一层配置里,让上层的编码工具保持稳定。