让 Codex CLI 使用任意模型:OpenRouter、DeepSeek、Ollama
Codex 只说 OpenAI Responses 协议。本文介绍如何借助本地网关把 Responses 转换为 Chat Completions,让 Codex 用上 OpenRouter、DeepSeek、Ollama 或任意 OpenAI 兼容模型,以及 ~/.codex/config.toml 里写入了什么。
Codex CLI 是 OpenAI 推出的终端编程智能体,速度快、可脚本化,擅长多步骤代码修改。但它围绕一种协议构建:OpenAI Responses API。问题在于,DeepSeek、OpenRouter、Ollama,以及 vLLM 这类自部署服务,最普遍提供的仍然是 Chat Completions 协议。
本文介绍如何用 AutoJev 让 Codex 跑在这些模型上。AutoJev 是一款免费、开源的桌面应用,在本机运行一个本地网关 http://127.0.0.1:9527/v1,并负责协议之间的转换。读完本文,你将:
- 一键把 Codex 接入本地网关;
- 在 Codex 里看到一份包含所有已选模型和路由的模型目录;
- 让 OpenRouter、DeepSeek 和本机 Ollama 模型并存可用;
- 搞清楚哪些 Responses 功能可以转换、哪些不行。
协议之间的鸿沟
Codex 发出的是 POST /v1/responses 请求。Responses 对输入项、工具定义(包括自定义工具)、工具调用输出和流式事件都有自己的结构;而 Chat Completions 把同样的对话表示成一组带 tool_calls 的消息,流式增量的格式也不同。
只支持 Chat Completions 的模型无法直接回应 Responses 请求。必须有人在入口把请求翻译过去,在出口把流式事件翻译回来——同时保证工具调用 ID 稳定,因为 Codex 要靠它把工具结果对应到发起调用的那一步。
这正是 AutoJev 的工作:
Codex ──Responses──▶ AutoJev(127.0.0.1:9527/v1)──▶ Chat Completions 上游
──▶ Responses 上游(原生)
──▶ Anthropic Messages 上游如果模型的上游本来就支持 Responses,请求会原样透传;否则 AutoJev 会完成转换,调用服务商的 /v1/chat/completions(或 /v1/messages),再把响应转换回 Responses 事件。
第一步:安装 AutoJev 并添加服务商
从下载页下载 AutoJev(macOS、Windows x64、Linux x64),打开后网关会在 9527 端口启动。
在「服务商」中添加你需要的服务商,预设会自动填好地址:
| 预设 | 接口地址 |
|---|---|
| OpenRouter | https://openrouter.ai/api |
| DeepSeek | https://api.deepseek.com |
| Ollama | http://127.0.0.1:11434 |
| OpenAI | https://api.openai.com/v1 |
其他服务——Kimi(Moonshot)、GLM(智谱)、Qwen(DashScope)、SiliconFlow、vLLM、LM Studio——可以用「OpenAI 兼容」或「Anthropic 兼容」填入对应地址。本机 Ollama 一般不需要密钥。添加后逐个点击测试。
如果你的服务商配置已经在 CC Switch 或 Termany 里,直接导入即可。AutoJev 会读取 ~/.cc-switch/cc-switch.db 或 ~/.termany/termany.db,并按接口地址去重。
第二步:添加模型,选对 API 类型
在「模型」中为每个模型添加一条记录。最关键的字段是 API 类型,它描述的是上游,而不是 Codex:
| 服务商 | 模型 ID 示例 | API 类型 |
|---|---|---|
| OpenRouter | qwen/qwen3-coder-flash | chat_completions |
| OpenRouter | anthropic/claude-sonnet-4 | chat_completions |
| DeepSeek | deepseek-chat | chat_completions |
| Ollama | ollama list 中显示的模型名 | chat_completions |
| OpenAI | 支持 Responses 的模型 | responses |
常见误区是:因为 Codex 用 Responses,就把所有模型都设成 responses。千万别这样——AutoJev 需要知道上游的真实格式,才能正确转换。
再填上每百万 token 的输入、输出和缓存价格,让「用量」页面能估算费用。然后跑一次测速:AutoJev 会对每个模型发送三次简短的流式请求,记录首字延迟和每秒输出 token 数。定时测速默认开启(每 30 分钟一次),为速度优先路由提供最新数据。
第三步:创建路由(可选,但推荐)
Codex 可以直接连接单个模型,但用路由的好处是:以后换模型不用再动 Codex 的配置。在「路由」中可以这样建:
fast:智能选择,偏好设为速度优先。AutoJev 根据近期测速数据在本地选择,不调用 Jev。cheap:智能选择,偏好设为成本优先。AutoJev 选出满足能力要求、费用最低的候选。打开「优先使用本地模型」,符合条件时会优先用 Ollama。quality:智能选择,偏好设为质量优先。由 OpenRouter 上的 Jev 决策模型来选,只发送路由元数据,不发送对话内容。
路由对智能体显示为 autojev/fast、autojev/cheap、autojev/quality;单个模型显示为 <服务商 ID>/<模型 ID>,例如 deepseek/deepseek-chat。
第四步:接入 Codex
打开「智能体」,AutoJev 会在 ~/.codex/config.toml 检测到 Codex。选择一个或多个模型和路由,指定默认项,点击「连接」。AutoJev 会先备份原文件,然后写入:
model = "autojev/fast"
model_provider = "autojev"
model_catalog_json = "/Users/you/.codex/autojev-models.json"
web_search = "disabled"
[model_providers.autojev]
name = "AutoJev"
base_url = "http://127.0.0.1:9527/v1"
wire_api = "responses"
[model_providers.autojev.http_headers]
x-autojev-agent = "codex"逐行说明:
model:Codex 启动时使用的默认模型或路由。model_provider = "autojev"与[model_providers.autojev]:让 Codex 以 Responses 格式把请求发往本地网关。x-autojev-agent = "codex":给请求打上标签,「日志」和「用量」就能按智能体拆分。web_search = "disabled":关闭 Codex 的托管联网搜索,因为托管工具无法转换给 Chat Completions 或 Messages 模型。model_catalog_json:指向 AutoJev 写入的另一个文件~/.codex/autojev-models.json。
这份目录列出了你选中的所有模型和路由,方便在 Codex 内部切换。精简后的单条记录如下:
{
"models": [
{
"slug": "autojev/fast",
"display_name": "Fast",
"description": "AutoJev · fast",
"visibility": "list",
"supported_in_api": true,
"input_modalities": ["text", "image"],
"supports_search_tool": false,
"apply_patch_tool_type": "freeform"
}
]
}config.toml 中的其他设置都会保留。如果 Codex 正在运行,重启后试一下:
codex "给注册接口加上输入校验,并补一个测试"在 AutoJev 的「日志」里可以看到:智能体、路由 ID、实际响应的模型和服务商、token 数、首字节与总耗时、预估费用;详情页还会列出每一次上游尝试。
能转换的部分
AutoJev 支持 Responses、Chat Completions、Anthropic Messages 三者之间全部六个方向的转换。对“Codex + Chat Completions 模型”来说,关键能力都已覆盖:
- 系统指令和完整的对话历史;
- 函数工具、工具选择、工具调用与工具输出,调用 ID 保持稳定;
- Responses 自定义工具:转换为只有一个字符串参数
input的函数,返回时再解码回自定义工具输入。上游函数接口不会强制执行语法约束; - 流式文本和流式工具参数,包括被网络分片切开的 UTF-8 字符;
- 图片(URL 或 base64);
- Responses 与 Chat Completions 之间的结构化输出格式;
- token 用量和符合协议格式的错误。上游流中断或格式异常时会报告为错误,而不是当作成功完成。
不能转换的部分
有些 Responses 功能在 Chat Completions 里没有对应物,AutoJev 会明确拒绝,而不是假装支持:
previous_response_id和conversation:跨协议转换要求每次请求都携带完整历史;- 托管工具,例如联网搜索——这就是写入
web_search = "disabled"的原因; - 音频和文件内容、带命名空间的工具定义、多候选输出;
- 推理状态:各家专有的 thinking 块、加密推理和签名会被丢弃,推理控制参数也不会转换。如果某个模型要求后续工具结果必须附带它原有的私有推理状态,那么跨协议时可能无法完整跑完智能体循环,这种场景请使用其原生 API。
另外,一条通用原则:转换无法让模型凭空获得工具调用、视觉、推理能力或更大的上下文。给 Codex 选模型时,请优先考虑工具调用能力强的模型。
用本机 Ollama 模型跑 Codex
本地模型适合处理敏感代码,或者干脆不想调用付费 API 的场景:
- 启动 Ollama 并拉取一个编程模型;
- 在 AutoJev 中启用 Ollama 服务商(
http://127.0.0.1:11434),添加该模型,API 类型选chat_completions; - 让 Codex 直接连接
ollama/<模型名>,或者把它加入一条打开了「优先使用本地模型」的路由,再放一个云端模型作为第二候选。
用路由的方式还有故障转移兜底:如果本地服务没启动,或者在开始输出之前返回 5xx,AutoJev 会尝试下一个候选。默认最多尝试 4 次、冷却 30 秒。已经开始输出的流不会重放,所以 Codex 不会把同一个工具操作执行两遍。
用 OpenRouter 或 DeepSeek 跑 Codex
步骤完全相同,只是换了服务商。两个建议:
- 用路由做对比。 把一个 OpenRouter 模型和 DeepSeek 放进同一条负载均衡路由,权重相同。新会话会分配到两边,会话保持让每个会话始终使用同一个模型。之后在「用量」里按模型对比结果。
- 关注费用。 为每个模型设置价格,并在路由中选择一个「成本基准」,就能估算相对参照模型节省了多少。粗略规划时可以借助 LLM 费用计算器。
断开连接
在「智能体」中对 Codex 点击「断开」,AutoJev 会恢复备份的 config.toml,并保留你之后做的、与其字段不冲突的修改;如果模型目录文件原本不存在,会被删除。「停止并恢复配置」会对所有已接入的智能体做同样的事,托盘菜单里的「Quit AutoJev (restore agents)」也是如此。
排错
Codex 提示某功能不受支持。 检查请求是否用到了 previous_response_id、托管工具或文件内容。可以把该会话切换到 API 类型为 responses 的模型,或者开一个新会话。
请求发到了意料之外的服务商。 在「日志」里打开这条请求,详情会显示路由、每一次上游尝试,以及智能选择路由的决策原因。
速度优先一直在用负载均衡。 速度路由需要近期测速数据——最近 30 分钟内最多 5 个样本。手动测速一次,或保持定时测速开启。
网关已暂停。 暂停期间请求会返回 HTTP 404 和 gateway_paused,在 AutoJev 中恢复服务即可。
小结
Codex 只说 Responses,但你的模型不必如此。AutoJev 只在 ~/.codex/config.toml 中写入一小段可还原的配置,再在 ~/.codex/autojev-models.json 生成模型目录,实时把 Responses 转换为 Chat Completions 或 Messages,并由路由决定每次请求交给哪个模型。
延伸阅读: