Codex 接入 DeepSeek 总是报错?一次完整的排查记录

Codex 想换脑子换成 DeepSeek,路上大概率会踩五个坑:curl 命令语法、本地代理网络环境、Provider 格式配置、上游协议不匹配、测试请求字段错误。这篇文章把这五个坑挨个拆开讲清楚,附带每一步的判断依据,看完基本能自己独立排查。

为什么 DeepSeek 接不进 Codex,一填 Key 就报错

Codex 现在默认走的是 OpenAI 的 Responses API,请求路径是 /responses,消息体里用 input 字段承载对话内容。DeepSeek 官方对外暴露的是 Chat Completions 接口,路径是 /chat/completions,消息体用的是 messages 字段。这两套协议在请求结构、流式事件、工具调用表达上都不一样,直接把 DeepSeek 的地址填进 Codex 配置,基本必然出问题——要么模型列表读不出来,要么发消息直接 404。

CC Switch 这类工具解决问题的思路很直接:让 Codex 始终以为自己在跟一个支持 Responses API 的服务对话,实际上背后跑着一个本地转换层(默认监听 127.0.0.1:15721),把 Responses 请求翻译成 Chat Completions 发给 DeepSeek,再把返回结果翻译回 Responses 格式还给 Codex。理解了这一层”翻译官”的存在,后面所有报错基本都能对号入座。

第一个坑:curl 测试命令本身写错了

排查时最容易先入为主地怀疑服务本身,但很多时候第一步就栽在了终端命令上。Windows 下如果在 cmd.exe 里直接抄网上那种 bash 风格的 curl 命令,比如用单引号包裹 JSON、用 $VAR 取环境变量,会得到一个看起来莫名其妙的报错:

expected value at line 1 column 1

