Codex 使用 DeepSeek:Responses 协议、CC Switch 路由与验证方法

依据 Codex 配置参考、DeepSeek API 与 CC Switch 文档,说明 Responses 和 Chat Completions 的差异,并验证本地路由与 OpenRouter Responses Beta。

想让 Codex 使用 DeepSeek,第一反应通常是改 ~/.codex/config.toml

1
2
model = "deepseek-chat"
base_url = "https://api.deepseek.com"

这个思路在一些旧版本或普通 OpenAI SDK 场景里确实成立,但放到当前 Codex CLI 上,很容易撞到一个底层问题:Codex 的自定义模型供应商走的是 OpenAI Responses 协议,而 DeepSeek 官方接口主要提供 OpenAI 兼容的 Chat Completions 调用方式。

我本机当前是 codex-cli 0.111.0codex --help 里可以看到它支持 --config--model--profile 这些配置入口;OpenAI 官方 Codex 配置参考也写得很明确:model_providers.<id>.wire_api 目前只支持 responses,省略时也默认是 responses

DeepSeek 官方文档则给出的调用路径是 https://api.deepseek.com/chat/completions,示例也是 client.chat.completions.create(...)。所以问题不在于 DeepSeek 不能被 OpenAI SDK 调用,而在于 Codex 发出去的请求语义和 DeepSeek 原生接口能理解的语义不完全是一套东西。

这就是为什么直接把 base_url 改成 https://api.deepseek.com 后,可能出现下面这些现象:

  • 请求路径不匹配,直接 404 或返回格式不对。
  • 多轮对话、工具调用、补丁生成时解析失败。
  • tool_calls 顺序、消息结构、流式事件格式对不上。
  • 看起来模型能回一句话,但一到 Codex 真正干活就开始报错。

更稳的办法,是在 Codex 和 DeepSeek 之间放一个“翻译层”。常见有两种路线。

方法一:使用 CC Switch 的 DeepSeek 本地路由

本地网关的作用不是简单转发,而是把 Codex 的 Responses 请求转换成 DeepSeek 能处理的 Chat Completions,再把普通 JSON、SSE 流、推理内容和工具调用转换回 Codex 能解析的 Responses 事件。

CC Switch 从 3.16 起提供这一条明确的官方项目路径。操作顺序是:

  1. 从官方 Releases 安装当前版本 CC Switch。
  2. 切换到顶部的 Codex 页面并新增 Provider。
  3. 选择内置 DeepSeek 预设,填写 DeepSeek API Key。
  4. 保留预设自动启用的 Needs Local Routing
  5. 在设置的 Routing 页面启动本地路由,并为 Codex 开启接管。
  6. 完全退出并重新启动 Codex,使模型目录重新加载。

路由启用后,官方指南给出的 Codex 本地地址通常是:

1
http://127.0.0.1:15721/v1

不要把这个端口写成固定真理;以 CC Switch 当前界面和生成的用户级 ~/.codex/config.toml 为准。CC Switch 会管理模型目录和鉴权字段,手动复制旧教程中的 TOML 反而容易与当前版本冲突。

进入 Codex 后,先用 /model 检查是否显示 DeepSeek 预设,再发一个最小请求。随后查看 CC Switch Routing 页面的请求数量或日志;只有请求确实经过本地路由,才能证明不是误用了其他 Provider。

实际环境记录

本文复核时,本机执行结果为:

1
codex-cli 0.111.0

codex --help 同时显示 --config--model--profile 可用。当前机器没有安装 CC Switch,也没有配置 DeepSeek Key,因此本文不声称完成了端到端 DeepSeek 生成实测;上面的界面步骤来自 CC Switch 项目文档。读者自己的验收应保存 Codex 版本、CC Switch 版本、请求日志和工具调用结果。

方法二:用 OpenRouter BYOK 做线上桥接

如果不想运行本地转换层,可以评估 OpenRouter 的 Responses API Beta 与 BYOK。BYOK 是把自己的上游供应商 Key 绑定到 OpenRouter,由 OpenRouter 负责路由;Codex 访问时使用的仍是 OpenRouter API Key。

OpenRouter 当前把 Responses API 标为 Beta,并说明它是无状态实现。接口能力和 Codex 所需事件仍可能变化,因此这条路线应先验证,再决定是否用于长期工作。

这里最容易写错的是环境变量。Codex 访问的是 OpenRouter,所以 env_key 通常应该是 OPENROUTER_API_KEY,不是 DEEPSEEK_API_KEY。DeepSeek Key 要在 OpenRouter 的 BYOK 或 provider key 设置里添加。

配置示例:

1
2
3
4
5
6
7
8
9
[profiles.deepseek-openrouter]
model = "deepseek/deepseek-chat"
model_provider = "openrouter"

[model_providers.openrouter]
name = "OpenRouter"
base_url = "https://openrouter.ai/api/v1"
env_key = "OPENROUTER_API_KEY"
wire_api = "responses"

启动方式:

