




























🔥 每次切换 API 提供商,你精心调教的所有 Agent 配置就各少一块。而你浑然不知。
上周六晚上 11:47 ,上海某 AI 创业公司的全栈工程师刚完成一组 MCP Server 的配置。他花了一个下午,把 Filesystem 、GitHub 、Postgres 、Slack 和 Brave Search 五个 MCP Server 全部接入了 Claude Code 。
settings.json 已经长到快 300 行。他深吸一口气,在终端敲下:
> 帮我查一下数据库里上周的订单量,和 GitHub 上最近的 commits 对比一下
Claude Code 读到了数据库。读到了 GitHub 。读到了文件系统。全部打通了。
他兴奋地截了个图发到团队群。然后顺手用 CC Switch 切了个 API 提供商。
Claude Code 又启动了。但是——数据库访问失败了。GitHub 也读不了。五个 MCP Server 全部瘫痪。
他把昨晚的配置 commit 翻出来 diff 。一模一样。mcpServers 明明就写在文件里。他重启了 Claude Code 。又重启了电脑。他开始怀疑是不是 Claude Code 新版本改了 MCP 协议的 JSON Schema 。
凌晨一点半,他打开了 ~/.cc-switch/cc-switch.db。看见了 common_config_claude 这个 key 。
CC Switch 的设计是这样的:
你点击"切换提供商"
│
▼
┌──────────────────────┐
│ 从 SQLite 读取模板 │ ← 这份模板是你第一次安装时存的快照
│ common_config_claude │
└──────┬───────────────┘
│
▼
┌──────────────────────┐
│ 注入新提供商的 env │
│ (API key, base URL) │
└──────┬───────────────┘
│
▼
┌──────────────────────────────────┐
│ 用这份拼装好的 JSON │
│ 全量覆盖 ~/.claude/settings.json │ ← 💣 一切不在模板里的配置:没了
└──────────────────────────────────┘
注意那个「全量覆盖」。不是 merge 。不是 patch 。是 rm 然后 write。
模板 = 天花板。任何模板之外的配置,在下次切换时原地消失。
打开 ~/.cc-switch/cc-switch.db,你会看到:
SELECT key FROM settings WHERE key LIKE 'common_config_%';
返回结果让人后背发凉:
common_config_claude → 全量覆盖 ~/.claude/settings.json
common_config_codex → 全量覆盖 ~/.codex/config.toml
common_config_opencode → 全量覆盖 ~/.config/opencode/config.json
common_config_openclaw → 全量覆盖 ~/.openclaw/openclaw.json
CC Switch 管理的每一个 Agent ,都有一份独立的模板。每一份模板都是全量覆盖的逻辑。切一次提供商,五个 Agent 的配置同时被各自的模板覆盖。
这不是一个 bug 。这是一个设计模式。它的破坏范围是你安装的所有 Agent 。
我们来看一个真实的数据库快照对比:
| Agent | 模板行数 | 实际配置行数 | 切换一次丢失 |
|---|---|---|---|
| Claude Code | ~30 行 | ~50 行 | marketplace 、statusLine 、allowedTools |
| Codex | 110 行 | 373 行 | 263 行——4 个 marketplace 、model 设置、plugin_hooks 、context window |
| OpenCode | ~2 行 | 未知 | 可能几乎全部 |
| OpenClaw | ~15 行 | 未知 | workspace 、model defaults 、gateway 配置 |
Codex 用户尤其惨烈。你花了几周调出来的 373 行配置——包括 model_context_window = 1000000、model_reasoning_effort = "xhigh"、四个社区 marketplace 、plugin_hooks = true——切一次提供商,回到 110 行的远古版本。Codex 不会报错。它只是突然变得行为诡异。你以为是 prompt 的问题。你不是一个人。
你花了一个下午装了 8 个 Claude Code 插件,每个都调了参数。settings.json 长到 200 行。CC Switch 的模板里只有 4 个老插件。
切换一次提供商 → 4 个新插件配置消失。Claude Code 不报错——它只是静默地不再加载那些插件。你下次敲自定义命令时发现没反应,以为是 prompt 写错了,调试一个小时,最后发现插件根本没启用。
就是你刚才读到的那个真实案例。MCP Server 是 Claude Code 最强大的功能——它让 Claude Code 能直接操作你的文件系统、读 GitHub 、查数据库、调用外部 API 。
配置 MCP Server 是体力活:每个 Server 的 JSON schema 不同,参数名称五花八门,有的需要 API key ,有的需要本地路径绝对引用,有的需要 Node 版本匹配。五个 Server 配完,半天没了。
切一次提供商。全部消失。Claude Code 不会提示"配置已变更"——它只是突然变得很笨。你问它"帮我看看数据库",它说我没有数据库连接。你以为是它理解不了你的意图,实际上你的 mcpServers 键已经被 CC Switch 的模板覆盖成了一年前的空对象。
你维护着一个团队共用的 Claude Code 配置模板。三个月里,团队成员陆续加了 12 个 marketplace 、6 个自定义 hook 、3 个 MCP server 。settings.json 现在是一个精心打磨的产物。
新同事第一次用 CC Switch 切提供商——模板是他三个月前第一次安装时的快照。
整个团队的三个月配置积累,一键回滚。
这是最容易被忽视的。CC Switch 也会管理 Codex 的提供商切换。它的 Codex 模板存了 110 行——第一次安装时的快照。但你实际用了 Codex 几周后,~/.codex/config.toml 已经长到 373 行。
这些多出来的 263 行包括:
model_context_window = 1000000——你花了一个小时试出来的最优值model_reasoning_effort = "xhigh"——你专门查了文档才找到的参数plugin_hooks = true——没有这个,Codex 的插件 hook 完全不生效切一次提供商。263 行没了。Codex 不会弹窗说"配置已回滚"。它只是突然不懂得怎么用 Shortcuts 了,review 质量也变差了。你以为是 OpenAI 改了模型行为。你开始怀疑 GPT-5.5 是不是被降智了。
直到你打开 ~/.cc-switch/cc-switch.db,看见自己的 110 行模板静静地躺在那里。
| 你期望的 | 它实际做的 |
|---|---|
| 只改 env | 覆盖整个文件 |
| 合并配置 | 替换配置 |
| 增量更新 | 全量覆盖 |
| 保留所有自定义 | 保留模板里有的 |
CC Switch 的模板机制,本质上是把一个状态管理问题当成了配置生成问题。它假设 settings.json 除了它写入的东西之外没有其他重要内容。这在 2026 年的 AI agent 生态里是完全站不住脚的——Claude Code 的 settings.json 已经是一个会被多个工具(插件安装器、EchoBird 、手动编辑)同时修改的文件。
每次修改任意 Agent 的配置之后,手动反同步。全部 Agent 一键脚本(保存为 sync-cc-switch.sh):
#!/bin/bash
DB="$HOME/.cc-switch/cc-switch.db"
# Claude Code
python3 -c "import json; c=json.load(open("$HOME/.claude/settings.json")); json.dump({k:v for k,v in c.items() if k!="env"}, open("/tmp/ccs.json","w"), separators=(",",":"))"
sqlite3 "$DB" "UPDATE settings SET value = readfile("/tmp/ccs.json") WHERE key="common_config_claude";"
# Codex (TOML)
sqlite3 "$DB" "UPDATE settings SET value = readfile("$HOME/.codex/config.toml") WHERE key="common_config_codex";"
# OpenCode
python3 -c "import json; c=json.load(open("$HOME/.config/opencode/config.json")); json.dump({k:v for k,v in c.items() if k!="env" and k!="model_providers"}, open("/tmp/ccs.json","w"), separators=(",",":"))"
sqlite3 "$DB" "UPDATE settings SET value = readfile("/tmp/ccs.json") WHERE key="common_config_opencode";"
# OpenClaw
python3 -c "import json; c=json.load(open("$HOME/.openclaw/openclaw.json")); json.dump({k:v for k,v in c.items() if k!="env"}, open("/tmp/ccs.json","w"), separators=(",",":"))"
sqlite3 "$DB" "UPDATE settings SET value = readfile("/tmp/ccs.json") WHERE key="common_config_openclaw";"
rm /tmp/ccs.json && echo "✅ All 4 agents synced"
或者单独同步 Claude Code:
python3 -c "
import json
with open('$HOME/.claude/settings.json') as f:
c = json.load(f)
template = {k:v for k,v in c.items() if k != 'env'}
with open('/tmp/sync.json','w') as f:
json.dump(template, f, separators=(',',':'))
" && sqlite3 ~/.cc-switch/cc-switch.db \
"UPDATE settings SET value = readfile('/tmp/sync.json') WHERE key = 'common_config_claude';" && \
echo "Synced ✅"
CC Switch 没有提供「从当前配置导入」的功能,也没有在切换前做 diff 警告。如果你发现自己经常需要跑上面的脚本,那说明你的使用模式已经超出了 CC Switch 的设计假设。
用 EchoBird 切模型——它只动 env,不动别的:
// EchoBird: 只改这个 block
"env": {
"ANTHROPIC_BASE_URL": "...",
"ANTHROPIC_AUTH_TOKEN": "..."
}
// CC Switch: 覆盖整个文件
{
"enabledPlugins": {...}, // ← 从模板
"extraKnownMarketplaces": {...}, // ← 从模板
"skipDangerous...": true, // ← 从模板
"env": {...} // ← 从提供商
// statusLine? 不在模板里 → 💥
}
CC Switch 是个好工具——它对「一键切换 API 提供商」这个原始需求的解法很直接。但它的模板机制有一个静默丢失数据的致命缺陷,而它不会给你任何提示。
如果你读了这篇文章之后去检查自己的 settings.json,发现少了点什么——不要怀疑自己。你没记错。你是被覆盖了。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。