Claude Code 和 Codex 这类命令行 AI 编程工具好用是好用,但真到了日常干活的时候,问题马上就来了:手上同时有官方订阅、有国产大模型的额度、还有本地跑的 Ollama 小模型,每个客户端的配置方式都不一样,环境变量、base_url、密钥格式、请求路径全是各写各的。想换个模型试试,就得翻文档、改配置、重启终端,一来二去半小时没了。CC Switch 就是冲着这个痛点来的——它本质上是一个跑在本机的模型路由与协议转换层,把 Claude Code、Codex、OpenCode 这些客户端统一接到一个本地地址上,再由此转发到你真正想用的模型供应商。这份手册不打算复述官方文档,而是按"基础配置到高级功能"的顺序,把我在多台机器上反复折腾后总结出的配置方法、字段含义、踩坑记录一次性讲清楚,从没装过的小白到想调优的老手都能对着抄。
1. CC Switch 到底解决什么问题:先想清楚再动手
1.1 多模型时代的"接线板"逻辑
很多人第一次听到 CC Switch,会把它理解成"模型切换器",觉得点一下按钮换个模型就完事了。这个理解只对了一半。真正干活的时候你会发现,麻烦的从来不是"选哪个模型",而是每个客户端说不同的语言。
Claude Code 说的是 Anthropic 的 Messages API,请求路径是/v1/messages,消息体里system是独立字段,工具调用走tool_use和tool_result块;Codex 走的是 OpenAI 的/responses端点,工具调用是function_call;OpenCode 则更灵活,但默认按 OpenAI Chat Completions 格式走/chat/completions。而国内的智谱、硅基流动、DeepSeek 这些平台,虽然大多提供 OpenAI 兼容接口,但细节上各有各的脾气——有的不支持某些字段,有的对reasoning_content有强制要求,有的流式返回格式做了微调。
CC Switch 的价值就在于它站在中间,把"客户端方言"和"上游方言"解耦了。它在本机起一个 HTTP 服务,监听一个端口,客户端只认这个本地地址;请求进来之后,由 CC Switch 负责路径重写、字段映射、鉴权头替换、响应格式回填,再转发给真正的上游。这么设计的好处很直接:客户端配置文件不用动,想换上游只改 CC Switch 里的一行;上游挂了或者涨价了,改配置比改十几个环境变量快得多。
打个生活类比,这就像家里装修时装了一个总配电箱。各个房间的插座位置固定不动,你想换台电器,插拔的是插座那头;至于电从哪个发电厂来、走的是火电还是光伏,那是配电箱里面的事。CC Switch 就是那个配电箱,而且它还能顺手做几件配电箱不该干的事——比如把 A 家的电和 B 家的电混着用。
还有一层价值容易被忽略:密钥隔离。真实项目里经常出现"公司额度"和"个人额度"混用的情况,密钥散落在各个客户端的配置文件、shell 的rc文件、甚至项目根目录的.env里,哪天要轮换密钥就得全仓库搜一遍。用 CC Switch 之后,客户端里只留一个本地占位密钥,真密钥集中在它自己的配置里,轮换成本从"搜十处"降到"改一处"。
注意:CC Switch 只是本地转发层,它不提供任何模型能力,也不改变上游的服务条款。你接入的每一个平台,该实名认证的实名认证,该付费的付费,该限制并发量的还是限制。指望靠它"白嫖"是不现实的,任何绕过平台计费与配额的做法都不该尝试。
1.2 它和直接改环境变量的区别
有人会问,Claude Code 本身就支持通过ANTHROPIC_BASE_URL指向兼容端点,我直接改环境变量不就行了,为什么还要多套一层?
这个问题问到点子上了。直接改环境变量在"只用一家供应商、格式完全兼容"的场景下确实最省事,一行export搞定。但只要你开始面对下面这几种情况,裸改环境变量就会开始难受:
- 上游格式不完全兼容。比如某平台只提供 OpenAI 格式的
/chat/completions,而客户端只会说 Anthropic 格式的/v1/messages,这时必须有人在中间做协议转换。 - 想按模型名分流。同一个客户端里,让它处理长文本时走便宜的大上下文模型,写代码时走强推理模型,这靠环境变量做不到,得靠路由规则。
- 想保留思考链但客户端不认。不少推理模型会返回
reasoning_content字段,客户端解析时直接报错或丢弃,需要在中间层决定是剥离还是透传。 - 想给多个项目用不同额度。每个项目一个终端窗口,各自指向不同的本地端口,这在 CC Switch 里就是多开几个实例的事。
反过来说,如果你只是想把 Claude Code 接到一个完全兼容 Anthropic 协议的服务上,而且以后也不打算换,那真没必要上 CC Switch,多一层转发就多一个故障点。工具是为场景服务的,不是为了显得专业。
我个人建议的判断标准是这样的:当你在一个月内有过两次以上"换模型要改配置"的经历,就该上 CC Switch 了。低于这个频率,手动改更划算。
2. 基础配置:从零把本地代理跑起来
2.1 下载与安装:Windows、macOS 与 WSL 的差异
安装环节本身不难,难的是不同系统下的坑完全不一样,尤其是 WSL 环境。
Windows x64 桌面版是最省事的路径。下载对应架构的安装包,双击走完向导,首次启动会在托盘区出现图标。这里有一个新手最容易忽略的点:Windows 版本的 CC Switch 默认监听的是127.0.0.1,也就是回环地址,只有本机进程能访问。如果你打算让 WSL 里的 Ubuntu、或者局域网里的另一台机器连过来,就必须在设置里把它改成监听0.0.0.0,同时确认系统防火墙对那个端口放行。
macOS 版本的安装流程和普通 dmg 应用没区别,但有两个系统层面的细节值得提醒。一是首次运行时会弹"无法验证开发者"的提示,需要在系统设置的隐私与安全性里手动允许一次;二是如果开启了某些系统级的网络过滤类软件,可能会拦截本地回环流量,表现是 CC Switch 显示运行中、但客户端连不上,此时把回环地址加入例外即可。
WSL 里的 Ubuntu是问题最多的场景,原因在于网络模型。WSL2 默认运行在独立的轻量虚拟网络里,localhost指向的是 WSL 自己,而不是 Windows 宿主。所以当 CC Switch 跑在 Windows 上、客户端跑在 WSL 里时,客户端不能填127.0.0.1,得填宿主机的地址。有两种解法:
第一,从 WSL 里读取宿主机 IP,然后写进客户端配置:
# 在 WSL 的 Ubuntu 中执行,取出 Windows 宿主 IP HOST_IP=$(ip route show default | awk '{print $3}') echo "宿主机地址: $HOST_IP" # 测试连通性,假设 CC Switch 监听 8899 curl -sS -m 5 "http://${HOST_IP}:8899/health" || echo "连不上,检查监听地址和防火墙"第二,启用 WSL 的镜像网络模式,让 WSL 与 Windows 共享网络命名空间。这需要在 Windows 用户目录下新建或修改.wslconfig:
[wsl2] networkingMode=mirrored改完之后在 PowerShell 里执行wsl --shutdown,再重新进入 WSL。镜像模式下127.0.0.1在 WSL 和 Windows 之间是互通的,配置立刻简单一个量级。代价是某些依赖独立网络栈的工具可能出现异常,遇到问题就把这行注释掉回退。
提示:WSL 用户的排查顺序建议固定为"先确认 CC Switch 的监听地址 → 再从 WSL 里 curl 健康检查端点 → 最后才怀疑客户端配置"。跳过前两步直接改客户端,八成会绕远路。
2.2 供应商接入:字段含义与密钥管理
安装完进入主界面,核心工作就是配置供应商条目。每个条目大致由这几个字段组成:
| 字段 | 作用 | 常见填错的地方 |
|---|---|---|
| 名称 | 本地标识,随意起 | 用了中文或空格,导致日志难读 |
| Base URL | 上游接口根地址 | 多写或少写/v1,导致路径拼接后 404 |
| API Key | 鉴权凭据 | 提前带了Bearer前缀,又被程序加了一次 |
| 模型映射 | 客户端模型名 → 上游真实模型名 | 映射了但客户端仍用旧名字,命中不了规则 |
| 端点类型 | messages / responses / chat_completions | 选错类型,直接 404 |
| 超时 | 单次请求最长等待 | 用默认 30 秒,长任务被自己掐断 |
这里我想重点说Base URL 的拼接逻辑,因为它是 404 报错的第一大来源。不同程序的拼接习惯不同:有的会把端点类型对应的路径直接拼到 Base URL 后面,有的会先去掉末尾斜杠再拼,还有的假设你填的地址已经包含版本号。稳妥的做法是看客户端的报错信息里打印出的完整 URL,拿它和上游文档里的示例 URL 逐段比对,差一段就是差在这里。
密钥管理这块,我的习惯是分三层。第一层是"高频日常用"的密钥,配额中等、调用频繁;第二层是"应急"密钥,平时不用,主密钥出问题时顶上;第三层是"本地模型",不需要密钥,直接用 Ollama 的地址。CC Switch 里把这三层分别建成三个供应商配置,客户端通过不同的本地端口或不同的模型别名去区分。这样即使某个平台临时限流,我也能在十秒内把当前会话切到备用通道,而不是干等着。
再补一个细节:不要把所有平台的密钥都写进同一份配置文件然后丢进 Git 仓库。哪怕仓库是私有的,密钥进了版本历史就很难彻底清除。我习惯的做法是配置文件只写占位符,真值放在系统的环境变量里,由 CC Switch 启动时读取。这样配置文件可以放心提交。
2.3 各客户端接入姿势:Claude Code、Codex、OpenCode 与 Ollama
配置完供应商,接下来是让各个客户端指向 CC Switch。这里逐个说。
Claude Code的接入最简单,因为它原生支持自定义 Base URL。在 shell 配置文件里加两行:
# 指向 CC Switch 的本地地址,端口按实际填写 export ANTHROPIC_BASE_URL="http://127.0.0.1:8899" export ANTHROPIC_API_KEY="cc-switch-local-placeholder"第二行的密钥是给客户端做本地校验用的占位值,真密钥由 CC Switch 在转发时替换。很多人在这里踩坑:把真密钥填进了客户端,结果 CC Switch 又替换了一次,上游收到两个鉴权头,直接 401 或 403。占位密钥这件事一定要养成习惯。
Codex走的是 OpenAI 的/responses端点,这也是热词里报错最密集的地方。配置时要注意两点:一是端点类型必须选responses,选成chat_completions会稳定 404;二是 Codex 对响应格式的要求比一般客户端严格,如果上游返回的流式分片结构不完全一致,就会出现"流提前关闭"的现象。我的处理办法是先在 CC Switch 里接一个完全兼容 OpenAI 格式的上游跑通,确认链路没问题,再换成目标平台。
OpenCode的接入点是在项目配置里指定 provider 的 baseURL 和模型列表。它的好处是天然支持多 provider 并存,所以即使不经过 CC Switch 也能配多套。但经过 CC Switch 之后,它能省掉为每个 provider 单独维护一份配置的麻烦,尤其是当你想让 OpenCode 用上和 Claude Code 同一个模型池的时候。
Ollama是本地模型场景的核心。它默认在11434端口提供 OpenAI 兼容接口,所以可以直接当成一个特殊供应商接进来:
# 确认 Ollama 在跑,并且模型已拉取 ollama list curl -sS http://127.0.0.1:11434/v1/models | head -c 300把http://127.0.0.1:11434/v1填进 CC Switch 的 Base URL,端点类型选chat_completions,密钥随便填一个非空值(Ollama 不校验)。这样就能实现"简单的补全和格式化走本地小模型、复杂推理走云端"的混合编排。
注意:本地模型和云端模型的上下文窗口差异巨大,同一个客户端配置文件在不同模型间切换时,很可能因为历史对话太长导致本地模型报"上下文超限"。稳妥做法是给本地模型单独配一个更激进的上下文裁剪策略,别指望客户端自己管好。
3. 高级功能详解:路由、映射与思考模式
3.1 模型映射与别名:让一个客户端名字对应多个后端
模型映射是 CC Switch 里最能提升效率的功能,也是最容易被配错的。它的作用很简单:客户端里写claude-sonnet-4-5,CC Switch 收到后把它替换成上游真正认识的模型 ID 再转发出去。
为什么需要这个?因为客户端的模型名经常是硬编码的,改起来很麻烦。比如 Claude Code 内部有一整套默认模型名,你想让它用智谱的 GLM 系列,不可能去改客户端的源码,只能在中间层做替换。映射规则通常是"客户端模型名 → 上游模型名"的一对一关系,但进阶用法是一对多:根据请求特征分流。
我在实际项目里用过这样一套规则,效果不错:
| 客户端请求特征 | 实际路由到 | 理由 |
|---|---|---|
| 消息数少于 5 且无工具调用 | 本地 Ollama 小模型 | 简单问答,省额度 |
| 包含工具调用且消息数中等 | 国内平台中档模型 | 平衡成本与能力 |
| 上下文超过阈值 | 长上下文专用模型 | 避免被截断 |
| 显式指定了强推理别名 | 最强推理模型 | 关键任务兜底 |
配置时有两个坑必须提。第一是别名冲突:如果你给两个供应商配了同一个别名,行为取决于实现,可能是先匹配到的胜出,也可能报错。养成别名加前缀的习惯,比如local-qwen、cloud-glm。第二是映射不生效却不报错:有些客户端会在模型名不匹配时静默回退到默认模型,你以为是映射失败,其实是根本没走到映射规则。排查方法是打开 CC Switch 的请求日志,看上游收到的模型 ID 到底是什么。
3.2 reasoning_content 回传机制:400 报错的真正原因
这是热词里出现频次极高的一个报错,值得单独拎出来讲透:
upstream_status: http 400; cause: the `reasoning_content` in the thinking mode must be passed back to the api.这句话翻译成人话就是:这个推理模型在工作时会产生一段"思考过程",上游要求你在下一轮对话里把这段思考过程原样带回去,但你没带。
为什么上游要这么要求?因为这类模型的多轮对话是"有状态"的——它需要看到自己上一轮是怎么想的,才能保持推理的连贯性。如果中间层在转换消息格式时把reasoning_content字段丢了,上游就会认为这次请求不完整,直接返回 400。
问题出在哪一环?八成在 CC Switch 的消息映射规则上。Anthropic 格式的消息结构里没有reasoning_content这个字段的位置,所以当 CC Switch 把上游响应转成 Claude Code 能看懂的格式时,这个字段很容易被当成"未知字段"丢弃。下一轮请求再发出去时,自然就缺了。
我验证和处理这个问题的思路分三步:
- 确认是不是真的丢了:打开 CC Switch 的请求日志,找到发送给上游的原始 JSON,看
messages数组里最后一条助手消息有没有reasoning_content。没有就是丢在中间层了。 - 优先用透传模式:如果 CC Switch 提供了"保留未知字段"或"原始响应透传"之类的选项,先打开它。透传模式下中间层不做字段裁剪,兼容性最好,代价是客户端可能看到一些它不认识的字段,只要不报错就没问题。
- 实在不行就降级:把该供应商配置里的思考模式关掉,让它返回普通响应。能力会打折扣,但链路立刻稳定。适合作为过渡方案。
再补充一个容易被忽略的点:即使字段透传了,顺序也可能有影响。部分实现要求reasoning_content紧跟在对应的助手消息之后、工具调用之前。如果你的映射规则做了消息重排,同样会触发这个 400。遇到这种情况,把映射规则简化到最小集,只做模型名替换,不做结构变换。
提示:接入带思考模式的新模型时,先用一条最少轮次的对话验证(问一句、答一句、再追问一句),能跑通再把长会话接上去。直接拿复杂任务试,出错了根本分不清是字段问题还是内容问题。
3.3 本地与云端混合编排:省额度又不掉链子
高级功能里最实用的组合,是把本地模型当成"第一道过滤器"。日常使用中,真正需要强推理的请求其实占比不高,大量操作是改个变量名、补个注释、格式化一段 JSON,这些交给本地小模型完全够用,而且零延迟、零成本。
具体怎么编排?我的做法是给 Claude Code 配两个不同的启动别名,用 shell 函数切换:
# 写入 shell 配置,按需切换本地与云端通道 cc-local() { export ANTHROPIC_BASE_URL="http://127.0.0.1:8899" export ANTHROPIC_MODEL="local-qwen" echo "已切到本地模型通道" } cc-cloud() { export ANTHROPIC_BASE_URL="http://127.0.0.1:8899" export ANTHROPIC_MODEL="cloud-strong" echo "已切到云端强推理通道" }两个别名在 CC Switch 里映射到不同的上游。日常敲cc-local,遇到复杂重构再cc-cloud,切换成本几乎为零。
这套编排有两个硬性前提。第一是本地模型的工具调用能力必须过关,因为 Claude Code 高度依赖工具调用来读写文件,如果本地模型不支持或支持得很差,整个流程会卡死或者乱操作文件。选模型时优先挑那些明确标注支持 function calling 的。第二是上下文长度要够,Claude Code 塞进去的系统提示词本身就不短,本地模型如果只有 4K 上下文,基本没法用。
还有一个隐蔽的坑:本地模型对系统提示词的遵循度通常不如云端模型,可能出现"无视指令乱改文件"的情况。我的应对是给本地通道加一层保护——在项目根目录挂一个 Git 钩子或者干脆养成频繁提交的习惯,一旦模型跑偏能一键回滚。这个习惯看着笨,但救过我不少次。
4. 报错排查实录:local proxy failed 系列逐条拆解
4.1 状态码速查:从 400 到 503 分别意味着什么
热词里那一长串local proxy failed while handling ...后面跟着不同的状态码,看起来吓人,其实每个码的含义都很明确。先看这张表,绝大多数问题能靠它定位到方向。
| 状态码 | 大概率原因 | 优先动作 |
|---|---|---|
| 400 | 请求体字段不符合上游要求,如缺 reasoning_content | 抓原始请求体,和上游文档逐字段比对 |
| 401 | 鉴权失败,密钥错、过期或重复 | 检查密钥占位符与中间层替换逻辑 |
| 402 | 额度耗尽或账户欠费 | 登录平台查看余额与配额 |
| 403 | 权限不足,密钥无该模型权限或实名未完成 | 确认账户状态与密钥授权范围 |
| 404 | 路径不匹配,端点类型选错 | 比对实际请求 URL 与文档示例 |
| 429 | 触发限流 | 降并发,或加退避重试 |
| 502 / 503 | 上游服务不可用或中间层转发异常 | 先直连上游验证,再查中间层 |
这张表里我想多说两句 401 和 404,因为它们最容易被误判。
401 的典型误判是"密钥明明是新的"。这时候要看的不是密钥本身,而是它有没有被加前缀。很多平台文档写的是Authorization: Bearer sk-xxx,于是有人就把Bearer sk-xxx整个填进了 API Key 输入框,程序再拼一次Bearer,上游收到Bearer Bearer sk-xxx,直接拒绝。另外还要确认客户端和 CC Switch 没有同时注入鉴权头,两个头并存时部分网关会判定为异常。
404 的典型误判是"地址没错啊,浏览器能打开"。浏览器打开的是根路径,而客户端请求的是具体端点。/v1/messages、/v1/responses、/v1/chat/completions这三个路径长得很像,选错一个就是 404。最靠谱的排查方式是看 CC Switch 日志里那条完整 URL,把它复制出来直接 curl 一次,看返回什么。如果 curl 也 404,问题在路径;如果 curl 通而客户端不通,问题在客户端的端点类型配置。
402 和 403一起说。402 是钱的问题,没什么技术含量,去平台后台看一眼余额就行。403 就复杂一些,除了钱,还可能是密钥权限范围不含目标模型、账户实名认证未完成、或者平台对某些模型做了额外授权要求。国内几家平台在这方面的规则差异不小,有的开通即用,有的需要单独申请模型权限。遇到 403 别急着重配,先去平台控制台把账户状态和密钥权限逐项确认一遍。
4.2 流断开问题:stream disconnected 与 stream closed before response
比状态码更烦人的是流式响应中断。表现是客户端开始输出了几个字,然后突然停住,日志里出现stream disconnected before completion或stream closed before response。这类问题通常没有明确的状态码,因为连接是被中途掐断的。
按我的排查经验,原因按概率从高到低排是这几个:
- 超时设置太短。默认 30 秒对长响应来说完全不够,尤其开启思考模式后,模型"想"的时间可能就超过一分钟。把 CC Switch 和客户端的超时都调到 5 分钟以上试试。
- 中间层做了缓冲聚合。有些转发实现为了便于日志记录,会先把整个响应读完再一次性返回,这直接破坏了流式语义,客户端等不到分片就判定超时。检查 CC Switch 是否有"流式透传"开关,打开它。
- 上游本身的分片格式不规范。比如结尾少了一个
[DONE]标记,或者分片的 JSON 没换行分隔。这种要在日志里对比分片结构才能发现。 - 网络链路中间设备干预。企业网络里的某些设备会对长连接做空闲回收,表现是固定时间点断流,比如每次都卡在 60 秒左右。这种规律性很强的断流,基本可以锁定是链路问题,改用更短的心跳间隔或者干脆换成非流式请求来验证。
判断是不是超时,有个简单办法:把同一个请求改成非流式发一次。如果非流式能完整返回,只是慢,那就是超时或缓冲问题;如果非流式也失败,那就是上游或字段问题。
4.3 启动就失败:端口、监听地址与配置语法
还有一类问题发生在更早的阶段——CC Switch 根本没起来,或者起来了但客户端完全连不上。这时候客户端日志通常是一句干巴巴的"连接被拒绝",看不出所以然。
端口占用是最常见的原因。默认端口被别的程序(比如另一个开发服务器)占了,CC Switch 启动后静默失败或者自动换了个端口,而客户端还指着老端口。Windows 上用netstat -ano | findstr 8899查占用,macOS 和 Linux 上用lsof -i :8899。查到占用进程后,要么关掉它,要么给 CC Switch 换个端口并同步改客户端配置。
监听地址不匹配排在第二。前面提过,只监听127.0.0.1时,WSL 和局域网都连不进来。判断方法是看 CC Switch 启动日志里打印的绑定地址,如果是127.0.0.1:8899而你从 WSL 里连,必然失败。
配置语法错误最容易浪费感情。JSON 配置多一个逗号、少一个引号,程序可能只打印一行解析错误就退出了。我的习惯是改完配置先过一遍校验:
# 校验 JSON 配置语法,jq 会明确指出错误位置 jq empty ./cc-switch-config.json && echo "语法 OK" # 查看实际生效的配置内容,确认字段值符合预期 jq '.providers[] | {name, baseUrl, endpointType, models}' ./cc-switch-config.json补一个我自己的体会:配置改动后不要一次改多项。一次性改了 Base URL、端点类型、密钥三处,一旦出错就得逐个二分排查,很浪费时间。改一项、测一次,看着慢,实际快得多。
5. 长期使用中的经验与配置维护
5.1 配置版本管理与升级后的回归检查
CC Switch 的配置文件值得像代码一样管理,但前面说过密钥不能明文提交。我的做法是维护两份:一份是config.template.json,所有密钥位置写成占位符,进 Git;一份是本地实际的config.json,通过.gitignore排除。升级或者换机器时,从模板复制一份,填上密钥即可,五分钟能重建环境。
每次升级 CC Switch 版本之后,有三项回归检查是必做的:
- 模型映射是否还生效。升级可能改变映射规则的解析方式,尤其是别名匹配的优先级。
- 流式响应是否还正常。升级后默认配置可能发生变化,比如超时值被重置、流式透传开关被关闭。
- 思考模式字段是否还在透传。这是最容易被升级悄悄改掉的一项,因为它涉及字段裁剪策略。跑一条最短的三轮对话就能验证。
这三项加起来不到三分钟,但能挡掉升级后 90% 的"莫名其妙就不行了"。
注意:升级前把当前可用的配置文件复制一份带日期的备份,比如
config.20250115.json。出问题直接回滚,比对着日志猜快十倍。
5.2 让额度可控:本地优先与用量观察
最后聊聊成本控制,这是长期使用绕不开的话题。不管用的是平台的免费额度还是付费额度,没有观察手段就一定会在某天突然收到"额度已用尽"的提示。
我的做法分三个层次。第一层是默认走本地,把本地模型通道设为日常默认,云端通道只在明确需要时手动切过去。这一条能砍掉大部分无谓消耗,因为大量日常操作根本不需要强模型。第二层是给每个供应商设置独立的模型别名,这样在日志里能清楚看到哪个通道被调用了多少次、每次请求大概多长。第三层是定期看用量,每周花两分钟登录各平台后台看一眼消耗曲线,发现异常增长就立刻查日志定位。
关于平台侧的一些规则,顺带提醒一下:国内几家模型平台在使用高级功能(例如创建 API 密钥、充值、开具发票)以及领取各类活动福利时,通常要求完成实名认证。这是平台侧的合规要求,跟 CC Switch 没有关系,但确实会卡住一部分刚上手的用户——配置全对、就是 403,折腾半天最后发现是账户状态问题。所以遇到 403 的时候,第一件事不是改配置,而是登录平台确认账户状态。
还有个实用的省钱技巧:把"探查性"的请求和非流式请求优先给本地模型。比如让模型解释一段代码、查个 API 用法、生成一段正则,这类请求对推理深度要求不高,本地模型完全能应付。真正需要云端强模型的是复杂重构、跨文件改动、长链路调试这些。按这个原则分配之后,我用云端额度的频率大概降到原来的三分之一,而实际工作效率没受影响。
配置这件事,说白了就是在"省事"和"可控"之间找平衡点。全手动改环境变量最可控但最费事,全自动路由最省事但出问题时最难查。CC Switch 提供的其实是中间那一档,前提是你愿意花半小时把映射规则和日志看懂。我在几台机器之间来回切换项目之后的最大感受是,配置文件写得越简单越好——只做必要的模型名替换,别加花哨的字段变换,因为每一次变换都是一次潜在的丢字段、一次潜在的 400。真正稳定的配置,看起来往往朴素得让人怀疑它是不是少写了什么。