免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Codex切换供应商后旧会话消失?从JSONL存储到配置排查全解析

Codex切换供应商后旧会话消失?从JSONL存储到配置排查全解析 最近好几个用 Codex 写代码的朋友碰到同一个怪问题用 cc-switch 这类供应商切换工具换了一个 API 供应商再打开 Codex 桌面版之前的会话全部“消失”了。有人说是不是供应商把账号数据清了有人怀疑 Codex 历史文件损坏还有人干脆重装了一遍工具。其实这里面九成的情况是“数据还在只是界面不给你看了”真正被删掉的情况反而少见。这篇文章就围绕“一切换 Codex 供应商旧会话为什么消失”这件事把会话文件存在哪、切换工具到底改了什么、怎么一步步排查、怎么恢复以及以后怎么避免一次说清楚。适合正在用 Codex CLI、Codex 桌面版或者 cc-switch 等切换工具的人参考。1. 先搞清楚 Codex 的会话到底存哪1.1 本地 JSONL 文件才是真正的“历史仓库”Codex 无论是命令行版还是桌面版历史会话都不是只存在服务端的。它会把每一段会话完整地写在本机磁盘上默认目录是~/.codex/sessions/。这个目录下通常按项目名再分一层子目录每个会话是一个 JSONL 文件文件名就是一串 UUID。JSONL 的意思是“每一行一个 JSON 对象”。会话文件的第一行通常保存会话的元信息包括provider、model、org、project、workspace这些身份字段。从第二行开始才是对话过程中产生的真实事件用户消息、助手回复、工具调用、执行结果、Token 统计等等。Codex 之所以能“恢复历史”靠的就是把这些事件按顺序重新加载把上下文窗口重建出来。所以这里有个很重要的结论切换 API 供应商这个动作理论上不应该导致任何历史会话物理消失。除非你换的同时有人把数据目录搬走了或者环境变量改掉了。明白这条之后再回头看“会话消失”这个问题思路就会清楚很多——你要找的其实是一个“为什么程序没去读旧目录”的问题而不是“为什么数据没了”的问题。1.2 GUI 的会话列表是“过滤后”的结果Codex 桌面版刚打开时并不是把sessions目录下所有 JSONL 文件一股脑全列出来。它要做一个过滤和归属判断。常见过滤维度有三个按当前项目的project_id或工作目录过滤按当前配置里的org_id过滤按某个会话是否能在当前model和 API 配置下继续对话来判断是否展示。也就是说你看到的会话列表本质上是“当前环境 当前身份 当前项目上下文”筛选之后的结果。只要切换供应商导致这些关键字段变化GUI 就会认为那些旧会话不属于当前上下文然后不显示出来。这就是为什么“供应商切换”和“旧会话消失”会被绑定在一起。并不是切换工具删了文件而是它把 Codex 的“视角”改了。会话文件还在原来的地方躺着只是 GUI 不再主动把它们读出来给你看。2. 切换供应商时哪些动作会把旧会话藏起来2.1 配置重写导致的路径漂移cc-switch 这类工具切换供应商时核心动作就是重写 Codex 的配置文件config.toml。它会把你选中的供应商对应的model、api_base_url、org_id、project_id写进配置替换掉之前的内容。问题往往出在细节上。我手头就有一个例子A 供应商的配置里project_id是proj_a_123B 供应商的配置里project_id是proj_b_456。切到 B 之后Codex 桌面版加载的是proj_b_456对应的项目会话而旧会话文件仍然躺在~/.codex/sessions/proj_a_123/下面。你说它删了吗没有。你说它“消失”了吗界面上确实是看不见了。还有一种更隐蔽的路径漂移是某个供应商配置里额外设置了CODEX_HOME环境变量或自定义数据目录。切换过去之后Codex 跑到新目录里去读历史旧目录里的 sessions 自然全部“消失”。我甚至见过有人把CODEX_HOME指到了一个完全没数据的路径打开界面空空如也排查半天才发现是环境变量的问题跟供应商本身没关系。2.2 cc-switch 本地转发层切换失败cc-switch 这类工具的实现方式一般会在本机起一个本地转发层。Codex 的api_base_url指向http://127.0.0.1:14540/v1之类的地址由这个转发进程把请求再送到当前选中的供应商 API。这样切换供应商时Codex 配置可以保持基本不变只要转发层换个目标就行。听起来很优雅但这个设计有一个明显弱点转发层必须一直在且状态正确。一旦切换过程中转发层没起来、端口被占用、或者目标服务地址没更新就会出问题。很多朋友遇到的cc switch local proxy failed while handling codex endpoint /responses就是这个场景的典型表现。具体来说会话列表可能还正常但当你点开一个旧会话想恢复历史时Codex 要先向后端发一个/responses请求来确认能否继续对话。这个请求先打到本地转发层转发层又没就绪结果就是界面一直转圈最终把整条会话标记为无法加载。这看起来就像“旧会话消失了”但文件其实好好的。你只需要重启转发层或切换工具让本地代理恢复正常会话列表很可能就回来了。2.3 模型或账号权限引发的恢复中断第三个坑是模型兼容性这个非常容易被误判成“会话被删”。比如你之前用官方 ChatGPT 账号下的gpt-5.6-sol这个预览型号写了一段很长的代码后来切到一个第三方聚合供应商对方只提供gpt-5-codex或者gpt-4.1这类模型。你打开旧会话Codex 读取到文件头部的model字段是gpt-5.6-sol于是它拿这个模型名去请求新的 API 网关。网关直接拒绝报类似the gpt-5.6-sol model is not supported when using codex with a chatgpt account的错误。此时 Codex 无法正常恢复这个会话GUI 就会把这条历史从“可继续会话”里剔除或者点了之后直接报错。从用户视角看就是“切换供应商之后旧会话没了”。从技术视角看会话文件还在只是元信息里的模型和当前供应商的模型清单不匹配导致加载链路中断。所以排查这个问题时一定不要只看界面要落到文件层面去验证。3. 三步排查法确认旧会话是真没了还是看不见3.1 第一步看文件系统判断数据是否物理存在我遇到这种问题第一件事永远不是去翻 GUI 设置而是打开终端检查会话文件。先跑这几条命令ls -la ~/.codex/sessions/ find ~/.codex -name *.jsonl -mtime -30 | head -20 echo $CODEX_HOME第一条看默认目录下有哪些会话子目录第二条找最近 30 天内的会话文件第三条确认当前环境变量有没有被改过。如果文件都在说明物理数据没有丢问题大概率出在加载和过滤逻辑上。如果默认目录是空的而且你确实设置过CODEX_HOME或自定义数据路径那就用下面的命令全局找一下find / -name *.jsonl -path *codex* 2/dev/null我有一次帮人排查会话全在/data/codex_home/sessions下面因为他的CODEX_HOME早就被某个配置脚本改到了这个路径而 GUI 默认读的却是~/.codex。另外如果想快速看一批会话分别属于哪个项目和模型可以用这个命令把每个 JSONL 的第一行解析出来for f in ~/.codex/sessions/*/*.jsonl; do head -1 $f | python3 -c import sys,json; djson.loads(sys.stdin.read()); print(d.get(project,), d.get(model,), d.get(org,)) 2/dev/null | sed s|^|$f | done不要嫌麻烦这一步能直接告诉你会话是按什么维度拆分的后面排查思路会清晰很多。3.2 第二步检查当前配置指向的存储和身份参数确认文件还在之后下一步看~/.codex/config.toml。重点看这几个字段model当前用的模型api_base_url请求发送到哪org_id组织标识project_id项目标识如果有session_path、history、data_dir之类的字段也要留意如果api_base_url指向的是127.0.0.1这样的本地地址说明 Codex 正在走本地转发层。这时候再去切换工具里看“当前选择的供应商”和“实际生效的供应商”是否一致。很多切换工具在界面上显示已经切了但配置文件因为权限或者格式问题没写进去实际启动的 Codex 还在用旧配置。还有一点容易被忽略有些工具不是改config.toml而是通过启动 Codex 时注入环境变量来改变配置。如果你从 GUI 里手动启动 Codex和通过切换工具启动 Codex两者读到的可能是完全不同的配置。这样就会出现“工具里显示切到了新供应商但 Codex 界面里还是旧供应商”的错位。3.3 第三步检查切换工具的本地转发层和日志如果前两步都没问题接下来的重点就是日志。cc-switch 这类工具一般都有日志窗口或者会把日志写入某个本地文件。出现local proxy failed时去日志里看它具体失败在哪一步是端口被占用、是目标地址连不上、还是证书或模型名校验没过。常用端口检查命令lsof -i :14540 netstat -ano | grep 14540如果看到端口被别的进程占着把那个进程找出来杀掉或者修改切换工具里的本地端口然后重启工具。如果看到的是类似cc gui 尚未配置 ai 供应商或未授权使用本地配置的提示多半是切换工具升级之后旧配置格式不兼容或者配置文件权限不对工具认为自己没有权限覆盖。这种情况直接去供应商管理里重新选一次供应商并保存让它重新生成配置一般就能恢复。4. 恢复旧会话的四种可行办法4.1 切回原供应商最快最稳的验证手段如果只是切换后看不到旧会话而且你还没动过任何数据目录最快的验证方式就是先切回原来的供应商。切回去之后Codex 加载的路径、模型、org、project 又都和旧会话的元信息对上了会话列表大概率会恢复。原理很简单旧会话没有丢只是之前的切换让当前上下文和旧会话不匹配匹配关系恢复自然就看到了。有个操作细节切回去之前先把当前配置备份一下。避免来回切换时把两边配置都覆盖乱。我一般会在切换前先这样做cp ~/.codex/config.toml ~/.codex/config.toml.bak这个动作成本极低但能省很多事。4.2 手工迁移 sessions 目录如果你的问题是数据目录被改了或者你确定旧会话文件在一个新环境不读取的路径下那就需要手工迁移。第一步先备份tar -czf codex_sessions_backup.tar.gz -C ~ .codex/sessions第二步找到旧会话文件find ~/.codex -name *.jsonl第三步确认目标目录的结构。一般sessions下第一层是项目名第二层是 JSONL 文件。把旧文件复制过去时也要保持这种结构否则 Codex 不知道按什么项目来归属这些会话。最省事的做法是直接复制整个目录cp -r ~/.codex/sessions ~/new_codex_home/sessions然后把CODEX_HOME环境变量指向新目录再启动 Codex。这里要提醒复制解决的是“路径不对”的问题不解决“模型不匹配”的问题。如果新供应商不支持旧会话里的模型迁移之后照样打不开。所以迁移完还要检查模型字段。4.3 修改 JSONL 元信息匹配新供应商当你确定旧会话文件都还在但新供应商不接受旧模型时可以小范围修改 JSONL 第一行的元信息把model字段替换成新供应商支持的模型名。先备份再用脚本批量处理import json, glob, shutil model_map { gpt-5.6-sol: gpt-5-codex, gpt-6-astra: gpt-5-codex, } for path in glob.glob($HOME/.codex/sessions/**/*.jsonl, recursiveTrue): with open(path, r, encodingutf-8) as f: lines f.readlines() if not lines: continue changed False try: header json.loads(lines[0]) except Exception: continue old_model header.get(model) if old_model in model_map: header[model] model_map[old_model] lines[0] json.dumps(header, ensure_asciiFalse) \n changed True if changed: shutil.copy2(path, path .bak) with open(path, w, encodingutf-8) as f: f.writelines(lines) print(updated, path)注意这里只改model键其他的不动。改完再用 Codex 打开会话至少列表能出现。需要理解的是这种处理只能让会话“可打开”上下文里如果大量引用了旧模型的行为实际对话质量可能有差异。但对于“找回列表”这个目标来说已经足够了。如果你的旧会话问题不是模型而是org_id或project_id不匹配思路类似只替换对应的键就行。不过强烈建议在改之前多做一步验证用head -1读几个文件看看元信息差异确认你要替换的字段到底是什么格式。4.4 日常备份与导出习惯恢复办法说到底都是补救最好的策略是不让问题发生。我现在已经养成习惯每次切换供应商之前先跑一次备份tar -czf ~/codex_sessions_$(date %Y%m%d_%H%M%S).tar.gz -C ~ .codex/sessions这个压缩包不会很大但一旦切换后出问题我能随时回到切换前的完整状态。如果你的 GUI 客户端有导出会话功能也可以用但从可靠性和完整性来看直接压缩目录是最好用的。另外一个有意思的点JSONL 文件本身就是文本格式意味着你可以用grep直接搜索历史内容比如查某段代码片段在哪些会话里出现过。这个技巧不针对“会话消失”但每次备份时用grep -l 某个报错信息 ~/.codex/sessions/**/*.jsonl找历史踩坑记录特别方便。5. 避免下次再踩同一个坑的配置规范5.1 统一或固定 org_id / project_id如果你需要在多个供应商之间来回切换最好的办法是尽量让不同供应商配置里的org_id和project_id保持一致只在api_base_url和model上做区分。为什么这样建议因为 Codex 的会话列表默认就是按项目维度过滤的。如果每个供应商的project_id都不同那么每次切换都会导致“当前项目”变化旧会话自然全部被隐藏。而如果你把project_id固定成同一个值切换供应商后会话仍然归属同一个“项目”GUI 过滤时不至于把历史全部藏起来。实际使用中我也明白有些供应商会强制绑定不同的org_id那这种情况下不要硬改而是采用另一个思路用不同的工作目录来区分场景而不是依赖项目标识。工作目录的变化更直观也好排查也方便迁移。5.2 把 Codex 配置文件纳入 Gitconfig.toml是一切配置的源头。我建议在~/.codex下初始化一个 Git 仓库把关键配置纳入版本管理。cd ~/.codex git init git add config.toml 2/dev/null || true git commit -m before switch supplier每次切换供应商前后都 commit 一次。切换后如果发现会话消失直接git diff就能看到config.toml到底被改了哪些字段。这一步往往能让你在五分钟内定位问题而不用靠猜。如果只是临时排查不想建仓库也可以直接用cp备份配置文件效果差不多只是没有历史版本对比那么方便。5.3 升级切换工具前先读 release notescc-switch 这类工具更新很频繁。新的供应商格式、新的配置模板、新的本地转发层实现都可能导致旧会话加载逻辑变化。我遇到过一种情况工具升级后它把 Codex 的api_base_url从“直接指向供应商”改成了“统一走本地代理”。这个改动本身没问题但旧版本生成的会话文件里记录的是直连时的上下文信息新版本 GUI 在恢复时校验身份不通过于是历史列表变空。所以升级前一定要看 release notes。升级之后去供应商管理里重新保存一次当前供应商配置让工具重新生成配置文件和本地转发地址这能避免大部分兼容性问题。如果升级后出现本地转发层频繁报错优先怀疑端口占用。常见处理方式lsof -i :14540 kill -9 pid然后重启工具让转发层重新绑定端口。6. 会话消失常见问题速查表平时排查多了我把常见场景整理成一个速查表遇到问题先对着找比闷头翻日志快得多。现象可能原因处理办法切换供应商后会话列表为空配置重写导致项目维度或数据目录变化检查CODEX_HOME、project_id切回原供应商验证点开旧会话一直转圈或提示重新连接本地转发层未就绪或崩溃查看 cc-switch 日志重启转发层或工具检查端口占用local proxy failed while handling codex endpoint /responses本地代理转发目标异常查看日志中实际错误重启工具换本地端口升级工具会话列表还在但点开就报模型不支持旧会话中的model字段新供应商不支持修改 JSONL 头部的model字段或改 Codex 配置里的模型提示“尚未配置 AI 供应商或未授权使用本地配置”切换工具未正确写配置或格式不兼容重新进入供应商管理保存一次目标供应商配置切换后界面加载的是另一个项目的历史GUI 按项目过滤导致旧会话不显示切换回原项目/工作目录或清理筛选条件这些问题的本质其实就一句话Codex 的会话历史是本地的并且强绑定当前项目上下文供应商切换只应该改变“请求发到哪里”不应该改变“数据放在哪里”。凡是违反这个原则的工具行为或配置写法都会让你觉得会话“消失”了。我自己在实际操作中的体会是遇到这种问题第一反应永远不要想着恢复数据而是先确认数据是不是真的没了。只要 JSONL 文件还在会话就还有救。我现在已经形成了固定流程切换前备份config.toml和 sessions 目录切换后发现异常先看环境变量和配置 diff最后才去看 GUI 和日志。最后再分享一个小技巧如果你希望切换供应商后旧会话依然能显示尽量把不同供应商配置成相同的org_id和project_id只在api_base_url和model上做区分。这样 GUI 的会话过滤不会因为项目上下文变化把历史藏起来切换供应商这件事对你来说就真的只是“换一个请求出口”而不是“换一个世界”。
返回列表