
1. CC Switch 到底在管什么先搞清楚它动的是哪几个文件刚开始接触 Claude Code 那阵子我的手边有四五个不同的模型服务账号一个官方订阅一个国内厂商的按量付费还有一个本地跑的 Ollama。每次切换我要么去改~/.claude/settings.json要么去动环境变量改完还要关掉终端重开一次否则旧的ANTHROPIC_BASE_URL还挂在当前 shell 里。最崩溃的一次是周五晚上赶一个重构任务切回官方账号时手抖把ANTHROPIC_AUTH_TOKEN复制错了一位排查了四十分钟才发现是 token 的问题而不是模型的问题。CC Switch 这类工具就是被这种场景逼出来的。它的定位很简单把一套模型服务配置抽象成一个供应商档案你可以在图形界面里维护多份档案一键切换切换动作会自动落到对应的配置文件上。它主张管理的核心对象通常包括三块Claude Code 的~/.claude/settings.json、Codex 的~/.codex/config.toml以及 OpenCode 这类客户端的 provider 配置。有些版本还会维护一个自己的本地代理服务把不同格式的请求做一次中转翻译。1.1 手改配置文件的三个隐性成本大多数人觉得改个 JSON 有什么难的但真正用久了会发现成本不在打字而在三件事上。第一是上下文丢失。Claude Code 读的是settings.json里的env块Codex 读的是config.toml里的model_providers两者的字段名、格式、甚至密钥放哪的约定都不一样。你在 A 客户端上调通了B 客户端还得重新学一遍字段含义。第二是状态不可追溯。手改文件没有历史记录今天把 base_url 改成了/v1结尾明天改成不带/v1后天出问题时你根本想不起来上一次能跑通的是哪个版本。我习惯在 CC Switch 里给每个档案写一句备注比如带 /v1仅支持 chat 协议这句备注在排错时省的时间是以小时计的。第三是误伤其他工具。ANTHROPIC_*系列环境变量是全局的你为了 A 项目设的值可能把 B 项目的脚本搞挂。CC Switch 的做法是尽量把配置写进客户端各自的配置文件而不是无脑往系统环境变量里塞这一点在同时维护多个项目时非常关键。1.2 配置档案模型一个档案就是一份可复现的连通性快照理解 CC Switch 的关键是把它看成一个档案管理器而不是API 密钥仓库。一个完整的供应商档案通常包含这几类信息字段类别典型内容为什么必须有标识信息档案名、备注、协议类型切换时你要能一眼认出它是谁接入地址base_url、端口、路径前缀决定了请求最终打到哪里鉴权信息API Key、鉴权头字段名决定 401 还是 200模型映射主模型名、轻量模型名决定客户端请求的模型 ID 能否被上游识别端点协议chat / responses / messages决定请求体格式能否被上游接受把这五类信息凑齐一个档案才算完整任何一项缺失都会在某个特定场景下炸出来。举个最常见的例子只填了模型名没填轻量模型名Claude Code 在处理文件摘要之类的后台任务时会去请求一个默认的小模型上游不认识这个 ID直接返回 400。你以为是密钥问题其实是模型映射漏了一项。2. 安装落地Windows、macOS 与 WSL 的差异点安装环节看起来最没技术含量但我在三个平台上都踩过不同的坑值得单独拆一节。CC Switch 属于典型的桌面客户端形态安装包按平台分发Windows 侧通常是x64的安装程序macOS 侧是 dmg 或 zipLinux 侧视版本而定WSL 环境下的用法又和纯 Linux 有区别。2.1 Windows x64 安装路径、权限与首次启动Windows 上装的时候有两件事建议提前想清楚。一是安装目录不要放在带中文或空格的路径下。这不是迷信而是这类客户端在写入配置文件、调用本地子进程时如果路径里有空格某些命令行拼接会断掉。我一般装到C:\Tools\CCSwitch这种干净的路径。二是是否勾选开机自启。如果你打算用它管理本地代理模式后面第 5 节会细讲那开机自启是必要的因为代理服务需要在你打开终端之前就处在监听状态。如果只是偶尔切配置不开自启更省资源。首次启动后客户端一般会做一次配置文件探测扫描~/.claude、~/.codex这类目录是否存在。如果你之前手改过配置文件建议先备份再让它接管# Windows PowerShell Copy-Item $HOME\.claude\settings.json $HOME\.claude\settings.json.bak Copy-Item $HOME\.codex\config.toml $HOME\.codex\config.toml.bak这个备份动作我是强烈建议的。工具接管配置文件时不同版本的处理策略不一样有的会整文件覆盖有的只合并env块。一旦它把你的自定义字段比如某个permissions配置冲掉了没有备份你就得靠记忆重建。2.2 macOS 与 WSL配置文件位置才是重点macOS 的安装过程基本没坑双击拖进 Applications 就行。真正的差异在配置目录的位置~/.claude、~/.codex这类路径在 macOS 上是标准的问题不大。WSL 下就有点绕了。WSL 里的 Ubuntu 是一个独立的文件系统你在 Windows 侧装的 CC Switch 写的是C:\Users\你\.claude而你在 WSL 终端里跑的 Claude Code 读的是/home/你/.claude——这是两个完全不同的文件。我见过太多人在 Windows 客户端里配好了回到 WSL 里一跑发现还是旧配置然后怀疑工具坏了。解决办法有两个思路思路一在 WSL 里单独跑一份 Linux 版的 CC Switch如果有对应发行包让它直接管 WSL 内部的配置。思路二保持 Windows 侧管理然后在 WSL 里做一次符号链接或同步脚本把 Windows 的配置目录挂过来。# WSL 中把 Windows 用户目录下的配置软链过来路径按实际调整 ln -sf /mnt/c/Users/你的用户名/.claude/settings.json ~/.claude/settings.json注意软链方式有个副作用Claude Code 内部如果对配置文件做原子写入写临时文件再重命名跨文件系统的软链偶尔会失败。如果遇到改完不生效的情况优先怀疑这里改成定时同步脚本比软链更稳。2.3 首次启动后建议先确认的三件事我自己的习惯是装完先别急着配供应商先把这三件事确认掉客户端能读到配置文件。在终端里跑一次 Claude Code 或 Codex看它启动时打印的 base_url 是不是你预期的。很多客户端支持/status之类的命令能直接看到当前生效的端点。本地代理端口没被占用。默认端口如果和你已有的服务撞了代理起不来但界面可能只给你一个很轻的提示。用netstat -ano | findstr 端口号Windows或lsof -i:端口号macOS/Linux确认一下。备份已完成。上面那两条复制命令记得执行这不是可选项。3. 供应商配置从内置模板到全手写这一节是整篇手册的核心。CC Switch 的配置能力分两层内置模板和自定义供应商。内置模板的价值在于帮你把字段名 端点路径 模型 ID这一整套东西都预置好你只需要贴一个密钥自定义供应商则是给那些模板里没有的服务用。两层都要会用因为你迟早会遇到一个模板里没有、但公司内网在跑的端点。3.1 内置模板的适用范围与注意事项内置模板通常覆盖几个类型一是官方 Anthropic 接口二是主流云厂商的兼容接口三是国内几家提供 Anthropic 兼容层或 OpenAI 兼容层的模型服务。用模板的好处是省去查文档的时间但也有两个需要留意的地方。第一个是模板里的模型 ID 会过期。模型服务商会更新模型列表模板里预置的 ID 可能是上一代的。我第一次用某个国内厂商的模板时主模型 ID 是对的但轻量模型那一栏填的还是已下线的旧 ID结果 Claude Code 每次做文件摘要都报 400。后来我把轻量模型也改成同一个可用的 ID问题就消失了。第二个是模板里的 base_url 路径前缀不一定对。有些服务是https://api.xxx.com/v1有些是https://api.xxx.com还有些是https://xxx.com/api/anthropic。路径差一个段表现就是 404。判断方法很简单拿 curl 直接打一次看返回的是模型不存在还是路径不存在。curl -sS https://api.example.com/v1/messages \ -H x-api-key: $KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d {model:your-model-id,max_tokens:16,messages:[{role:user,content:hi}]}如果这条 curl 通了说明地址、密钥、模型 ID 三件事里至少没有致命问题剩下就是客户端配置的问题了。3.2 自定义供应商字段逐个拆解自定义供应商是我用得最多的功能因为经常要接一些非标准端点。下面按字段说明它们各自决定什么。base_url请求的根地址。这里有个经验值——先不带/v1试因为很多客户端的 SDK 会自己补/v1。如果带了重复拼接成/v1/v1表现就是 404 或者路径非常奇怪的错误信息。反过来如果错的路径不存在通常返回 404 而不是 400这是区分路径问题和参数问题的重要线索。鉴权头字段名Anthropic 风格用x-api-keyOpenAI 风格用Authorization: Bearer。这两个不能混。混了的表现是 401而且错误信息通常是invalid api key或者authentication required很容易让人误以为是密钥本身错了其实只是头名字错了。模型映射主模型和轻量模型两个字段。主模型负责你的对话请求轻量模型负责客户端的后台小任务。一个实用技巧是把两个都填成同一个可用 ID先保证跑通等确认稳定了再拆分。端点协议这是最容易被忽略但最容易出事的字段。Anthropic 的/messages接口和 OpenAI 的/chat/completions接口请求体结构完全不同而 Codex 还额外有个/responses协议。选错协议的表现通常是 400而且错误信息会提到某个不认识的字段。{ name: 内网兼容端点, base_url: http://10.0.0.20:8000, api_key_env: INTERNAL_LLM_KEY, protocol: openai-chat, models: { primary: internal-large, fast: internal-large }, headers: { X-Tenant-Id: team-alpha } }上面这份示例是我自己常用的结构加了headers字段用来塞租户标识这类额外头。很多模板不提供这个字段但在企业内网里它经常是必需的。3.3 密钥存放别把 Key 直接写进配置文件这是我见过最危险的习惯——直接把sk-xxxx明文写进settings.json然后同步到某个笔记或者 Git 仓库里。国内几家模型服务商在创建 API Key 时都明确提示密钥只在创建时显示一次这本身就说明它等同于密码。比较稳妥的做法是走环境变量引用。CC Switch 的档案里填环境变量名真正的密钥放在系统的环境变量或者.env文件里并且把.env加进.gitignore。这样即使配置文件被同步出去了泄露的也只是一个变量名。注意Windows 下设置用户级环境变量后需要完全重启终端和客户端才能读到不是关掉那个窗口重开就行。这一点我踩过不止一次每次都要浪费十几分钟怀疑自己配错了。4. 接入 Claude Code、Codex 与 OpenCode 的三种姿势同一个 CC Switch 档案接入不同客户端的方式完全不同。这三个客户端各有各的配置约定我把它们的差异整理成了一张表后面再逐个展开。客户端主配置文件密钥传递方式协议偏好Claude Code~/.claude/settings.jsonenv块内环境变量Anthropic messagesCodex~/.codex/config.tomlenv_key指向的环境变量responses 或 chatOpenCodeopencode.jsonprovider 的 options 内OpenAI 兼容Ollama本地无需改文件无OpenAI 兼容4.1 Claude Codesettings.json 里的 env 块Claude Code 读配置的方式非常直接它会在启动时把settings.json的env块里的键值对注入到自己的运行环境。所以你要做的就是把 base_url 和 token 塞进去。{ env: { ANTHROPIC_BASE_URL: https://api.example.com, ANTHROPIC_AUTH_TOKEN: ${MY_LLM_TOKEN}, ANTHROPIC_MODEL: your-model-id, ANTHROPIC_SMALL_FAST_MODEL: your-model-id } }几个实测要点ANTHROPIC_AUTH_TOKEN和ANTHROPIC_API_KEY是两个不同的变量不同客户端版本认的字段不一样。如果配了没生效把两个都填上通常能解决。ANTHROPIC_SMALL_FAST_MODEL千万别漏前面的 400 报错大半来自它。改完settings.json后必须重启 Claude Code 会话热加载是不存在的。4.2 Codexconfig.toml 与 responses 协议的坑Codex 用的是 TOML 格式配置结构上和 Claude Code 差别很大。它的核心概念是model_provider你需要先定义一个 provider然后指定当前使用哪个。model your-model-id model_provider myprovider [model_providers.myprovider] name My Provider base_url https://api.example.com/v1 env_key MY_LLM_TOKEN wire_api chatwire_api这个字段是 Codex 特有的可以填chat或responses。这是 Codex 用户最常踩的坑如果你的上游服务只实现了 OpenAI 的/chat/completions而你这里填了responses那请求就会打到/responses路径上直接 404。热词里出现的cc switch local proxy failed while handling codex endpoint /responses这类报错追根溯源基本都是这个字段配错。判断方法看你的上游服务文档里有没有/responses这个路径。没有就老老实实填chat。4.3 OpenCode 与 Ollama本地模型零成本接入OpenCode 的配置是 JSON 形式它支持通过ai-sdk/openai-compatible这类适配器接入任意 OpenAI 兼容端点。如果你用 CC Switch 的本地代理模式这里填的就是代理的本地地址。{ $schema: https://opencode.ai/config.json, provider: { ccswitch: { npm: ai-sdk/openai-compatible, options: { baseURL: http://127.0.0.1:8899/v1, apiKey: any-non-empty-string }, models: { glm-4.7: { name: GLM-4.7 } } } } }Ollama 是最省事的一环因为它本身就提供 OpenAI 兼容接口默认跑在http://127.0.0.1:11434。你在 CC Switch 里建一个指向它的档案模型名填ollama list里显示的名字即可。# 确认 Ollama 在跑并看一眼模型名 ollama list curl http://127.0.0.1:11434/v1/models本地模型这条路的实际价值在于它是唯一一个不消耗任何额度的选项。代价是速度和能力受限于你的机器跑大参数模型需要足够的内存。我自己的用法是把本地模型当兜底——网络不稳或者额度用尽时切过去保证工作流不断。5. 本地代理的工作原理以及状态码怎么读CC Switch 最有价值也最容易出问题的功能就是本地代理local proxy。它在你本机起一个 HTTP 服务客户端把请求发给这个本地地址代理再转发给真正的上游。中间这一层带来了格式转换、密钥注入、请求日志等能力也带来了整整一类新的报错。热词里那一大串local proxy failed while handling ... unexpected status 4xx/5xx全是这一层的产物。5.1 代理到底做了哪几件事理解代理的职责是排错的前提。它一般做三件事第一协议转换。客户端说的是 Anthropic messages 的方言上游可能只懂 OpenAI chat 的方言。代理负责把请求体翻译过去再把响应翻译回来。翻译过程里如果有字段处理不当就会出现 400。第二密钥注入。客户端发给本地代理的请求可以不带密钥或者带个占位串代理在转发时把真实的密钥补上。这样做的好处是密钥不需要写进每个客户端的配置文件。但副作用是如果你在客户端那边也配了密钥两个密钥打架就会出现 401。第三请求记录。代理会把完整的请求和响应记下来这是排错的黄金材料。遇到任何报错第一件事就是去看代理日志里的完整错误体里面通常直接写了上游的原始报错原因。5.2 从状态码反推问题出在哪一层下面这张表是我自己总结的排查路径按上游返回给我的状态码来定位比漫无目的地试要高效得多。状态码最可能的成因优先检查项400请求体字段不被接受协议类型、模型 ID、思考模式字段401密钥无效或未注入环境变量是否被读到、鉴权头名402账户额度耗尽服务商后台余额403密钥无该模型权限密钥权限范围、账户实名状态404路径错误base_url 是否重复拼接/v1502 / 503上游网关异常或代理自身异常重试、查看代理进程状态402 和 403 这两个在国内服务商上出现的频率比想象中高。402 基本就是余额或免费额度用完了去后台看一眼就知道。403 的一个常见原因是账户没有完成平台要求的身份验证导致没法创建可用的 API 密钥或访问某些高级模型——这是平台侧的合规要求跟配置无关别在配置上浪费时间。404 的排查有个小技巧看代理日志里实际请求的完整 URL。如果显示成https://api.example.com/v1/v1/messages那就说明 base_url 多带了一层/v1。这个错误肉眼看不出来只有看日志才一目了然。502 和 503 大多不是你的问题属于上游临时故障。但有一个例外值得警惕如果日志显示请求根本没发出去那可能是代理进程本身挂了或者端口被占。这时候重启一下客户端或者去设置里把端口换一个。5.3 stream disconnected 与 reasoning_content 回传这两个报错值得单独讲因为它们都属于看起来像网络问题实际上是配置问题的类型。先说stream disconnected before completion: stream closed before response completed。流式响应中断成因有三个层次一是上游服务本身在生成到一半时断了大模型服务偶发二是代理的读超时设置太短模型还在思考它就把连接掐了三是输出长度超过了max_tokens限制上游主动截断。排查顺序建议是先把超时调大再看日志里是否有截断标记最后才怀疑上游稳定性。再说reasoning_content这个。部分模型在思考模式下会在响应里返回一个reasoning_content字段。关键在于在后续轮次的请求里这个字段必须被原样传回去。很多中间层包括代理的协议转换逻辑、客户端的消息裁剪逻辑会自作主张地把不认识的字段丢掉一旦丢了上游就会认为请求不合法直接返回 400错误信息里通常就带着reasoning_content in the thinking mode must be passed back这句话。处理办法有三条路把协议类型换成能保留该字段的那一档。有些代理实现对 OpenAI chat 协议做了字段透传选对了就不会丢。在上游侧关掉思考模式。如果你不需要推理链的可见输出直接不用这个模式是最省心的。升级代理版本。字段透传这类问题通常是版本迭代里修的老版本丢了就是丢了。提示遇到 400 时先去代理日志里把完整的错误响应体复制出来再去搜关键词。错误信息里的那句英文往往直接告诉你是哪个字段的问题比看状态码有用得多。6. 长期维护档案命名、备份与那些没人写进文档的经验配通只是第一步真正的考验是三个月后你还能不能想起来当初为什么这么配。这一节讲的是我在长期使用中沉淀下来的几个习惯都是些文档不会写、但能实实在在省时间的做法。6.1 档案命名要带环境和用途两个维度我最早的命名是供应商A供应商B这种两个月后完全分不清谁是谁。后来改成三段式环境_供应商_协议比如prod_deepseek_chat、local_ollama_compat、test_internal_messages。这样命名的好处是排序天然按环境聚合切换时不容易点错。更重要的是出问题时你能一眼看出哦我用的这个是 chat 协议那/responses的报错就不该出现省掉一轮无效排查。备注栏也别空着把必须带 /v1、轻量模型和主模型同 ID这类踩坑信息写进去三个月后的你会感谢现在的自己。6.2 备份、迁移与升级的正确姿势CC Switch 管的配置文件都在你的用户目录下这意味着它天然可以跟着你迁移。我的做法是维护一个配置清单文档记下每个档案的关键字段不含密钥然后定期导出一次配置文件目录。# 一次性打包主要配置注意排除含密钥的文件 tar -czf cc-config-backup-$(date %Y%m%d).tar.gz \ ~/.claude/settings.json \ ~/.codex/config.toml \ ~/.config/opencode/opencode.json升级客户端时有个顺序问题先备份再升级升级后逐项验证。我遇到过一次版本升级后代理的默认端口被改了我没注意结果 OpenCode 那边一连串 502查了半小时才定位到端口变了。所以升级后至少要跑一次完整的连通性验证Claude Code 发一句话、Codex 发一句话、OpenCode 发一句话三个都通才算升级完成。另外一个细节是代理模式下不要同时开多个客户端的高并发请求。有些代理实现是单线程处理的多个客户端同时发请求会出现排队甚至互锁。我一般错开使用或者干脆给不同客户端配不同端口的代理实例。6.3 几条实测出来的经验能少走不少弯路最后整理几条零散的、但每次都能救命的经验。先在 curl 层验证再上客户端。任何新供应商先用 curl 打一次原始接口确认地址、密钥、模型三件事都通再去配客户端。这样出问题时你就知道问题一定在客户端配置这一层搜索范围直接缩小一半。改配置后重启客户端别指望热加载。这条看着简单但我统计过自己前期的排错时间至少三分之一是花在忘了重启上。把代理日志的路径记在便签上。出问题时第一反应就是打开它而不是在各个客户端之间乱试。同一个模型别在两个客户端上用不同的档案。我一度 Claude Code 用 A 档案、Codex 用 B 档案两个档案指向同一个上游但协议类型不同结果一个是 chat 一个是 responses排查时完全绕晕了。统一成一个档案问题面会小很多。额度快用完时提前切。402 这种报错往往来得突然工作到一半被打断很影响状态。我习惯在服务商后台设置里开启用量提醒快到底了就提前切到本地 Ollama 兜底。