Codex CLI 通过 ~/.codex/config.toml 里的 [model_providers.<id>] 段接入任意 OpenAI 兼容端点;最容易翻车的字段是 wire_api——它决定请求发到 /responses 还是 /chat/completions,选错了表现是 404 或 400,而不是优雅的报错。 判据只有一条:上游是不是原生 Responses API? 官方 OpenAI 用 wire_api = "responses",绝大多数第三方兼容网关和本地模型(DeepSeek、阿里云百炼、OpenRouter、Ollama、new-api 之类)只提供 /chat/completions,必须写 wire_api = "chat"。下面给一份可直接用的配置模板和实测过的排错顺序。
上面这段就是全文的结论块,可以直接拿走。下面是装、配、排错。

Codex CLI 是什么?和 Claude Code 有什么区别?
Codex CLI 是 OpenAI 出的终端编程智能体,和 Claude Code 属于同一类工具:读你的仓库、改文件、跑命令。 定位差别在配置模型上——Claude Code 主要靠环境变量(ANTHROPIC_BASE_URL 等)指向自定义后端,Codex CLI 则用一份 TOML 描述多个 provider 和多个 profile,可以在同一台机器上"切换着用"。
| 维度 | Codex CLI | Claude Code |
|---|---|---|
| 配置载体 | ~/.codex/config.toml |
~/.claude/settings.json + 环境变量 |
| 多后端 | 原生支持多 provider + profile 切换 | 靠环境变量切,通常一套一套改 |
| 项目级配置 | 支持 .codex/config.toml(需信任项目) |
支持项目级 CLAUDE.md |
| 接第三方 | 自定义 provider,注意 wire_api |
只要兼容 Anthropic API 即可 |
两个都接第三方模型的完整做法我都跑过,Claude Code 那篇在这里。如果你已经在用 new-api 这类聚合网关,那 Codex CLI 接它一个端点就能把上游模型全用上。
Codex CLI 怎么装、怎么跑?
# 1) 装(需要 Node 18+)
$ npm install -g @openai/codex
$ codex --version
# 2) 登录官方账号(用官方模型时)
$ codex login
# 3) 直接在项目目录里跑
$ cd ~/projects/my-app
$ codex # 交互式
$ codex exec "把 src/utils.py 里的重复代码合并成一个函数" # 非交互
装完先跑一次 codex --version 并记下版本号——Codex CLI 迭代很快,TOML 的字段名在版本之间有过调整,遇到不认识的键时先对照 codex --help 和当前版本的官方配置文档。

config.toml 怎么写?一份可直接用的模板
结论:把官方 provider 留作默认,第三方按业务分组写进 model_providers,再用 profiles 做"一套配置一个场景"。 下面这份模板在 ~/.codex/config.toml:
# ---- 默认走官方 ----
model = "gpt-5"
model_provider = "openai"
# ---- 第三方 provider:注意 wire_api ----
[model_providers.deepseek]
name = "DeepSeek"
base_url = "https://api.deepseek.com/v1"
env_key = "DEEPSEEK_API_KEY"
wire_api = "chat" # 兼容端点走 /chat/completions
request_max_retries = 4
[model_providers.dashscope]
name = "阿里云百炼(OpenAI 兼容)"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
env_key = "DASHSCOPE_API_KEY"
wire_api = "chat"
[model_providers.local_ollama]
name = "本地 Ollama"
base_url = "http://localhost:11434/v1"
wire_api = "chat" # 本地模型不需要 key
[model_providers.mynewapi]
name = "自建聚合网关"
base_url = "https://api.example.com/v1"
env_key = "NEWAPI_KEY"
wire_api = "chat"
# ---- profile:一套配置一个场景 ----
[profiles.deepseek]
model = "deepseek-chat"
model_provider = "deepseek"
[profiles.local]
model = "qwen2.5-coder:14b"
model_provider = "local_ollama"
# ---- 沙箱与审批 ----
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = false
把 key 交给环境变量(env_key 指的是变量名,不是密钥本身):
$ echo 'export DEEPSEEK_API_KEY="sk-你的key"' >> ~/.bashrc && source ~/.bashrc
然后按 profile 启动:
$ codex --profile deepseek
$ codex --profile local exec "解释一下这个函数的算法复杂度"
两个硬性限制:model_provider 和 openai_base_url 这类键不允许被项目级 .codex/config.toml 覆盖——这是官方故意的设计,防止你 clone 的仓库把请求悄悄导向别处。所以想换后端,只能在用户级配置或命令行里改。

