Featured image of post ccswitch 改了模型却没生效:一次 Claude Code 三层模型覆盖的根因诊断

ccswitch 改了模型却没生效:一次 Claude Code 三层模型覆盖的根因诊断

在 ccswitch 里编辑供应商模型并保存,Claude Code 实际跑的模型却不变。用日志加数据库逐字段对比,逼出三层叠加的根因:① 编辑只写数据库不推 live ② 数据库模板与 live 文件漂移 ③ ANTHROPIC_MODEL 环境变量硬钉盖过档位映射。附最小修复与自查命令。

起因:改了三次都没变

我在 ccswitch(v3.19.2,Windows 端的 Claude Code 配置切换工具)里点"编辑供应商",把 Opus 档的模型改掉、保存。切回 Claude Code 重开,跑的模型还是原来那个。再改、再保存、再重启,依旧没变。

“改不了"这类问题最怕瞎猜。下面是用日志和数据库逐字段对比、一步步逼出根因的过程。结论比直觉绕得多——写入是成功的,毛病出在三个地方叠加。

先排除两个看起来最像的嫌疑

嫌疑一:写入失败(原子写 os error 50)。 WSL2 经 9P 桥写 Windows 侧文件,历史上 rename 操作会被拒,报 os error 50。但我看 ~/.claude/settings.json 的修改时间,刚被成功写过;ccswitch 自己的数据库也在同一秒写了,还做了切换前备份。写入链路是通的,排除。

嫌疑二:WSL 和 Windows 是两份文件。 检查发现 ~/.claude/settings.json 是个符号链接,指向 Windows 侧的同一份文件。ccswitch 在 Windows 端写的,就是 Claude Code 在 WSL 里读的,同一份,排除。

先证伪这两个,能省掉大量在错误方向上折腾的时间。这也是排查这类"看起来没生效"问题的第一步:先确认写入到底成没成,别在没坏的地方修。

真正的根因一:模型配置的三层覆盖

Claude Code 决定"实际跑哪个模型”,不是看一个字段,是三层叠在一起,优先级从高到低:

  1. ANTHROPIC_MODEL 环境变量——最高优先级。一旦设了,强制全程跑这个模型,盖过下面两层。
  2. ANTHROPIC_DEFAULT_<档位>_MODEL——“Opus/Sonnet/Haiku/Fable 档分别映射到哪个具体模型”。
  3. model 字段——当前用哪个档位(opus/sonnet/haiku/fable)。

我的配置里三层互相打架:model: "opus"(选 Opus 档),Opus 档映射到模型 A,但 ANTHROPIC_MODEL 又硬钉成模型 B。最高优先级那条一压,下面两层全失效——不管你改 Opus 档的映射,还是改 model 字段切档,实际都跑模型 B。

这就是"改了跟没改一样"的第一层原因:你以为改的是档位映射,但硬钉压着,根本没轮到档位映射说话。

三层模型覆盖:ANTHROPIC_MODEL 硬钉盖过档位映射和 model 字段

真正的根因二:ccswitch 的"编辑"和"应用"是两个分离的动作

这是日志逼出来的。ccswitch 的日志在这次操作的时间窗里只记了这些:

1
2
3
table=settings,  merged_changes=1     ← 改了 ccswitch 自己的设置
table=providers, merged_changes=1     ← 写了 providers 表(数据库模板)
(之后只有托盘鼠标事件,没有任何"应用到 live 配置"的记录)

也就是说,“点编辑、改模型、保存"这个动作,ccswitch 只把它写进了自己的数据库 providers 表(模板更新成功,连云端同步都触发了),但不会因此就把新模板推写到 Claude Code 实际读的那个 .claude/settings.json。要推到 live,得另外点"切换/应用供应商”。ccswitch 启动时也只做反向检查(要不要从 live 回灌进数据库),不会主动把数据库推到 live。

所以:数据库里你的编辑生效了,live 文件纹丝未动,Claude Code 读的还是旧的。这是第二层原因——你做了"编辑",没做"应用"。

真正的根因三:数据库模板与 live 文件漂移

把数据库里这个供应商的模板和 live 文件的实际值拉出来逐字段对比,四个档位映射整组错位了一个位置:

