CC Switch 切到第三方,Codex 仍显示官方账号是不是串账了
有一类问题在 CC Switch 的使用者里出现得特别频繁,而且两种方向都有:一种是明明已经把 Codex 切到了第三方供应商,客户端里显示的却还是官方账号,于是开始怀疑请求到底记在谁头上;另一种恰好相反,切回一张绑定了 ChatGPT 账号的官方卡之后,请求被代理层挡住,返回一句「当前 Codex 会话未加载所选 ChatGPT 账号,请重启 Codex 或新建会话后重试」。
这两件事看着像同一个「账号错乱」,实际上一个是文档明确写过的误解,另一个是软件为了不让账单串到别的账号上而主动设的闸。分不清是哪一种,就会朝错的方向折腾。
这篇文章的依据
下面所有说法都来自 cc-switch 仓库 v3.20.1 这一份快照(对应 commit 3217f725),核对日 2026-08-31。我们只静态读了 docs/ 下的用户手册与路由指南、docs/release-notes/ 里的发布说明,以及 src/、src-tauri/ 的源码;没有编译过,没有运行过,也没有安装过这个桌面应用。因此这篇不会出现任何关于界面长什么样、点哪里、响应多快的描述——凡是需要装起来才知道的事,这里一概不写。
方向一:客户端显示的账号,本来就不代表计费方
docs/guides/codex-official-auth-preservation-guide-zh.md 这篇指南(第 3 行声明适用 v3.16.1 及以上版本)专门有一节「需要理解的副作用」,标题就叫「Codex 里显示的账号始终是官方账号」。指南给出的解释是:Codex 客户端读的是 ~/.codex/auth.json 里的官方登录态,所以它会继续显示官方账号信息;但这不代表模型请求还走官方,实际流量以 CC Switch 当前的 Codex 供应商与 config.toml 为准。
紧接着的一节标题更直白——不要用 Codex 账号信息判断计费方。指南写的是:切到第三方之后,客户端里仍显示官方账号,但模型请求走第三方 API,计费、限额、错误码和数据策略都应按第三方供应商理解。
这个现象的根在两个文件的职责分工上(同一篇指南第 117 至 141 行):
~/.codex/auth.json保存官方登录缓存,桌面端识别账号、远程操作、官方插件都靠它;~/.codex/config.toml保存当前模型供应商、base URL、模型目录、provider-scoped token 这些运行配置。
所谓「保住官方登录态」的开关,做的事情是走一条 config-only 的写入路径:auth.json 原样保留官方登录,第三方的模型、endpoint、model_provider 与 experimental_bearer_token 全部写进 config.toml。既然登录缓存没动,客户端当然还显示官方账号——它显示的是「我用哪个身份登录过」,不是「这次请求发去了哪里」。
怎么确认自己就是这一种
判定动作很具体,不需要猜:
- 打开
~/.codex/config.toml,看顶层的model_provider指向谁,以及对应的[model_providers.*]段里的base_url和wire_api写的是什么。这里写的地址,才是请求真正发去的地方。 - 对照
~/.codex/auth.json是否仍是官方登录态。如果config.toml指向第三方而auth.json仍是官方,那就是指南描述的预期形态,不是故障。 - Windows 上这两个文件在用户主目录下的
.codex目录里,路径写法与 macOS / Linux 的~/.codex/对应;两边文件名一致。
方向二:绑定账号的官方卡,被代理层挡了
第二种现象完全是另一条链路。v3.20.0 的发布说明把「Codex 多 ChatGPT 账号、逐卡绑定」列为本版三条主线之一,同时明确写了一句:接管下的请求会校验账号一致性,绝不静默把账单记到另一个账号头上。
这句话在代码里的落点是 src-tauri/src/proxy/forwarder.rs 第 57 到 98 行的 validate_codex_official_authorization。它的形状是一个 match,四路分支:
- 请求里没有
Authorization头,或者头是空串 → 直接返回AuthError,文案是「Codex 官方登录不可用,请先在 Codex 中完成 ChatGPT 登录」。 - 拿到的
Authorization里含代理占位符 → 文案是「已切换到 OpenAI 官方供应商,请重启 Codex 或新建会话以加载官方登录配置」。占位符还在,说明客户端进程没有重载配置。 - 其余情况下,先从这张卡的
meta里取managed_account_id_for("codex_oauth")。只有取到了非空值(也就是这张卡真的绑了账号),才进入一致性校验;没绑账号的空官方卡直接放行。 - 校验通过则
Ok(())。
一致性校验本身只有一个 if,但里面有两个值得单独说的设计。
第一,判据是请求头,不是 token。 代理拿的是请求头里的 chatgpt-account-id,跟这张卡上绑定的 expected_chatgpt_account_id 做比对。代理层不去解析 token 内容,只比对客户端自报的账号 id 与卡上记的 id。这是个很克制的选择——解 token 意味着要理解上游的令牌格式,而比对一个 id 只需要字符串相等。
第二,双条件,而且第二个条件是三态。 判断写成的是:请求头里的账号 id 与期望值不等,或者 managed_session_matches != Some(true)。后者的类型是 Option<bool>,也就是说它有三种取值:Some(true) 是明确匹配,Some(false) 是明确不匹配,None 是不知道。而条件写的是「不等于 Some(true) 就拒绝」——未知也算失败。这就是 fail-closed:拿不准的时候关,不开。放在账单语义下,这个取向几乎是唯一合理的选择,因为「放行一个不确定归属的请求」的代价是钱记到别人头上,而「多拦一次」的代价只是重启一下客户端。
三条报错文案里有两条都指向同一个动作:重启 Codex 或新建会话。原因发布说明也交代了——Codex CLI 进程在启动时读一次 auth.json,之后不重读;代理这边换了账号,客户端进程内还是旧的那份。所以这里的「重启」不是万金油式的建议,而是这条链路上唯一能让客户端重新读取配置的动作。
对应的回归测试在同一个文件的第 4621、4651 行,断言的就是错误消息里含「重启 Codex」。
与之配套的另一半:官方卡退出自动故障转移
v3.20.0 的「变更」章里还有一条与上面同源的改动:官方 ChatGPT 卡不再被加入、列出或经由故障转移队列重试,官方路由上的所有错误类别一律不可重试。发布说明给的理由是原话——对着另一个供应商重试,会把入站的 ChatGPT 授权用到别的账号头上。
这是个「为了正确性主动放弃可用性」的取舍。故障转移是这个软件反复讲的能力之一,却在这条路径上被刻意关掉,理由不是技术做不到,而是重试的语义在这里等于串账。实现上还有一个细节值得注意:内置官方卡的存量队列行是在读取时过滤的,不改数据。也就是说它不去动你已经存下的队列配置,只是在用的时候跳过。
配套的升级提醒也写清楚了后果:如果内置的 Codex 官方卡原本在自动故障转移队列里,它现在会被过滤,Auto 模式不会从官方卡启动,需要另选一个第三方 Codex 供应商作为主选。
还有一条更早的边界,记在 Chat Completions 上游方向的那两篇路由指南里(各自的第 127 至 129 行、101 至 103 行):CC Switch 会在本地路由接管模式下阻止切到官方供应商,指南给的理由是用代理访问官方 API 可能带来账号风险。
处置之后怎么验证
改完之后不要靠「看起来正常了」收工。仓库文档里给了两条可以自己核的口径。
一是用量归属。Chat Completions 方向那篇指南里有专门一节讲「直连之后用量归属会变」:改走直连以后,请求不再经过本地路由,按请求计费的代理侧用量统计就看不到它了;用量本身不丢(会话日志照常导入),但这条路径不携带供应商身份,所有没走代理的 Codex 用量会归入一个名为 Codex (Session) 的条目。要把它们区分开,只能看模型 ID——用量面板的「模型统计」是按模型逐行列的。反过来说,如果你就是要按供应商对账,那就得保持在需要转换的格式上并开着路由接管。
二是金额口径。docs/guides/claude-codex-routing-guide-zh.md 第 97 行有一句很难得的自陈:token 计数是准确的,美元金额是按公开 API 价折算的估算值,可能与真实扣费不符。所以拿这个面板里的金额去跟账单对数,对不上是正常的;能用来判断归属的是 token 计数与条目归类,不是那个金额。
什么情况说明不是这个原因
这一节比上面几节都重要,因为把不相干的问题按串账去查,只会浪费时间。
- 报错文案是「Codex 官方登录不可用,请先在 Codex 中完成 ChatGPT 登录」。 这走的是第一路分支,含义是请求根本没带
Authorization头。这不是账号对不上,是压根没登录,账号一致性校验还没轮到执行。 - 你用的是不绑定账号的空官方卡。 那段校验被
managed_account_id.is_some()包着,卡上没绑账号时整段不执行,走的是旧路径。这也是这次改动的设计意图之一:新机制不破坏旧行为。所以这种卡出问题,原因一定在别处。 - 你根本没开路由接管。
forwarder.rs里这段代码在代理转发路径上,没开接管就不在链路里。 - Windows 上出现的是「已有的供应商改不了、切不动,但新建能用」。 这是另一条完全不同的因果:v3.19.2 把 Windows 原子写切到了
ReplaceFileW,而 WSL 文件系统以ERROR_NOT_SUPPORTED(错误码 50)拒绝它,当时的 rename 回退只在 NotFound 时触发,于是\\wsl.localhost/\\wsl$路径上任何「替换已有文件」的写入都失败,唯独首次创建仍可用——因为目标缺失本来就触发 NotFound 回退。v3.20.0 把错误 50 也归入了触发回退的分支。这条跟账号毫无关系,认它的特征是「新建能用、改已有的不能用」。 - 接管期间跑过一次
codex login,之后官方登录被抹掉了。 这是接管恢复的问题:恢复用的备份是接管开始时的快照,接管期间新产生的登录会被这份旧快照盖掉,而启动时的自动重接管让这次抹除每次重启都重演。v3.20.0 的修法是仲裁而不是简单跳过——live 的登录材料永远胜出,理由写的是「只有 Codex 自己能推进它,必然比快照新」。
最后一句提醒
这个工具会读写 ~/.claude、~/.codex 这类真实 CLI 配置,并在本机保存 API Key,上面提到的每一个文件都属于本机敏感数据。判定动作里让你去看的 config.toml 与 auth.json,贴出来求助之前请把其中的 token、key 一律替换成 <YOUR_API_KEY> 这类占位。至于多账号本身怎么用,这篇只复述仓库文档与源码写了什么,不给任何绕开平台规则的做法。
本文依据 CC Switch 官方仓库(github.com/farion1231/cc-switch)的 README、docs/ 下的用户手册、
路由指南与发布说明,以及 src/、src-tauri/、tests/ 的源码整理,
核对日 2026-08-31,对应仓库快照 3217f725(仓库内版本号 3.20.1)。
本文内容为仓库源码与文档口径,我们没有安装或运行过这个桌面应用,
因此不涉及界面外观、操作手感与切换速度的任何描述。
文中出现的阈值与默认值均为源码中的默认配置,不构成对实际运行结果的保证。
该项目仍在快速迭代,版本与默认值随时可能变动,请以仓库最新内容为准。
安全相关做法请结合自身环境评估,本文不构成安全方案建议。
留言讨论
评论发布后会被人工复核,违规内容将被删除。
如果发表没有反应,可以前往联系我们告诉我们。