原因很朴素:cmd.exe 根本不认识单引号做字符串定界符,它会把单引号原样当成字符发出去,JSON 解析器读到的第一个字符自然不是 {$DEEPSEEK_API_KEY 这种写法在 cmd 里也不会被展开,cmd 的变量语法是 %VAR%

cmd.exe 里正确的写法是用双引号包 JSON,内部双引号转义:

curl http://127.0.0.1:15721/v1/responses ^
  -H "Content-Type: application/json" ^
  -H "Authorization: Bearer 你的Key" ^
  -d "{\"model\":\"deepseek-v4-pro\",\"input\":[{\"role\":\"user\",\"content\":\"hi\"}],\"stream\":false}"

嫌麻烦的话,直接换成 PowerShell,能继续用单引号加 $env: 前缀取变量,体验会顺滑很多。这一步不是什么高深问题,但确实卡住了不少人——排查复杂系统时,反而是最基础的终端语法容易被忽略。

第二个坑:本地代理连不上 DeepSeek 服务器

命令语法改对之后,如果拿到的报错变成类似这样:

cause: 转发失败: 上游请求发送失败: error sending request

这说明请求已经正确到达了本地的 CC Switch 代理进程,代理也确实尝试往外发请求了,但连接 DeepSeek 服务器这一步失败了。这时候第一件该做的事,是绕开代理,直接用 curl 测一次官方接口

curl https://api.deepseek.com/v1/models -H "Authorization: Bearer 你的Key"

如果这条也失败,问题在网络本身或者 Key;如果这条能拿到正常的模型列表返回,说明网络和 Key 都没毛病,问题精确定位在”CC Switch 进程自己的网络环境”上。

这里有个容易被忽略的细节:终端窗口的网络状态和后台常驻进程的网络状态,不是一回事。如果电脑上跑着 VPN 或代理软件,且中途切换过开关状态,终端里新起的 curl 会用当前状态,但 CC Switch 是早先启动的后台进程,读取到的可能是它启动那一刻的代理环境变量,跟你现在的状态对不上。检查一下:

echo %HTTP_PROXY%
echo %HTTPS_PROXY%
echo %ALL_PROXY%

如果这几个变量之前配置过,尤其是给 Codex 用过 .env 文件但没写 NO_PROXY,就容易出现”开着代理能用、一关代理就失败,或者反过来”的情况。最省事的解决办法是把 CC Switch 进程彻底关掉重启,让它用当下这套网络配置重新建立连接,而不是指望它自己感知到外部代理状态的变化。

第三个坑:连上了,但 DeepSeek 返回 404

网络链路走通之后,如果错误变成:

upstream_status: HTTP 404; cause: 上游错误 (404)

这说明请求已经成功送达 DeepSeek 服务器,服务器也给出了明确答复——只是答复是”你访问的路径不存在”。这时候问题不再是网络层,而是回到了最开始那个协议不匹配的老问题:CC Switch 没有把这个 Provider 识别成”需要格式转换”的类型,而是把 Responses 风格的请求原样透传给了 DeepSeek,DeepSeek 自然找不到 /responses 这个路径。

排查思路很直接,去检查这个 Provider 的配置里有没有类似”API Format”或”是否需要本地路由”这样的开关。如果这个 Provider 是手动添加的,很容易漏掉勾选”OpenAI Chat Completions(需要路由)”这一项。比起手填,更稳的做法是删掉手动配置,改用工具内置的 DeepSeek 预设——预设本身就是针对协议差异提前适配好的,能省掉大部分手工踩坑的机会。这也是我在这轮排查里体会最深的一点:遇到”某个第三方模型接不进某个 Agent 工具”这类问题时,先看有没有官方或社区维护的预设,比自己对着文档现填参数靠谱得多。

第四个坑:终于打通了,但报”消息为空”

配置改成内置预设之后,如果报错变成:

upstream_status: HTTP 400; cause: Empty input messages

先别慌——这其实是个好信号,说明请求已经被正确翻译并送到了 DeepSeek,DeepSeek 也正常处理了请求,只是它读到的对话内容是空的。顺着这条线往回查,问题往往出在测试用的 curl 命令本身用错了字段名

/responses 端点对应的是 Responses API 协议,承载对话内容的字段是 input;而很多人测试时习惯性沿用了 Chat Completions 的写法,用了 messages 字段。CC Switch 按 Responses 格式解析请求体,找不到 input,只能把一个空数组转发给 DeepSeek,DeepSeek 收到空消息,规规矩矩地报了这个错——这不是 bug,是测试脚本本身用错了协议格式。

正确的测试写法:

curl http://127.0.0.1:15721/v1/responses ^
  -H "Content-Type: application/json" ^
  -H "Authorization: Bearer 你的Key" ^
  -d "{\"model\":\"deepseek-v4-pro\",\"input\":[{\"role\":\"user\",\"content\":\"hi\"}],\"stream\":false}"

到这一步,如果拿到的是带具体内容的正常返回,说明 Codex → CC Switch → DeepSeek 这条链路已经完全打通了,可以直接回 Codex App 里发消息实测——毕竟 Codex App 自己发出去的请求天然就是标准 Responses 格式,不会有手写测试脚本这种格式误用的问题。

两种协议的核心差异,一张表说清楚

对比项 OpenAI Responses API(Codex 默认) OpenAI Chat Completions(DeepSeek 官方)
请求路径 /responses /chat/completions
对话内容字段 input messages
典型报错触发点 字段填错、端点没适配 直接被当成 Responses 端点访问会 404
需要转换层吗 是转换的目标格式 需要被转换成这个格式再发出去

理解这张表之后再回头看前面四个坑,会发现它们其实是同一个根因在链路不同环节的不同表现:语法错误发生在”你自己发请求”这一步,网络失败发生在”代理转发给上游”这一步,404 发生在”协议没被正确识别转换”这一步,Empty messages 发生在”你测试时又用错了字段”这一步。排查这类跨协议桥接工具的问题,养成”先确认自己卡在链路的哪一环”的习惯,比一上来就怀疑某个具体组件坏了要高效得多。

一个不得不提的题外话:API Key 的安全习惯

排查过程里很容易图省事,把真实的 API Key 直接明文写进命令行贴出来测试或求助。这个习惯风险不小:聊天记录、截图、复制粘贴板,任何一个环节泄露出去,Key 都可能被盗用产生额外费用。更稳妥的做法是测试时用占位符代替真实 Key,真正需要执行的命令在自己本地环境里补全,或者用环境变量间接引用,而不是把 Key 明文写死在命令里到处传播。一旦怀疑 Key 已经在不安全的地方出现过,直接去平台后台吊销重新生成,成本远比善后一次泄露事故要低。

实用摘要 / 操作清单

  • [ ] 确认终端类型(cmd / PowerShell),curl 命令语法要对应,不要混用
  • [ ] 直接 curl 官方 DeepSeek 接口,排除网络和 Key 本身的问题
  • [ ] 检查 HTTP_PROXY / HTTPS_PROXY 等环境变量,确认代理状态和实际网络一致
  • [ ] 彻底重启本地代理/路由工具的进程,而不是仅仅切换配置
  • [ ] 优先用工具内置的 DeepSeek 预设,避免手动配置漏勾”需要路由转换”选项
  • [ ] 测试请求体字段要对应 /responses 端点的 input,不要照抄 Chat Completions 的 messages
  • [ ] 链路测通后回归 Codex App 里实测,而不是止步于命令行测试
  • [ ] 任何测试中出现过的真实 API Key,用完就去后台重新生成

一页速览

Codex 默认说 Responses 语言,DeepSeek 官方只懂 Chat Completions 语言,中间必须有一层翻译。所有报错基本都能归到”翻译前””翻译中””翻译后”三个阶段里的某一个:命令语法错误发生在你自己组装请求的阶段,网络连接失败发生在翻译层往外转发的阶段,404 发生在翻译层没识别出需要翻译的阶段,Empty messages 发生在你测试翻译层时自己又用错了语言。把这条链路在脑子里过一遍,遇到新的报错也能顺着这个思路快速定位。

FAQ

Q:本地代理测试都通了,Codex App 里还是连不上,是为什么?
大概率是 Codex 本地配置文件里的 base URL 没有真正指向本地路由地址,或者路由开关没打开,可以直接检查配置文件里的地址是不是写的是本地端口。

Q:为什么直接 curl DeepSeek 官方接口能成功,走本地代理就不行?
说明网络和 Key 都没问题,问题出在本地代理进程自身的网络环境(比如残留的代理设置),跟你终端当前状态不一致,重启代理进程通常能解决。

Q:404 和 400 报错有什么本质区别?
404 通常意味着请求根本没走对路径,协议层面就没对上;400 说明路径对了、协议也对上了,但请求体里的具体内容有问题,比如字段名错了或者内容为空。

Q:一定要用内置预设吗,自己手动配置不行吗?
手动配置能跑通,但需要自己确认每一个协议细节都填对,包括是否需要路由转换、字段格式等,出错概率更高。内置预设是针对这些细节提前适配好的,优先用预设能省掉大量排查时间。

Q:Windows 下到底该用 cmd 还是 PowerShell 测试?
两个都能用,但语法不能混着抄。PowerShell 支持单引号包 JSON、$env: 取变量,写法更接近常见教程;cmd 需要用双引号加转义,教程里的命令经常需要手动改写才能用。

Q:报错信息里能看出请求到底走到哪一步失败了吗?
基本可以。error sending request 类的通常是网络连接层面失败;upstream_status 字段出现,说明请求已经送到了上游服务器并拿到了明确的 HTTP 状态码,问题在服务器端的解读逻辑上,不在网络连通性上。