档位 / 字段数据库模板(编辑后存的)live 文件(实际跑的)
Opus 档qwen3.8-maxglm-5.2-fast-preview
Sonnet 档glm-5.2-fast-previewdeepseek-v4-flash-0731
Fable 档deepseek-v4-flash-0731qwen3.8-max
ANTHROPIC_MODELglm-5.2-fast-previewqwen3.8-max

DB 模板 vs live 文件:四个档位整组错位一位

这不是一个字段没改对,是多次编辑数据库、live 却一直停在老切换点,两头越漂越远。即使你回去点"切换"让 ccswitch 推 live,推过去的也是这套错位的模板,还是会乱。另外数据库模板只含 env 块、不含 modeleffortLevel 顶层字段——这是 ccswitch 的设计,但它确实让"通过 ccswitch 完整管理模型"变得别扭。

修复:删掉硬钉,让档位说话

最小修复:删掉 ANTHROPIC_MODEL 这条最高优先级的硬钉。删掉之后,model 字段选档位 → 档位映射 → 实际模型,这条链才真正通。配合理顺过的档位映射(Opus=主力、Sonnet=难任务、Haiku=轻活、Fable=满分),删硬钉后档位分工才生效。

改完必须重启 Claude Code——env 是启动时注入进程的,改文件不影响已经跑起来的会话,当前会话仍是旧值,完全退出重开才读到新配置。

验证方法:重启后用 /model 切到 Sonnet 档,看实际模型是不是变成了 Sonnet 档映射的那个。变了,就证明档位映射这条链通了。

日常怎么办:绕开 ccswitch,直接改 settings.json

诊断清楚之后,最省心的路反而是最朴素的:日常不用 ccswitch,直接改 ~/.claude/settings.json。因为这次"改不了"的唯一原因就是 ccswitch 切换会拿数据库旧模板盖掉 live 文件;你不碰它,这条覆盖路径就不存在了,settings.json 就是你说了算的单一真相源。

唯一铁律:别再打开 ccswitch 点"切换/应用供应商"。一点就触发整块覆盖(错位的档位映射、硬钉、丢键全回来)。不点它,改完重启即可。日常切档用 Claude Code 自带的 /model 命令也行,它本质就是改 settings.jsonmodel 字段,在"不用 ccswitch"的前提下同样持久。

诚实边界

  • 三层覆盖的优先级排序,是静态推断加系统回显佐证(“settings.json pins X — applies on restart”)。重启后三层里究竟哪层最终拍板,我没逐字段实测重启,这部分待你自己重启验证。
  • 结论针对 ccswitch v3.19.2。写文当天检测到 v3.20.0 更新,是否修了"编辑不推 live"的行为,未知。
  • settings.local.json 优先级比 settings.json 高。如果 local 里也设了同名模型字段,会盖过 settings.json——排查时别忘了看 local。

怎么自己查

复现这套诊断,核心就四条命令(路径和密钥请换成你自己的):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1. 看当前进程实际注入了哪些 ANTHROPIC_* 环境变量(只看变量名,屏值)
env | grep -iE 'claude|anthropic' | sed 's/=.*/=<masked>/'

# 2. 看 live settings.json 的 env 块和 model 字段
cat ~/.claude/settings.json | python3 -c "import sys,json;d=json.load(sys.stdin);print('model:',d.get('model'));print(json.dumps(d.get('env',{}),indent=2,ensure_ascii=False))"

# 3. 看 ccswitch 数据库里当前供应商的模板(对比 live)
sqlite3 ~/.cc-switch/cc-switch.db "SELECT settings_config FROM providers WHERE is_current=1"

# 4. 看 ccswitch 日志,找"编辑保存"到底有没有触发 live 写入
grep -iE 'table=providers|live|switch|apply' ~/.cc-switch/logs/cc-switch.log | tail -20

第三条查出来的模板,和第二条查出来的 live 值,逐字段对比——对不上的字段就是漂移点。第四条日志里如果没有"应用到 live"之类的事件,就坐实了"编辑不推 live"。

排查这类"配置改了不生效"问题,思路其实通用:先把数据流上每一段都点亮——写进去了没?写的和读的是同一份吗?读的时候哪层优先级最高盖过了你改的那层?三步走完,根因自己就浮出来了。