让 ChatGPT 桌面应用里的 Codex 使用第三方模型
让 ChatGPT 桌面应用里的 Codex 使用第三方模型
适用:ChatGPT 桌面应用(内置 Codex,本文验证版本 codex-cli 0.153.4 / 应用 26.1023)。
范围:只覆盖 Codex 部分。ChatGPT "work" 等功能依赖 OpenAI 账号,本文没有找到不登录的办法,也不提供绕过方法。
1. 前提:你的网关要满足什么
| 要求 | 说明 |
|---|---|
支持 POST /v1/responses |
Codex 走 Responses 协议。只有 /chat/completions 的网关不行,需要先用 LiteLLM 等转换 |
有 GET /v1/models |
用来列出模型,格式见第 4 节 |
| 能访问 | 本文示例网关在 http://localhost:3425/v1,请换成你自己的 |
2. 需要改哪些文件
只需要动 一个必改文件 + 一个可选文件,都在 ~/.codex/ 下(Windows 为 %USERPROFILE%\.codex\):
| 文件 | 是否必改 | 作用 |
|---|---|---|
~/.codex/config.toml |
必改 | 声明第三方 provider、默认模型、模型目录来源 |
~/.codex/vendor_models.json |
二选一 | 本地模型目录(方式 B 用) |
转换服务(catalog_server.py) |
二选一 | 实时把网关的 /models 转成 Codex 格式(方式 A 用) |
不要手改 ~/.codex/models_cache.json(Codex 会覆盖它),也不要动 auth.json。改之前先备份 config.toml。
3. config.toml 要新增的配置
# ① 顶层键:必须放在文件里第一个 [表头] 之前
model_provider = "localproxy"
model = "vendor/model-a" # 必须是目录里存在的 slug,否则选择器里没有模型
# 原来的 service_tier = "priority" 是 OpenAI 专属,建议注释掉
# ② provider 定义
[model_providers.localproxy]
name = "Local Proxy"
base_url = "http://localhost:3425/v1" # 不要带 /responses
wire_api = "responses"
requires_openai_auth = false
# 需要 key 时二选一:
# env_key = "MY_VENDOR_API_KEY" # 桌面应用读不到终端 export,macOS 需 launchctl setenv
# experimental_bearer_token = "sk-xxx" # 明文,勿提交 git
# ③ 模型目录来源:方式 A 或 B 二选一
# 方式 A:实时读取(经转换服务,见第 5 节)
model_catalog_url = "http://127.0.0.1:3426/v1/models"
# 方式 B:本地文件(顶层键,放在第一个 [表头] 之前)
# model_catalog_json = "/Users/你/.codex/vendor_models.json"
[features]
api_key_model_discovery = true # 方式 A 需要
注意:
model_provider、model、model_catalog_json是顶层键;项目目录里的config.toml会忽略 provider 配置,只认用户级文件。- 如果文件里已有
[features],把这一行并进去,不要重复表头。 - 有其他软件(例如 magpie)也会改这个文件,改完后建议复查,特别是顶层
model行有没有被删。
4. /models 的格式
4.1 网关返回的(OpenAI 风格,大多数网关如此)
{
"data": [
{
"id": "vendor/model-a",
"display_name": "Vendor Model A",
"context_window": 128000,
"modalities": {
"input": [
"text",
"image"
]
},
"native_endpoints": [
"/v1/responses"
],
"supported_reasoning_levels": [
{
"effort": "low"
},
{
"effort": "medium"
}
],
"object": "model",
"type": "model"
}
],
"object": "list"
}
4.2 Codex 要求的(顶层必须是 models,不是 data)
直接把 4.1 给 Codex 会解码失败,日志里会看到:
failed to decode models response,选择器里只有 effort 没有模型。
{
"models": [
{
"slug": "vendor/model-a",
"display_name": "Vendor Model A",
"description": "Third-party model",
"default_reasoning_level": "medium",
"supported_reasoning_levels": [
{
"effort": "low",
"description": "low"
},
{
"effort": "medium",
"description": "medium"
}
],
"shell_type": "unified_exec",
"visibility": "list",
"supported_in_api": true,
"priority": 1,
"model_messages": {
"instructions_template": "<从 ~/.codex/models_cache.json 里任意一个模型条目复制,约 22KB>"
},
"include_skills_usage_instructions": false,
"include_plugin_usage_instructions": false,
"include_apps_usage_instructions": false,
"default_reasoning_summary": "none",
"support_verbosity": true,
"default_verbosity": "low",
"apply_patch_tool_type": "freeform",
"web_search_tool_type": "text_and_image",
"truncation_policy": {
"mode": "tokens",
"limit": 10000
},
"supports_image_detail_original": true,
"context_window": 128000,
"max_context_window": 128000,
"effective_context_window_percent": 95,
"experimental_supported_tools": [
"send_user_message_async",
"clock"
],
"input_modalities": [
"text",
"image"
],
"supports_search_tool": true,
"supports_experimental_context": false,
"use_responses_lite": true,
"supports_reasoning_effort_updates": true,
"node_repl_auto_review_required": true,
"node_repl_disabled": false,
"tool_mode": "code_mode_only",
"multi_agent_version": "v2",
"multi_agent_reasoning_effort": "xhigh"
}
]
}
要点(均为本机实测):
- 顶层键是
models,每项用slug标识模型。 - 缺
support_verbosity会报错;缺base_instructions且缺model_messages.instructions_template也会报错。 - 其余字段建议完整保留。最省事的做法是:从
~/.codex/models_cache.json复制一个现成条目当模板,只改slug、display_name、description、推理档位、上下文窗口、输入模态。 instructions_template约 22KB/模型。每个模型的model_messages里只留它即可(全留 28 个模型约 1.8MB,Codex 会中途断开)。- 字段映射:
id→slug,supported_reasoning_levels→同名(effort加description),context_window→context_window/max_context_window,modalities.input→input_modalities。
5. 两种方式怎么落地
方式 A:实时读取(推荐,模型变化自动同步)
Codex 的 provider 支持 model_catalog_url,但它要的是 4.2 的格式。网关不是这个格式时,起一个小转换服务:
catalog_server.py:监听127.0.0.1:3426,每次请求拉取网关/v1/models并转成 4.2 的格式。sync_models.py:转换逻辑(被上面的服务引用)。vendor_models.example.json:模板,内容取自本机models_cache.json的一条。
MODELS_URL=http://localhost:3425/v1/models python3 -I catalog_server.py
需要 key 时加 API_KEY=...。想开机自启,把它做成 macOS launchd 服务。服务不在时,Codex 回退到内置目录,选择器里就没有你的模型。
过滤规则:只保留 native_endpoints 含 /v1/responses 的模型,以及 auto/* 路由组。只有 chat/completions 或 messages 的模型 Codex 调不了。
方式 B:本地文件(无需常驻服务)
python3 -I sync_models.py ~/.codex/vendor_models.json
然后在 config.toml 顶层加 model_catalog_json。缺点:模型变化后要重新运行。
6. 验证(不用启动应用)
CODEX=/Applications/ChatGPT.app/Contents/Resources/codex-cli/CodexCLI.app/Contents/MacOS/codex
$CODEX debug models | python3 -c "import sys,json;print(len(json.load(sys.stdin)['models']))"
- 输出大于 0,且包含你的
model→ 目录读取成功。 - 输出 0 → 看转换服务是否在跑;看
~/.codex/logs_2.sqlite里codex_models_manager的 ERROR。 - 再完全退出并重启 ChatGPT 应用,在选择器里选模型并发一条消息。
7. 常见问题
| 现象 | 原因 / 处理 |
|---|---|
| 选完 effort 后没有模型 | 目录解码失败(格式见 4.2),或 model 不在目录里 |
| 报缺字段 | 按报错补字段,用 model_catalog_json 测试,报错最明确 |
| 目录有,发消息报错 | 网关不支持 Responses 协议,或该模型不接受(先试原生支持 /v1/responses 的模型) |
| 配置被改回去 | 其他软件会改 config.toml,复查顶层 model / model_provider |
| 仍弹 OpenAI 登录 | 已知 issue 中的行为,可尝试加 experimental_bearer_token = "任意值" 并保持 requires_openai_auth = false;未验证 |
| 回滚 | 用备份覆盖 config.toml,或删掉 model_provider/model 与 provider 表 |
8. 已验证 / 未验证
- 已验证:
model_catalog_url与model_catalog_json都能被codex debug models解析;响应体顶层键必须是models;上面提到的必填字段。 - 未验证:ChatGPT 应用内真实对话是否走通;
api_key_model_discovery是否是必需开关;Windows/Linux 路径。

浙公网安备 33010602011771号