CC Switch 中 OpenAI Official 与第三方 API 双向切换:Codex 历史记录与请求兼容操作手册
CC Switch 中 OpenAI Official 与第三方 API 双向切换:Codex 历史记录与请求兼容操作手册
适用场景:Windows 本地 Codex Desktop / ChatGPT Desktop,通过 CC Switch 在 OpenAI Official 与第三方 API、中转站或自定义 provider 之间切换。
本文基于 2026-07-30 的一次真实修复和后续协议兼容故障整理。最终成功同步 SQLite 190 条、JSONL 190 个,共恢复并统一 193 条本地会话;数据库完整性检查结果为
ok。随后又定位了第三方 API 返回非官方响应对象 ID,导致旧任务切回官方 API 后无法继续对话的问题。
1. 先说结论
切换 API 后侧栏历史突然消失,很多时候不是消息被删除,而是同一批本地会话被不同的 model_provider 分成了几组。
但“侧栏历史可见”和“同一任务能被另一家 API 继续执行”是两个不同问题:
- 历史可见性问题:由 SQLite、JSONL 中的
model_provider和rollout_path决定,使用 Provider Sync 处理。 - 请求/响应协议连续性问题:第三方虽然接受 Codex 的 Responses 请求,却可能返回不符合 OpenAI Responses 约定的对象 ID,导致切回官方 API 后续聊失败。
本次真实错误为:
1 | [ApiIdParam] [input[9].id] [invalid_id_prefix] |
这不是历史消失,也不是 Provider Sync 失败,而是第三方写进本地 JSONL 的 reasoning 对象使用了通用 item_ ID。官方 API 恢复该任务时要求 reasoning ID 以 rs_ 开头,因此拒绝整个请求。
要做到双向切换时历史记录始终可见,有两条路线:
长期推荐:两个 CC Switch profile 使用同一个稳定 provider ID。
- OpenAI Official 使用 Codex 内置
openai。 - 第三方 API 也使用内置
openai,仅通过顶层openai_base_url改变接口地址。 - 只有第三方接口和认证方式兼容 Codex 内置 OpenAI provider,且 CC Switch 不会覆盖该配置时才能采用。
- OpenAI Official 使用 Codex 内置
通用稳妥:CC Switch 切换后,把本地历史同步到当前真实 provider。
- 如果官方 profile 是
openai,就同步到openai。 - 如果第三方 profile 是
custom、ccswitch、code-switch或其他 ID,就同步到那个实际 ID。 - 每次必须先 DryRun、确认警告为 0,再正式同步。
- 如果官方 profile 是
本文重点推荐第二条处理历史可见性;第三方响应兼容性则优先使用 CC Switch 的“需要本地路由映射”,让 CC Switch 把第三方 Chat Completions 响应重建成 Codex 所需的 Responses 形态。
2. 现象
常见表现包括:
- CC Switch 切到 OpenAI Official 后,项目名称还在,但历史任务全部或大部分消失。
- 从官方切回第三方 API 后,只能看到第三方期间创建的任务。
- 切换后只显示刚刚新建的一条会话。
sessions下的 JSONL 文件仍然存在,但 Codex 侧栏不显示。- 不同登录方式看到的是两套历史记录。
- SQLite 中能查到会话,但当前界面仍为空。
这些症状不能直接证明数据已经丢失。应先检查 provider 元数据和 rollout_path,不要删除数据库或覆盖会话目录。
3. 根因:provider 元数据分裂
本次故障中,SQLite 曾同时出现:
1 | cc-switch-official |
切回 OpenAI Official 后,当前配置没有显式写 model_provider。根据 Codex 官方配置参考,model_provider 的默认值是内置的 openai,新任务也确实以 openai 写入数据库。
旧任务仍标记为 custom 或 cc-switch-official,因此侧栏看起来像“历史记录丢了”。
本地会话至少要关注两处 provider 元数据:
1 | state_<版本>.sqlite |
只修改 SQLite、不修改 JSONL,或只修改 JSONL、不修改 SQLite,都可能造成后续重建、索引和显示不一致。
此外还要检查:
1 | threads.rollout_path |
它必须指向当前 CODEX_HOME 下实际存在的 JSONL。如果数据库还指向迁移前的旧磁盘或旧用户目录,即使 provider 正确,修复工具也应停止操作。
说明:Codex 官方文档公开说明了
model_provider、openai_base_url、CODEX_HOME等配置含义,但没有把 Desktop 侧栏的全部内部过滤和 SQLite schema 承诺为稳定公共接口。本文关于历史可见性的结论来自本机实测以及社区项目的交叉验证,未来 Codex 版本可能调整内部结构。
3.1 第二类根因:第三方响应对象 ID 不兼容
本机出错的第三方 profile 已经配置:
1 | wire_api = "responses" |
也就是说,Codex 发出的请求本来就是 Responses API。问题不在“请求格式没有设置成官方格式”,而在第三方服务返回的 Responses 对象不规范。
本机正常官方响应和异常第三方响应的对比如下:
| 对象类型 | 官方响应中观察到的 ID 前缀 | 异常第三方返回 |
|---|---|---|
| reasoning | rs_ |
item_ |
| assistant message | msg_ |
item_ |
| function call | fc_ |
item_ |
| custom tool call | ctc_ |
item_ |
本次共在 5 个会话文件中发现 141 个通用 item_ 响应对象,其中包括:
1 | reasoning 46 |
其中 46 个异常 reasoning 均没有可用于安全重建的 encrypted_content。因此不能简单把 item_ 批量替换成 rs_:ID 可能还被后续工具调用、响应引用或服务端状态关联,机械改前缀只能改变表象,不能证明语义关系仍然正确。
3.2 为什么 Provider Sync 不能修复这个错误
Provider Sync 只负责同步:
1 | threads.model_provider |
它不会、也不应该改写每条 response_item 的正文和对象 ID。因此:
- Provider Sync 可以让 193 条历史重新出现在侧栏。
- Provider Sync 不能让已经污染的旧任务重新满足官方 Responses API 的对象约束。
- 这两类修复必须分别处理,不能把“历史可见”误认为“跨服务继续请求一定兼容”。
4. 准备工作
4.1 使用正确的 CODEX_HOME
Codex 官方文档说明,本地状态保存在 CODEX_HOME,默认是:
1 | %USERPROFILE%\.codex |
但 CC Switch、多实例配置或自定义安装可能使用其他目录。必须确认当前 Codex 实例真正读取的是哪一个目录。
【本地 Windows PowerShell】
目的:查看当前进程和用户级环境变量是否设置了 CODEX_HOME。
执行目录:任意目录。
1 | [Environment]::GetEnvironmentVariable("CODEX_HOME", "Process") |
正常输出:
- 输出一个实际存在的
.codex目录;或 - 两行均为空,此时通常使用
%USERPROFILE%\.codex。
停止条件:
- 找到了多个
.codex,但无法确认当前实例使用哪个。 config.toml、sessions和state_<版本>.sqlite分别位于不同目录。
不要凭印象选择旧目录。操作错 CODEX_HOME 可能得到“工具提示成功,但 Codex 仍看不到历史”的假象。
4.2 下载实际使用的修复工具
本文实测使用:
- pipabcc/codex-history-session-recovery
- 实测版本:
v1.2.0 - 许可证:MIT License
它会同步:
- SQLite 的
threads.model_provider sessions和archived_sessions中有效 JSONL 首行的 provider
并提供:
- Codex 进程检测
- DryRun
- SQLite 完整性检查
- WAL/SHM 一致性快照
- JSONL 首行备份
- 事务写入
- 失败回滚
- 完成报告
从 GitHub 下载发布包后完整解压,确保以下文件在同一目录:
1 | provider-sync.bat |
不要只下载来历不明的 BAT,也不要直接在压缩包预览窗口运行。
4.3 完全退出 Codex
正确顺序是:
1 | 完全退出 Codex/ChatGPT Desktop |
Provider Sync 会在检测到以下相关进程时拒绝写入:
1 | ChatGPT |
这是正常安全保护。不要为了省一步而强行绕过。
5. 每次切换后的标准操作
以下示例使用占位路径:
1 | <CODEX_HOME> |
执行前必须替换成自己机器上的绝对路径,例如:
1 | D:\CodexData\.codex |
第一步:在 CC Switch 中启用目标 profile
目标可以是:
- OpenAI Official
- 第三方 API
- 中转站
- 自定义 provider
启用后不要只看 CC Switch 卡片名称。卡片名称是给人看的,Codex 实际使用的是生成到 config.toml 中的 provider ID。
第二步:读取真实 provider
【本地 Windows PowerShell】
目的:读取切换后 Codex 实际配置中的 model_provider。
执行目录:任意目录。
1 | Select-String ` |
可能输出:
1 | model_provider = "custom" |
或:
1 | model_provider = "cc-switch-official" |
也可能没有任何输出。
判断规则:
- 有输出:使用引号中的实际值。
- 没有输出:Codex 官方默认 provider 是
openai。
不要根据“OpenAI Official”按钮名称猜成 cc-switch-official。本次真实修复中,旧说明曾按历史行为推测为 cc-switch-official,但切换后的实际配置没有显式 provider,新任务写入值是 openai。最终同步目标必须以当前配置为准。
第三步:DryRun
假设上一步确认目标为 openai。
【本地 Windows PowerShell】
目的:只读盘点需要修改的数据库记录和 JSONL,不写入数据、不创建持久备份。
执行目录:<工具目录>。
1 | Set-Location -LiteralPath "<工具目录>" |
正常输出应同时满足:
1 | RESULT|success|0|db=<数量>|jsonl=<数量>|backup= |
停止条件:
RESULT|failed- 警告/跳过项不为 0
- JSONL 缺失
rollout_path越出会话目录- SQLite 完整性检查失败
- 盘点期间数据库、WAL 或 SHM 发生变化
- 修改数量明显不符合预期
如果目标 provider 是 custom,只替换:
1 | -TargetProvider custom |
其他参数保持不变。
第四步:正式同步
DryRun 成功且警告为 0 后,去掉 -DryRun。
【本地 Windows PowerShell】
目的:创建安全备份后,把 SQLite 与 JSONL provider 同步到当前目标值。
执行目录:<工具目录>。
1 | Set-Location -LiteralPath "<工具目录>" |
正常输出:
1 | RESULT|success|0|db=<修改数>|jsonl=<修改数>|backup=<备份目录> |
备份默认位于:
1 | <CODEX_HOME>\backups\provider-sync-bat\<时间戳-随机标识>\ |
停止条件:
- 退出码不是 0。
- 显示回滚未完成。
- 完整性检查失败。
- 工具提示不要启动 Codex。
第五步:重新启动 Codex 并验证
正式同步成功后再启动 Codex。
检查:
- 原有项目与任务是否重新出现。
- 活动会话和归档会话是否完整。
- 新建任务是否仍能正常保存。
- 再次重启后历史是否仍存在。
6. 双向切换速查表
| 切换方向 | 当前 config.toml 的实际 provider |
Provider Sync 目标 |
|---|---|---|
| 第三方 → OpenAI Official | 没有显式值,使用默认值 | openai |
| 第三方 → OpenAI Official | model_provider = "cc-switch-official" |
cc-switch-official |
| OpenAI Official → 第三方 | model_provider = "custom" |
custom |
| OpenAI Official → 第三方 | model_provider = "ccswitch" |
ccswitch |
| 任意方向 | 其他实际 ID | 原样使用该 ID |
最短流程:
1 | 退出 Codex |
7. 第三方响应格式兼容:使用 CC Switch 本地路由
7.1 适用判断
先编辑第三方 profile,检查其真实上游能力:
- 上游原生、完整支持 OpenAI Responses API,并能返回规范对象 ID:可直接使用,不必转换。
- 上游只支持 Chat Completions,或者虽然声称支持 Responses、实测却生成通用
item_ID:开启“需要本地路由映射”。
本次异常 profile 的 wire_api = "responses" 已经正确,单纯重复设置 wire_api 无法解决问题。需要改变的是上游处理路径:让 CC Switch 接收 Codex 的 Responses 请求,转换成第三方 Chat Completions 请求,再把第三方响应重建成 Responses 形态。
数据流如下:
1 | Codex Responses 请求 |
7.2 CC Switch 3.18 设置
以出错的第三方 profile 为例:
编辑第三方 provider。
开启“需要本地路由映射”(Needs Local Routing)。
上游格式设为 OpenAI Chat Completions;对应的内部元数据通常是:
1
2
3{
"apiFormat": "openai_chat"
}在模型映射中确认 Codex 模型名能够映射到第三方真实模型名。
打开“设置 → 路由 → 本地路由”:
- 开启本地路由主开关;
- 在“路由已启用”中开启 Codex;
- 默认地址保持
127.0.0.1:15721,除非端口冲突。
如果需要频繁往返官方和第三方,再打开“设置 → Codex 应用增强 → 切换第三方供应商时保留官方认证”。
切换 provider 后完全重启 Codex,使模型目录和 provider 配置重新加载。
不要在 CC Switch 和 Codex 正在运行时直接编辑 cc-switch.db。界面设置会同时维护 provider 元数据、本地路由状态、live 配置和备份;只改 SQLite 的 meta.apiFormat 并不能自动启动代理或完成 Codex 接管。
7.3 双向切换顺序
OpenAI Official → 第三方 API
1 | 确认第三方支持 /v1/chat/completions |
第三方 API → OpenAI Official
1 | 完全退出 Codex |
CC Switch 官方指南不建议把 OpenAI Official 流量经由第三方本地路由接管。切回官方前先关闭 Codex 路由,既能减少配置混淆,也避免把官方认证流量错误送入第三方代理路径。
7.4 上线前验证
不要直接在重要旧任务中测试。先创建一个不含敏感信息的新任务,至少验证:
- CC Switch 请求日志出现目标第三方 provider。
- 实际上游路径是
/v1/chat/completions,而不是继续直通/v1/responses。 - 流式输出、reasoning、普通文本和工具调用都能完成。
- 完全重启 Codex 后,该测试任务仍能继续。
- 切回 OpenAI Official 后,该任务不会再出现
invalid_id_prefix。
如果第三方不支持 /v1/chat/completions,常见结果是 404;此时应关闭本地路由映射,联系服务商修复 Responses 实现,或更换真正兼容的上游。CC Switch 转换器本身也可能存在特定 payload 的兼容边界,因此测试通过只能证明当前模型和工具组合可用,不能视为对所有请求的永久保证。
8. 真正“无需每次同步”的长期方案
Codex 官方配置参考说明:
model_provider默认值是openai。openai是内置保留 provider ID,不能通过[model_providers.openai]覆盖。openai_base_url可以修改内置openaiprovider 的 Base URL。
因此,在兼容条件满足时,可以让官方和第三方 profile 都使用同一个 provider ID:
OpenAI Official profile
1 | model_provider = "openai" |
不要保留第三方的:
1 | openai_base_url = "https://第三方地址/v1" |
第三方 API profile
1 | model_provider = "openai" |
不要创建:
1 | [model_providers.openai] |
因为 openai 是内置保留 ID。
这个方案的适用条件
必须同时满足:
- 第三方接口兼容 Codex 当前使用的 OpenAI Responses API。
- 第三方认证可以由内置
openaiprovider 正常完成。 - CC Switch profile 支持持久保存这组配置。
- 每次点击“启用”后,CC Switch 不会把 provider ID 改回
custom等其他值。 - 官方 profile 会移除第三方
openai_base_url,不会把官方请求继续发往第三方地址。
如果任一条件不满足,继续使用“切换后 Provider Sync”方案。不要为了统一 provider 而复制 OAuth token、API key 或 auth.json。
9. 本次真实案例
9.1 切换后的状态
切到 OpenAI Official 后:
1 | config.toml: |
DryRun 前数据库分布:
1 | cc-switch-official = 4 |
DryRun:
1 | 目标 provider:openai |
正式同步:
1 | 数据库更新:190 |
同步后:
1 | openai 活动会话:162 |
历史记录重新出现在 Codex 侧栏。
9.2 这次踩过的坑
坑 1:根据 CC Switch 卡片名猜 provider
旧记录曾经出现 cc-switch-official,但这一次 OpenAI Official 实际使用的是默认 openai。
经验:
1 | 始终读取当前 config.toml;没有显式值时按官方默认 openai 处理。 |
坑 2:自动化脚本只识别英文警告字段
第一次自动任务中,Provider Sync 的 DryRun 已成功,且显示:
1 | 警告/跳过项:0 |
但外层脚本只查找英文 warnings=0,因此安全停止,没有进行正式写入。
这不是数据修复失败,而是外层自动化误判。
经验:
- 人工操作应同时检查 DryRun 摘要和
RESULT|success|0。 - 自动化不要只匹配本地化界面文本。
- 正式阶段优先解析工具输出的结构化
CONFIRM|...|warnings=0和RESULT|...。 - 保护条件不满足时应停止,不能“默认继续”。
坑 3:Codex 运行时修改数据库
SQLite 可能同时存在 WAL/SHM,运行中复制或覆盖主数据库会产生不一致风险。
经验:
1 | 完全退出 Codex 后再盘点、备份和写入。 |
坑 4:只改 SQLite
如果 JSONL 首行仍保留旧 provider,后续索引重建可能再次出现分裂。
经验:
1 | SQLite 和 JSONL provider 必须一起同步。 |
坑 5:操作了旧 CODEX_HOME
多实例或迁盘后,旧目录可能仍然存在,看起来结构也完整。
经验:
1 | 先确认当前实例使用的 CODEX_HOME,再执行任何修复。 |
10. 常见错误处理
10.1 检测到 Codex 相关进程
完全退出:
- Codex Desktop
- ChatGPT Desktop
- Codex CLI
- Codex++
- 系统托盘中的相关进程
不要使用强制参数绕过。
10.2 rollout path 越出会话目录
说明 SQLite 的 threads.rollout_path 可能仍指向旧磁盘、旧用户目录或不存在的 JSONL。
处理原则:
- 不要立即同步 provider。
- 按线程 ID 在当前
CODEX_HOME中定位真实 JSONL。 - 先备份数据库。
- 只修复能够一一对应的路径。
- 再运行 Provider Sync DryRun。
本文所用仓库提供了 repair-rollout-paths.ps1,但它涉及具体的新旧路径映射。必须先运行诊断模式,确认所有映射都可解释后才允许 -Apply。
10.3 DryRun 成功但侧栏仍为空
依次检查:
- 是否操作了当前实例真正使用的
CODEX_HOME。 - 正式同步是否真的执行,而不是只完成 DryRun。
- 当前配置 provider 是否与 SQLite、JSONL 一致。
- 会话是否全部被标记为归档。
rollout_path是否真实存在。- 是否完全重启了 Codex。
如果 JSONL 存在但 SQLite 或索引缺失,可考虑:
- aisspire/codexSessionManager
- 许可证:MIT License
- 用途:预览、备份恢复、修复 SQLite/JSONL/index 不一致
不要直接删除 state_<版本>.sqlite 期待 Codex 自动重建。
10.4 CC Switch 再次覆盖 config.toml
这是 profile 重新生成配置的结果。
可选处理:
- 在 CC Switch profile 中修正生成配置。
- 如果当前版本无法固定 provider ID,则每次切换后运行 Provider Sync。
- 不要只手改当前
config.toml,因为下次点击“启用”可能再次被覆盖。
11. 发布日志或截图前的脱敏清单
不要公开:
auth.json- API key
- Bearer token
- OAuth token
- 未脱敏的
config.toml - 完整 SQLite 数据库
- WAL/SHM
- JSONL 会话文件
- Provider Sync 备份包
- 含用户名、项目路径、线程 ID 的完整日志
- CC Switch profile 数据库或导出包
可以公开:
- provider 计数
- 修改数量
integrity_check = ok- 已脱敏的 Base URL 示例
- 不含密钥的命令模板
- 工具版本与公开仓库链接
12. 开源项目、引用与许可证说明
12.1 CC Switch
- 项目:farion1231/cc-switch
- 用途:管理并切换 Codex、Claude Code 等工具的 provider/profile;在本地路由模式下完成 Responses 与 Chat Completions 的协议转换。
- 许可证:MIT License。
- 官方仓库声明的官方网站:ccswitch.io
- 本文使用的功能说明:添加 Codex 供应商
- 本地路由实战:在 Codex 中使用 DeepSeek
- 功能来源:CC Switch v3.16.0 Release Notes
CC Switch 文档说明,“需要本地路由映射”会把 Codex 的 Responses 请求转换为上游 Chat Completions,并把流式响应、reasoning 和工具调用重建成 Responses 形态。本文只讨论该开源项目的配置切换与协议转换行为,不为任何第三方 API 或中转服务背书。
12.2 Codex 历史记录 / 会话恢复工具
- 项目:pipabcc/codex-history-session-recovery
- 用途:同步 SQLite 和 JSONL 中的
model_provider。 - 许可证:MIT License。
- 本文实际使用版本:
v1.2.0。 - 本次 190 条 SQLite、190 个 JSONL 的正式同步由该工具完成。
如复制、修改或再发布源码,应保留项目 MIT License 中要求保留的版权和许可声明。
12.3 Codex Session Merge Fix
- 项目:yanyan1115/codex-session-merge-fix
- 用途:提供
model_provider分裂、统一使用openai和openai_base_url的早期排查思路。 - 本文引用范围:问题定位思路和配置方向,不直接复制其修复脚本。
- 许可证说明:截至本文整理时,本地检出的仓库根目录未发现独立
LICENSE文件。公开可读不等于可以任意复制、修改和再发布源码;如需复用代码,应先向原作者确认授权。
12.4 Codex Session Manager
- 项目:aisspire/codexSessionManager
- 用途:会话查看、备份恢复、数据库修复和路径修复。
- 许可证:MIT License。
- 本文定位:Provider Sync 无法解决 JSONL 缺失、SQLite/index 不一致时的可选辅助工具。
13. OpenAI 官方资料
-
model_provider默认值为openai。openai、ollama、lmstudio是内置保留 provider ID。openai_base_url用于覆盖内置openaiprovider 的 Base URL。
-
- Codex 状态保存在
CODEX_HOME。 - 如果只是让内置 OpenAI provider 指向代理,应使用顶层
openai_base_url,不要定义[model_providers.openai]。
- Codex 状态保存在
-
- 本地 Codex 支持使用 ChatGPT 登录,也支持 API key 登录。
- 认证方式与 provider 元数据是相关但不同的层面,不要为了统一历史而混用或复制认证文件。
-
- Responses 输出由带类型和 ID 的 item 组成。
- 本文的
rs_、msg_、fc_、ctc_对照来自本机官方响应实测;不要把本地观察到的所有内部前缀当作永远不变的公共兼容承诺。
14. 免责声明
- 本文不是 OpenAI、CC Switch 或任何第三方 API 服务的官方文档。
- Provider Sync 和其他会话修复工具均为社区项目。
- 本文只能恢复“本地文件仍存在、但因元数据或索引不一致而不可见”的会话,不能从云端找回已经删除或从未保存到本机的数据。
- Codex 内部 SQLite schema 和 Desktop 过滤行为可能随版本变化。操作前必须备份,并优先使用带 DryRun、完整性检查和回滚机制的工具。
- 第三方 API 存在隐私、稳定性、计费、模型真实性和合规风险,请自行评估,不要上传敏感项目与凭据。
15. 一句话总结
1 | 历史是否显示:统一 SQLite 与 JSONL 的 model_provider,并保证 rollout_path 有效。 |




