1. 为什么一个 config.yaml 能让人改三遍
Codex CLI 是 OpenAI 推出的命令行编码代理,能在终端里直接读写项目文件、跑命令、改代码。它和 Claude Code 定位类似,但配置走的是~/.codex/config.yaml这套 YAML 体系。问题就出在这:Codex CLI 的配置项命名和大多数同类工具不一样,provider字段的枚举值、api_key的读取优先级,官方文档写得非常含糊,导致很多人第一次接入非官方端点时会反复填错。
这篇聚焦两个具体坑:一是provider到底能填什么,二是api_key从环境变量读还是从配置文件读、谁优先。我会给出可复制的最小config.yaml、逐项覆盖顺序的验证命令,以及把 endpoint 改到 TaoToken 后的连通性检查动作。适合刚装好 Codex CLI 就跑出 401 的人、想把 Codex 接到聚合网关的人、以及从 Claude Code 或 Cursor 切过来以为改个 base_url 就完事的人。
先说清楚一个前提:Codex CLI 要求 Node.js ≥ 22。装之前先确认版本,不然后面所有配置都白搭。
node --version # 需要 v22.0.0 或更高版本不够就用 nvm 升级:
nvm install 22 && nvm use 22装 Codex CLI 本身一行命令:
npm install -g @openai/codex装完确认在 PATH 里:
codex --help如果报Cannot find module '@openai/codex',大概率是 npm 全局目录没加进 PATH,macOS 用 nvm 的人经常遇到。这一步过了,才轮到 config.yaml 登场。
2. provider 字段的枚举值到底有哪些
打开或新建~/.codex/config.yaml,你会看到一个providers段。我一开始想当然写了个openai-compatible,因为 Cline 和 Cherry Studio 都有这个选项。结果 Codex CLI 直接忽略了整个配置块,fallback 到默认行为,然后因为没读到我配的 baseURL 就去请求api.openai.com,网络不通,报了个:
APIConnectionError: Connection error.这个报错完全没提示是 provider 写错了,我排查了快一个小时才定位到。Codex CLI 的 provider 枚举值目前只认官方名称——openai、anthropic、gemini、ollama等,没有openai-compatible或azure这样的独立枚举值。想接第三方端点(包括 Azure OpenAI、各类聚合网关),provider 还是写openai,然后在对应 provider 块里覆盖baseURL指向你的实际端点。
providers: openai: baseURL: https://your-gateway-endpoint/v1 envKey: OPENAI_API_KEY这里有个细节:baseURL不要带末尾斜杠,也不要自己再拼/chat/completions,Codex 内部会处理路径。我试过在末尾加/,结果请求路径变成双斜杠,某些网关会直接 404。
Azure OpenAI 的情况更绕。Azure 的端点格式通常是https://<resource-name>.openai.azure.com/openai/deployments/<deployment-name>,而且model字段要填你在 Azure 门户里创建的部署名,不是 OpenAI 的原始 model ID(比如部署名可能是my-gpt4o而不是gpt-4o)。如果觉得这套映射麻烦,走支持 Azure 的聚合网关再转 OpenAI 兼容格式会省事一些。
provider 字段的对照关系可以这样记:
| 你以为的写法 | 实际正确写法 |
|---|---|
接第三方端点provider: openai-compatible | 不存在,用provider: openai+ 自定义baseURL |
接 Azureprovider: azure | 不存在,用provider: openai+ 自定义baseURL指向 Azure 端点 |
| baseURL 末尾加斜杠 | 不加,Codex 自己拼路径 |
3. api_key 优先级:环境变量和配置文件谁说了算
这个坑更隐蔽。config.yaml里有个envKey字段,它的意思是"去读哪个环境变量的值作为 API Key",而不是"在这里填 Key 的值"。很多人第一次看到envKey会以为是把 Key 写进去,结果填了个sk-xxx进去,Codex 拿这个字符串当环境变量名去找,当然找不到。
优先级实测结果(建议用codex --version确认你当前版本,不同版本行为可能有差异):
- 环境变量(
envKey指定的那个变量名)——最高优先级 - 配置文件里的
apiKey字段(如果你硬写了的话)——次优先级 - 都没有 → 报错
OPENAI_API_KEY is not set
我踩的坑是:在.zshrc里 export 了一个过期的 Key,然后在config.yaml里又写了一个新 Key。结果 Codex 读的是环境变量里那个过期的,直接 401:
AuthenticationError: 401 Incorrect API key provided我改了三遍 config.yaml 都没用,最后才反应过来是环境变量在"抢"优先级。建议二选一,别混用。要么只用环境变量(团队协作时每个人自己管自己的 Key),要么只写 config.yaml(个人机器图方便)。混用迟早出事。
下面是一个可以直接抄的最小可用模板,改两个值就能跑:
model: o4-mini approvalMode: auto-edit providers: openai: baseURL: https://taotoken.net/api/v1 envKey: OPENAI_API_KEY字段名说明:配置文件中推荐使用 camelCase 的approvalMode,命令行参数对应--approval-mode。baseURL这里填的是 TaoToken 的 API 地址,末尾不带斜杠,也不带/chat/completions。
然后终端里 export Key:
export OPENAI_API_KEY='your-key-here'如果你想把 Key 写进配置文件而不是环境变量,可以这样:
providers: openai: baseURL: https://taotoken.net/api/v1 apiKey: sk-your-key-here但记住,只要环境变量里存在OPENAI_API_KEY,它就会覆盖配置文件里的apiKey。所以要么把.zshrc里的旧 export 删掉,要么就别在配置文件里写apiKey。
4. 验证请求:从 401 到跑通的全过程
配置写完之后,验证分三步走。第一步确认 Codex 读到了哪个配置:
codex --version第二步,用一个最简单的任务测试连通性:
codex 'list all files in current directory'看到它开始分析文件列表就说明通了。如果这一步报 401,先跑:
echo $OPENAI_API_KEY看看终端实际读到的值是不是你以为的那个。.zshrc里如果有旧 Key,它的优先级高于 config.yaml 里写的值。另外注意复制 Key 时前后别多空格,这个肉眼看不出来但会 401。
第三步,如果 401 排除了,但报APIConnectionError或local proxy failed,那就是 baseURL 的问题。检查两件事:baseURL 是不是写成了https://taotoken.net/api/v1(注意/v1后缀),以及末尾有没有多余的斜杠。TaoToken 的 API 地址是https://taotoken.net/api,在 Codex 里需要补上/v1后缀,因为 Codex 内部会在这个 baseURL 后面拼/chat/completions。
跑通之后,你可以用codex 'add type hints to all functions in utils.py'这种真实任务验证模型能力。如果返回的是正常的代码修改建议,说明整条链路——Codex CLI → config.yaml → TaoToken 端点 → 模型——全部打通。
对于需要长期跑编码任务的场景,可以考虑用 Coding Plan 来管理调用配额,避免每次手动 export Key。如果只是想先验证模型对话效果,可以直接在模型对话页面测试。
5. 常见报错排查:401、local proxy failed、reading choices
报错一:401 Incorrect API key provided
这是最高频的。排查顺序:先echo $OPENAI_API_KEY确认环境变量值,再检查 config.yaml 里有没有同时写了apiKey和envKey。如果两个都写了,环境变量赢。如果环境变量是空的,Codex 会去读 config.yaml 里的apiKey。两个都没有,报OPENAI_API_KEY is not set。
报错二:APIConnectionError: Connection error或local proxy failed
这个通常不是 Key 的问题,是 baseURL 写错了。检查 provider 字段是不是写成了openai-compatible或azure——这两个枚举值不存在,Codex 会忽略整个 providers 块,fallback 到默认的api.openai.com。正确写法是provider: openai+ 自定义baseURL。另外确认 baseURL 带了/v1后缀,且末尾没有斜杠。
报错三:Error reading choices或返回体解析失败
这个报错说明请求发出去了,但返回的 JSON 结构不符合 Codex 的预期。常见原因是 baseURL 指向的端点不是 OpenAI 兼容格式,或者模型名填错了。Codex 期望的返回体里有choices数组,如果你的网关返回的是别的结构,就会报这个。检查model字段填的是不是网关支持的模型 ID。
报错四:OAuth 相关报错
如果你之前用codex auth走过 OAuth 登录流程,后来又改了 config.yaml 走 API Key,可能会遇到 OAuth token 和 API Key 冲突的情况。解决方法是清掉~/.codex/下的 auth 缓存文件,重新用 API Key 方式配置。
报错五:config.yaml 改了但不生效
先确认路径对不对——必须是~/.codex/config.yaml,不是~/.codex/config.yml(后缀别写错)。然后检查 YAML 缩进,providers下面的字段要缩进两格。我有一次就是baseURL没缩进,整个 providers 块被当成无效内容跳过了,也不报错。
6. 把 endpoint 改到 TaoToken 后的连通性检查
如果你决定把 Codex CLI 的 endpoint 改到 TaoToken,完整的配置三件套是:Base URL、Key、Model ID。Base URL 填https://taotoken.net/api/v1,Key 从 API Keys 页面获取,Model ID 填你实际要用的模型名。
完整的 config.yaml 长这样:
model: o4-mini approvalMode: auto-edit providers: openai: baseURL: https://taotoken.net/api/v1 envKey: OPENAI_API_KEY然后 export Key:
export OPENAI_API_KEY='your-taotoken-key'连通性检查分两步。第一步,用 curl 直接测端点:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"o4-mini","messages":[{"role":"user","content":"ping"}]}'如果返回体里有choices数组,说明端点和 Key 都没问题。第二步,跑 Codex CLI 的真实任务:
codex 'list all files in current directory'两步都通了,就说明 Codex CLI → TaoToken → 模型这条链路完全打通。后续如果要换模型,只改model字段就行,baseURL 和 Key 不用动。
对于团队协作场景,建议把 config.yaml 模板提交到团队 wiki,envKey统一用OPENAI_API_KEY,每个人自己管自己的环境变量。这样 config.yaml 可以 git 共享,Key 不会泄露。CI/CD 自动化场景加--approval-mode full-auto走非交互模式,Linux 环境建议套 Docker 做沙箱隔离。
codex --approval-mode full-auto \ 'add type hints to all functions in utils.py'整个配置就两个核心认知:provider 没有openai-compatible或azure这样的独立枚举值,想接第三方端点就用openai+ 自定义baseURL;api_key 环境变量优先级高于配置文件,混用迟早出事。搞清楚这两点,五分钟就能跑通。我现在的日常工作流是 Codex CLI 处理快速任务(加类型注解、写测试、重命名变量这种),复杂的多文件重构还是交给 Claude Code,两个工具配合着用比单押一个效率高不少。