1
2
export OPENROUTER_API_KEY="your-openrouter-key"
codex --profile deepseek-openrouter

PowerShell:

1
2
$env:OPENROUTER_API_KEY="your-openrouter-key"
codex --profile deepseek-openrouter

然后在 OpenRouter 后台添加 DeepSeek provider key,并限制允许使用该 BYOK Key 的 OpenRouter API Key。模型 ID 必须以 OpenRouter 当前模型目录为准,不能把 DeepSeek 官方模型名直接照搬后假定可用。

在启动 Codex 前,先验证 Responses 端点本身:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$headers = @{
  Authorization = "Bearer $env:OPENROUTER_API_KEY"
  "Content-Type" = "application/json"
}

$body = @{
  model = "从 OpenRouter 模型目录复制的 DeepSeek ID"
  input = "只回复 READY"
  max_output_tokens = 16
} | ConvertTo-Json -Depth 6

Invoke-RestMethod `
  -Uri https://openrouter.ai/api/v1/responses `
  -Method Post `
  -Headers $headers `
  -Body $body

这个请求成功,只证明基础 Responses 调用可用。还要在临时仓库中验证文件读取、补丁、流式响应和工具调用,才能判断它是否满足 Codex 工作流。

这条路省掉本地网关维护,但会增加线上中间层,而且 Responses 仍处于 Beta。排障时要分别保存 Codex、OpenRouter 和上游 DeepSeek 的错误信息。

要不要继续用 deepseek-chat 这个模型名?

DeepSeek 官方文档在 2026 年 5 月的说明里,推荐模型名已经出现 deepseek-v4-flashdeepseek-v4-pro,并提示 deepseek-chatdeepseek-reasoner 兼容别名会在 2026-07-24 之后废弃。

所以新配置里更建议优先测试:

1
model = "deepseek-v4-flash"

如果走 OpenRouter,则要按 OpenRouter 的模型命名来写,例如:

1
model = "deepseek/deepseek-chat"

实际可用名称以你所用网关或 OpenRouter 模型页为准。模型名不对时,错误通常会表现为 model not found、404,或者 provider 找不到对应 endpoint。

直接改 DeepSeek 官方 base_url 为什么不推荐

你当然可以试着写:

1
2
3
4
5
6
7
8
[profiles.deepseek-direct]
model = "deepseek-v4-flash"
model_provider = "deepseek"

[model_providers.deepseek]
name = "DeepSeek"
base_url = "https://api.deepseek.com"
env_key = "DEEPSEEK_API_KEY"

但这更像排错实验,不适合作为稳定方案。因为 Codex 会按 Responses 协议去和自定义 provider 说话,而 DeepSeek 官方示例走的是 /chat/completions。如果 DeepSeek 或 Codex 未来补齐了兼容层,这种直连才可能变得简单;在此之前,桥接层更靠谱。

改完配置后还是走 OpenAI 怎么办

先确认配置文件位置。全局配置应该在:

1
~/.codex/config.toml

项目里的 .codex/config.toml 不适合放 model_providermodel_providers 这类机器级 provider 配置。OpenAI 官方文档也提醒,项目级配置不会覆盖这些本地 provider 和认证相关字段。

不要把 codex logout 当成通用排错第一步。官方登录态和第三方 Provider 配置是不同问题;贸然退出只会增加恢复成本。先检查正在使用的 profile、model_provider、模型目录和本地路由日志。

还可以用临时参数做一次快速验证:

1
codex --profile deepseek-openrouter

或者:

1
codex -c model_provider=openrouter -c model="实际模型 ID"

如果这样能生效,说明配置本身可读;如果不生效,优先检查 profile 名称、TOML 语法、环境变量是否只在当前 shell 里有效。

排障清单

  • 401:Key 不对,或者 env_key 指向了错误的环境变量。
  • 404base_url 或模型名不对,也可能是把 Responses 请求打到了只支持 Chat Completions 的地址。
  • tool_calls、patch、流式解析报错:大概率是协议桥接不完整。
  • 仍显示默认 OpenAI 模型:确认用户级配置、profile 与 /model 结果,不要先删除登录态。
  • PowerShell 设置环境变量后新开窗口失效:$env:... 只对当前会话生效,需要长期保存就改用户环境变量。
  • OpenRouter BYOK 没走自己的 DeepSeek Key:检查 OpenRouter 后台 provider key 是否绑定、是否允许当前 OpenRouter API Key 使用,以及是否开启了 fallback。

结论

让 Codex 使用 DeepSeek,不是不能改 config.toml,而是不能只改 base_url 就指望一切自动兼容。

当前可以验证的两条路是:

  1. 用 CC Switch 本地路由做 Responses 与 Chat Completions 转换。
  2. 用 OpenRouter Responses API Beta,再结合 BYOK 路由到自己的 DeepSeek Key。

两种方法都不能只以“返回一句话”作为成功标准。至少要验证模型选择、流式输出、文件修改、工具调用、错误恢复和 Key 是否实际走向预期 Provider。

参考资料: