1. 为什么要把 Codex 接到 DeepSeek 上
Codex CLI 是 OpenAI 推出的终端编程助手,默认走的是官方 Responses API,模型固定指向 GPT 系列。问题在于,官方额度有限、按量计费不便宜,而且国内网络环境下调用官方接口的体验并不稳定。DeepSeek 的 API 兼容 OpenAI 的接口协议,价格只有官方的一个零头,推理能力在代码场景下也够用,所以把 Codex 的请求转发到 DeepSeek 上,是一个性价比很高的组合方案。
这个方案适合三类人:一是已经在用 Codex CLI、想降低调用成本的开发者;二是想用 DeepSeek 的代码能力但不想换工具链的人;三是手里有 DeepSeek API Key、想把它接进现有工作流的技术人员。整个配置过程不复杂,核心就是改一个config.toml文件,但坑不少,尤其是模型名、接口路径、认证方式这几处,稍不注意就会报 401 或 400。
我前后折腾了大概两个晚上,踩了 401 未授权、模型名不识别、上下文超限、配置项被忽略这几个典型问题,最后跑通了完整链路。下面把整个过程拆开讲,包括每一步为什么这么做、参数怎么填、报错怎么查。
2. 核心原理与方案选型拆解
2.1 Codex 的请求链路到底长什么样
Codex CLI 本质上是一个命令行客户端,它不自己跑模型,而是把用户的输入、上下文、工具调用请求打包成 HTTP 请求,发给后端 API。默认情况下,这个后端是 OpenAI 的api.openai.com,走的是/responses这个端点,也就是所谓的 Responses API。
Responses API 和传统的 Chat Completions API 不太一样。Chat Completions 是"你发消息、我回消息"的简单结构,而 Responses API 支持更复杂的工具调用、多轮状态管理、内置工具(比如代码执行、文件检索)。Codex 依赖 Responses API 的这些特性来实现它的 agent 能力,比如自动读写文件、执行命令、多步推理。
所以,要让 Codex 走 DeepSeek,有两种思路:
- 思路一:让 DeepSeek 直接兼容 Responses API。但 DeepSeek 目前主要提供的是 Chat Completions 格式的接口,Responses API 的支持并不完整。
- 思路二:在中间加一层代理,把 Codex 发出的 Responses 格式请求,转换成 DeepSeek 能理解的 Chat Completions 格式,再把 DeepSeek 的返回转换回 Responses 格式。
实际社区里跑通的方案,基本都走思路二。有些是用现成的转换代理工具,有些是自己写一个轻量转发层。这也是为什么热词里会出现cc switch local proxy failed while handling codex endpoint /responses这类报错——代理层在处理/responses端点时出了问题。
2.2 为什么选 DeepSeek 而不是别的
选 DeepSeek 有几个现实理由。第一是价格,DeepSeek 的 API 定价在同类模型里属于很低的一档,尤其是缓存命中后的价格,长期用下来成本差距很明显。第二是代码能力,DeepSeek 在代码生成、补全、重构这些任务上的表现,日常开发够用。第三是接口兼容性,DeepSeek 的 API 格式跟 OpenAI 的 Chat Completions 高度一致,改造成本低。
对比其他选项:智谱的 API 也能用,但模型风格和 Codex 的 agent 逻辑匹配度需要调;本地部署 DeepSeek(比如在 Jetson Orin 上跑)虽然数据不出本地,但推理速度和显存要求对普通开发者不友好,除非你有明确的离线需求。所以对大多数人来说,直接用 DeepSeek 的云端 API 是最省事的。
2.3 config.toml 在整个链路里的角色
Codex 的配置文件config.toml是控制行为的核心。它决定了:
- 用哪个模型(
model字段) - 请求发到哪个地址(
base_url或 provider 配置) - 用什么认证方式(API Key 怎么传)
- 哪些工具和 MCP server 启用
热词里有一条codex is ignoring 1 unrecognized configuration setting. check for typos or deprecated settings. user (c:\users\丁子洋.codex\config.toml): mcp_servers.node_repl.type is ignored.这个报错说明 Codex 对配置项的校验很严格,写错字段名或者用了已废弃的字段,它不会报错退出,而是直接忽略,然后你可能半天找不到问题在哪。
还有chatgpt 无法加载 config.toml,因此此对话串无法继续。请修复 config.toml:model这类问题,通常是 TOML 语法错误或者字段类型不对导致的。TOML 对格式敏感,字符串要加引号,布尔值不能加引号,这些细节后面会细讲。
3. 环境准备与前置检查
3.1 安装 Codex CLI 的正确姿势
Codex CLI 的安装方式取决于你的系统。官方推荐用 npm 全局安装:
npm install -g @openai/codex装完之后用codex --version验证。如果提示命令找不到,检查 npm 的全局 bin 目录有没有加到 PATH 里。Windows 上常见的问题是 npm 全局目录不在环境变量里,需要手动加。
也有直接下载安装包的方式,热词里出现的codex安装包、codex官网下载、codex安装 csdn说明不少人在找离线安装的路子。如果你网络环境受限,npm 装不动,可以去官方仓库的 releases 页面找对应平台的二进制包,解压后把可执行文件放到 PATH 目录下。
安装完成后,第一次运行codex会引导你登录。默认是走 OpenAI 账号授权。但我们的目标是接 DeepSeek,所以登录这一步可以跳过或者用 API Key 方式配置。如果你已经登录了官方账号,也没关系,后面改配置会覆盖掉默认的 provider。
3.2 拿到 DeepSeek 的 API Key
去 DeepSeek 的开放平台注册账号,在 API Keys 页面创建一个新的 Key。创建后立刻复制保存,页面刷新后就看不到了。Key 的格式通常是sk-开头的一串字符。
这里有个高频坑:热词里反复出现unexpected status 401 unauthorized: incorrect api key provided: sk-svcac****。这个报错的意思是 Key 无效或者传错了。常见原因有三个:
- Key 复制的时候带了空格或者换行
- Key 已经过期或者被删除
- 请求发到了错误的地址,导致认证信息没被正确识别
建议拿到 Key 之后,先用 curl 单独测一下,确认 Key 本身是有效的:
curl https://api.deepseek.com/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的key" \ -d '{ "model": "deepseek-chat", "messages": [{"role": "user", "content": "hello"}] }'如果这个请求返回正常,说明 Key 和网络都没问题,问题就出在 Codex 的配置上。如果这个请求就报 401,那先解决 Key 的问题,别往下走。
3.3 确认 config.toml 的位置
Codex 的配置文件默认放在用户目录下的.codex文件夹里。不同系统的路径:
| 系统 | 路径 |
|---|---|
| Windows | C:\Users\你的用户名\.codex\config.toml |
| macOS | /Users/你的用户名/.codex/config.toml |
| Linux | /home/你的用户名/.codex/config.toml |
热词里出现的c:\users\丁子洋.codex\config.toml就是典型的 Windows 路径。注意.codex前面有个点,是隐藏文件夹,Windows 上需要在文件管理器里开启"显示隐藏文件"才能看到。
如果这个文件不存在,手动创建一个。TOML 文件用 UTF-8 编码保存,别用 GBK,否则中文注释可能乱码导致解析失败。
4. config.toml 配置详解与实操
4.1 最小可用配置长什么样
先给一个能跑通的最小配置,然后再逐项解释:
model = "deepseek-chat" model_provider = "deepseek" [model_providers.deepseek] name = "DeepSeek" base_url = "https://api.deepseek.com" env_key = "DEEPSEEK_API_KEY" wire_api = "chat"这个配置做了几件事:把默认模型设成deepseek-chat,定义了一个叫deepseek的 provider,指定了 base_url 和从哪个环境变量读 API Key,并且声明走chat协议(也就是 Chat Completions 格式)。
wire_api = "chat"这一行很关键。Codex 默认走的是responses协议,如果不改成chat,它会往/responses端点发请求,而 DeepSeek 那边没有这个端点,就会报cc switch local proxy failed while handling codex endpoint /responses这类错误。
4.2 模型名到底该填什么
DeepSeek 目前主流的模型名有两个:
deepseek-chat:通用对话模型,代码能力不错,适合大多数场景deepseek-reasoner:推理增强模型,适合复杂逻辑和数学题,但速度慢、价格高
Codex 的场景主要是代码读写和命令执行,用deepseek-chat就够了。如果你要做复杂的重构或者算法设计,可以切到deepseek-reasoner试试,但要注意它的响应时间会长很多,Codex 的交互体验会变差。
热词里出现的deepseek hermes、deepseek harness这些,看起来是 DeepSeek 生态里的其他工具或项目名,跟模型名不是一回事。配置model字段的时候,只填官方文档里列出的模型标识符,别填这些工具名,否则会报模型不存在的错误。
4.3 API Key 的两种传法
第一种是环境变量法,就是上面配置里的env_key = "DEEPSEEK_API_KEY"。然后在系统里设置这个环境变量:
# Linux / macOS export DEEPSEEK_API_KEY="sk-你的key" # Windows PowerShell $env:DEEPSEEK_API_KEY="sk-你的key" # Windows 永久设置(需要重启终端) setx DEEPSEEK_API_KEY "sk-你的key"第二种是直接写在配置里,但不太推荐,因为配置文件可能被同步或者分享出去,Key 容易泄露:
[model_providers.deepseek] name = "DeepSeek" base_url = "https://api.deepseek.com" api_key = "sk-你的key" wire_api = "chat"我个人的做法是用环境变量,而且把 export 那行写进 shell 的启动脚本里(.bashrc或.zshrc),这样每次开终端自动生效。Windows 上用setx设置后需要新开一个终端窗口才生效,老窗口读不到新变量,这个坑我踩过。
4.4 那些容易被忽略的配置项
热词里有一条codex is ignoring 1 unrecognized configuration setting,说的是mcp_servers.node_repl.type is ignored。这说明 Codex 对 MCP server 的配置字段有特定要求,type这个字段可能已经废弃或者改名了。
MCP(Model Context Protocol)是 Codex 用来扩展工具能力的机制。如果你不需要额外的 MCP server,最简单的做法是把相关配置全部删掉,避免干扰。如果确实需要,去查当前版本的文档,确认字段名和取值。
另一个容易出问题的是model字段的位置。它必须放在文件顶层,不能塞到某个 section 里面。热词里的请修复 config.toml:model报错,很可能就是model被放错了位置,或者值不是合法的字符串。
TOML 语法检查可以用在线工具,或者用 Python 快速验证:
import tomllib with open("config.toml", "rb") as f: config = tomllib.load(f) print(config)能正常打印出字典结构,说明语法没问题。报错的话,错误信息会指出具体行号。
5. 完整实操流程与验证
5.1 一步步走完配置流程
先把整个流程按顺序列出来,然后逐步展开:
- 安装 Codex CLI 并验证版本
- 获取 DeepSeek API Key 并用 curl 验证
- 创建或编辑
config.toml - 设置环境变量
- 启动 Codex 并测试对话
- 测试文件读写和命令执行能力
- 根据报错调整配置
第一步和第二步前面讲过了,这里从第三步开始。
编辑config.toml的时候,建议先备份原文件。如果你之前登录过 OpenAI 账号,配置里可能有官方相关的字段,直接覆盖可能导致登录状态丢失。备份命令:
cp ~/.codex/config.toml ~/.codex/config.toml.bak然后把前面给的最小配置写进去。保存后,在终端里运行:
codex如果配置正确,Codex 会启动并进入交互界面。输入一句简单的话,比如"帮我写一个 Python 的 hello world",看它能不能正常返回。如果返回了内容,说明链路通了。
5.2 验证请求到底发到了哪里
有时候配置看起来对,但请求还是发到了官方地址。怎么确认?开一个终端窗口,用抓包或者日志的方式看。
Codex 本身有 debug 模式,启动时加参数:
codex --debug或者在配置里开日志:
[log] level = "debug"日志里会打印每次请求的 URL 和状态码。如果看到请求发往api.openai.com,说明 provider 配置没生效,检查model_provider字段的值是否和[model_providers.xxx]里的xxx一致。这两个名字必须完全匹配,大小写敏感。
另一个验证方法是临时把base_url改成一个不存在的地址,比如https://api.deepseek.com/v1/invalid,然后启动 Codex。如果报连接错误,说明配置生效了;如果还能正常对话,说明请求根本没走这个 provider。
5.3 上下文长度超限怎么处理
热词里有一条api error: 400 this model's maximum context length is 1048576 tokens。这个报错说明请求的 token 数超过了模型的上限。DeepSeek 的上下文窗口虽然大,但也不是无限的,而且 Codex 在处理大项目的时候,会把很多文件内容塞进上下文,很容易超。
解决办法有几个:
- 在 Codex 里限制它读取的文件范围,别让它一次性加载整个项目
- 用
.codexignore文件排除不需要的文件(类似.gitignore的写法) - 在配置里设置
max_tokens或者上下文截断策略
Codex 的具体配置项名称可能随版本变化,建议查当前版本的文档。通用的思路是:减少单次请求携带的上下文量,把大任务拆成小任务。
5.4 401 和 400 报错的排查顺序
遇到报错别慌,按这个顺序查:
| 报错 | 可能原因 | 排查动作 |
|---|---|---|
| 401 unauthorized | Key 无效、Key 没传、地址错误 | 用 curl 单独测 Key;检查环境变量是否生效;检查 base_url |
| 400 context length | 上下文超限 | 减少加载的文件;拆分任务 |
| 400 organization disabled | 账号问题 | 检查 DeepSeek 账号状态和余额 |
| 模型不存在 | 模型名写错 | 对照官方文档确认模型标识符 |
| 配置被忽略 | 字段名错误或废弃 | 检查 TOML 字段拼写;查版本文档 |
401 是最常见的。我遇到过一次,Key 明明是对的,但一直报 401,最后发现是环境变量在启动 Codex 的那个终端里没生效。因为我是用 IDE 的内置终端启动的,那个终端没有加载.bashrc。解决办法是在 IDE 设置里把终端配置成登录 shell,或者直接在启动命令前加上环境变量。
6. 常见问题与避坑经验
6.1 配置文件改了但没生效
这是最高频的问题。原因通常有三个:
第一,改错了文件。系统里可能有多个.codex目录,比如用户目录下一个,项目目录下一个。Codex 读的是用户目录下的那个。确认路径的方法是启动 Codex 时加--debug,日志里会打印它加载的配置文件路径。
第二,TOML 语法错误导致整个文件被忽略。Codex 遇到语法错误时,可能不会报错退出,而是用默认配置启动。所以改完配置一定要用tomllib验证一遍。
第三,环境变量没生效。前面说过,setx设置的变量需要新开终端才生效。如果你在同一个终端里改完配置直接启动 Codex,读到的还是旧的环境变量。
6.2 代理层的那些坑
如果你用的是带代理的方案(比如某些转换工具),热词里的cc switch local proxy failed while handling codex endpoint /responses就是典型报错。这说明代理层收到了/responses请求,但它不知道怎么处理。
解决思路是让 Codex 直接走chat协议,别走responses。在配置里加wire_api = "chat"就是干这个的。如果代理工具本身支持 Responses 转换,那就要检查代理的配置,确认它监听的端口和 Codex 配置里的base_url一致。
代理方案的好处是可以做请求转换、日志记录、限流。坏处是多了一层,出问题的时候排查链路变长。我的建议是先用直连方案跑通,确认 DeepSeek 的 Key 和接口没问题,再考虑加代理。
6.3 模型切换的注意事项
从deepseek-chat切到deepseek-reasoner的时候,要注意响应格式的差异。推理模型会返回额外的 reasoning 字段,Codex 如果没适配,可能会解析失败或者显示异常。切换前先在 curl 里测一下返回结构,确认 Codex 能处理。
另外,不同模型的计费方式不一样。deepseek-reasoner的推理过程也会计入 token,成本比deepseek-chat高不少。如果你只是日常写代码,没必要用推理模型。
6.4 关于"破甲"和"无限制"的说明
热词里出现了deepseek破甲、deepseek破甲无限制词这类词。这里要明确一点:任何试图绕过模型安全机制的做法,都不在本文讨论范围内。我们配置 Codex 接 DeepSeek,目的是提升开发效率、降低调用成本,不是去突破什么限制。模型的安全策略是产品的一部分,正常使用就好,别折腾这些。
6.5 配置文件的版本兼容性
Codex 更新比较频繁,配置字段可能会变。热词里的codex is ignoring 1 unrecognized configuration setting就是版本不兼容的典型表现。升级 Codex 之后,如果发现某些配置不生效了,先去查更新日志,看字段是不是改名了或者废弃了。
一个实用的习惯是:把配置文件用 Git 管理起来,每次改动都提交。这样出问题的时候可以快速回滚,也能看到哪个版本改了什么。
7. 我实际跑通后的几点体会
整套配置跑下来,最深的体会是:问题基本都出在细节上,而不是方案本身。方案是清晰的——Codex 发请求,DeepSeek 接请求,中间用配置把两者对上。但实际执行的时候,一个空格、一个字段名、一个环境变量的作用域,都能让整个链路断掉。
我现在用的配置是这样的:
model = "deepseek-chat" model_provider = "deepseek" [model_providers.deepseek] name = "DeepSeek" base_url = "https://api.deepseek.com" env_key = "DEEPSEEK_API_KEY" wire_api = "chat"没有多余的东西。MCP server 的配置我全删了,因为暂时用不上,留着反而容易触发"配置被忽略"的警告。日志级别设成 info,出问题的时候临时调到 debug。
环境变量我写在.zshrc里,每次开终端自动加载。IDE 的内置终端我单独配置过,确保它加载登录 shell 的环境。这一步花了我不少时间,但配好之后一劳永逸。
最后分享一个小技巧:如果你不确定某个配置项该不该加,先别加。用最小配置跑通,确认基础链路没问题,再一项一项往上加。每加一项就测一次,出问题的时候能立刻定位到是哪一项导致的。这个"增量配置"的习惯,帮我省了很多排查时间。