wire_api 到底该填哪个?
结论:先看上游文档的端点路径,再决定取值。 判据表:
| 上游情况 | wire_api | 原因 |
|---|---|---|
| OpenAI 官方 API | responses |
官方原生支持 Responses API |
| 兼容网关标注 "OpenAI 兼容" | chat |
通常只实现 /v1/chat/completions |
| DeepSeek / 百炼 / OpenRouter | chat |
走 chat completions |
| 本地 Ollama / LM Studio | chat |
兼容层只提供 chat completions |
| 自建 new-api / one-api 类网关 | chat |
透传 chat completions |
写错的症状:填 responses 打一个只有 chat 端点的上游,返回 404(路径不存在)或者 400(请求体结构不符);反过来填 chat 打官方 Responses,工具调用会退化,复杂任务的工具链容易断。排错时不要猜,直接打一次上游端点看路径存不存在:
# 判据 1:上游是否提供 /responses
$ curl -s -o /dev/null -w "%{http_code}\n" \
-X POST https://api.deepseek.com/v1/responses \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" -d '{}'
# 404 → 只有 chat 端点,wire_api 用 "chat"
# 判据 2:判据 1 之外,直接看 chat 端点是否通
$ curl -s https://api.deepseek.com/v1/chat/completions \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"hi"}]}' | head -c 300

怎么验证真的通了?
结论:别只看"能对话",要验证工具调用——那是编程智能体的核心能力。 一个能对话但工具调用退化的配置,用起来会在改文件时突然卡死。
# 1) 确认当前生效的 provider
$ codex --profile deepseek exec "只回答你正在使用哪个模型名"
# 2) 验证工具调用:让它读一个文件
$ codex --profile deepseek exec "读一下 README.md,用一句话总结" --cd ~/projects/my-app
# 3) 验证写权限(沙箱配 workspace-write 时)
$ codex --profile deepseek exec "在项目根目录建一个 hello.txt,内容写 ok"
$ cat ~/projects/my-app/hello.txt
三条都过,说明这个后端不只是"能聊天",而是能完成"读—改—跑"的完整循环。

三个真会踩的坑
- provider id 撞了保留名:
openai、ollama、lmstudio这三个 id 是内置保留的,自定义 provider 用它们会加载失败。想接 Ollama 用local_ollama这种名字,别叫ollama。 - 项目级配置需要"信任"才生效:
.codex/config.toml在项目里必须先把该目录标记为信任才会被加载。现象是"我在项目里配了 profile 却不生效"——查一下信任状态,别在 TOML 语法上找半天。 - 沙箱把网络关了,工具调用看着像卡住:模板里
network_access = false是默认安全姿势,但脚本里要pip install或者curl时会静默失败。要么临时把sandbox_mode调成danger-full-access(只在你信任的目录用),要么显式开[sandbox_workspace_write] network_access = true。
Codex CLI 常见问题(2026)
Q:没有 OpenAI 账号,能只用第三方模型吗?
A:能。把 model + model_provider 指向自定义 provider、key 用环境变量提供即可,不需要走 codex login。本地的 Ollama 连 key 都不需要。
Q:一份 config.toml 能配多少个 provider?
A:没有实际限制。典型做法是官方一个、国内一个、本地一个,用 profile 切换。别把 key 直接写进 TOML,用 env_key 指环境变量名。
Q:wire_api = "responses" 到底什么时候用?
A:只在确认上游原生实现了 Responses API 时用。判断方法就是上面那条 curl -o /dev/null -w "%{http_code}" 打 /responses,返回 404 就不要用。
Q:接了第三方模型,工具调用不稳定怎么办?
A:优先换 wire_api = "chat" 再测;仍不稳就换模型——小模型的 function calling 支持差异很大。想统一入口和模型路由,可以在前面放一层 new-api 聚合。
Q:和 Claude Code 哪个更值得用?
A:两个都留着不冲突。Codex CLI 的多 provider + profile 更适合"同一台机器上到处切后端";想要 本地模型 那种离线兜底,两边都能接。
Q:base_url 结尾要不要带 /v1?
要。绝大多数兼容网关的完整前缀是 https://host/v1,Codex CLI 不会帮你补。少了 /v1 最常见的症状是 404;多了斜杠(/v1/)在某些网关上也会出问题。照着上游文档一字不差地抄,别自己改。
Q:换 provider 后历史会话还能用吗?
上下文本身在客户端,换 provider 不丢;但不同模型的工具调用格式不一致,跨模型续接同一任务偶发中断。稳妥做法是换 provider 时开新会话。
一句总结
Codex CLI 接第三方模型,90% 的失败都出在 wire_api 这一个字段上:先确认上游的端点路径,再定取值,然后用"读文件 + 写文件 + 跑命令"三条验证工具调用。配置这件事真正的成本不在写,而在于知道该验哪三条。