Route Claude Code to third-party models: the env vars that actually matter
以下内容包含AIGC
Claude Code 大概是目前最好用的 coding agent 终端,没有之一。工具链、上下文管理、权限模型、子 agent 编排,这些工程细节是其他同类项目短时间追不上的。而且 CLI 本身免费安装——真正花钱的是背后绑定的 Claude 模型和官方计费。
但现实世界里,很多人手里攥着的是:各大厂商的模型订阅、OpenRouter 余额、公司内网网关、或者各种渠道的中转 API。我之前在内网用 new-api 负载均衡了几个 MiniMax 订阅给外包同事接 Claude Code(旧文:web-search-proxy),模型接入的问题就是这样解决的。协议层面 Claude Code 说的是标准 Anthropic Messages API 格式,任何能翻译这个协议的网关都能接——这条路社区已经走了很久。
先把官方文档原话放在前面:
Anthropic doesn’t endorse, maintain, or audit third-party gateway products, and doesn’t support routing Claude Code to non-Claude models through any gateway.
官方明确不支持把 Claude Code 路由到非 Claude 模型。这是一条没有 SLA 的野路子,版本升级随时可能改变行为,出了问题别找官方,先看 changelog。本文记录的是社区玩法 + 我自己的实践,截至 2026-09,对应 Claude Code v2.1.283。
有一件事值得先说:环境变量写错名字不会报错,不会警告,只会静默失效——你以为是保险的配置,可能从没生效过。所以在配置时要尽可能谨慎确保拼写和拷贝正确。
先从连接和模型映射讲起,再到上下文与成本,最后是终端工作流和两份可以直接抄的配置。
一、配置写在哪:settings.json 的 env 键
所有环境变量都可以写在 ~/.claude/settings.json 的 env 键下,对任何启动方式生效:
1 | { |
配置文件有四个层级,优先级从低到高:
| 文件 | 位置 | 用途 |
|---|---|---|
~/.claude/settings.json |
用户全局 | 个人默认配置 |
.claude/settings.json |
项目根目录 | 入库,团队共享 |
.claude/settings.local.json |
项目根目录 | 不入库,个人覆盖 |
| managed settings | 系统级 | 组织统一下发 |
几个容易想当然的规则:
- settings 里的
env会覆盖 shell 里导出的同名变量。排查“为什么这个值不生效”时,先检查 settings,再看 shell。 - settings 里无法 unset 一个变量。要顶掉一个别处设置、自己又删不掉的变量,设为空串:
"CLAUDE_CODE_USE_VERTEX": ""。 - 布尔变量一般
1/true开、0/false关。但有一类变量只看“是否被设置”:只要非空就算开启,写"0"也是开。后文的CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC就是典型,要关只能删掉这行。 - 数值变量从 v2.1.211 起支持
2e3、64_000这类写法,但个别变量只认纯整数,比如CLAUDE_CODE_AUTO_COMPACT_WINDOW写500k会被读成500。 - JSON 没有注释。网上流传的配置示例里的
//注释直接抄进去会整个文件解析失败。我的做法是给想“注释掉”的变量名加两个下划线后缀:
1 | { |
CLAUDE_CODE_USE_POWERSHELL_TOOL__ 是一个 Claude Code 根本不认识的变量,等于这行配置不存在,但留在文件里方便随时改回来。这是我认为最不脏的 JSON 注释替代方案。
二、连接层:把 Claude Code 指向你的网关
最小可用配置只需要两个变量:
| 变量 | 作用 |
|---|---|
ANTHROPIC_BASE_URL |
API 端点,指向代理/网关地址 |
ANTHROPIC_AUTH_TOKEN |
自定义 Authorization: Bearer <值> 头,绝大多数网关(new-api 系)用这个 |
ANTHROPIC_API_KEY |
以 X-Api-Key 头发送;设置后会压过订阅登录,交互模式首次会提示确认 |
ANTHROPIC_CUSTOM_HEADERS |
追加自定义请求头,Name: Value 格式,多个用换行分隔,需 v2.1.227+ |
ANTHROPIC_BETAS |
追加 anthropic-beta 头的值,逗号分隔 |
一个真实的坑:只设 ANTHROPIC_BASE_URL 而不设网关凭据时,已保存的 claude.ai 登录仍然是有效凭据——请求确实走了你的网关地址,但鉴权用的还是订阅账号,计费照旧。想“纯走第三方”,ANTHROPIC_AUTH_TOKEN 或 ANTHROPIC_API_KEY 必须一起设。
ANTHROPIC_CUSTOM_HEADERS 有个高发事故:从头网页或聊天窗口复制配置时混入弯引号、零宽空格这类 HTTP 头不允许的字符,请求会直接失败。报错会标出问题键值对的位置,遇到“Header无效”先检查不可见字符。
还要知道两个副作用:ANTHROPIC_BASE_URL 指向非官方主机时,MCP tool search 默认关闭(所有 MCP 工具全量加载,网关必须转发 tool_reference 块才值得设 ENABLE_TOOL_SEARCH=true);v2.1.196 起 Remote Control 也被禁用。
三、模型映射:四个别名槽位
接非 Claude 模型的核心是一组 ANTHROPIC_DEFAULT_* 变量。Claude Code 内部有 opus / sonnet / haiku / fable 四个别名,分别可以重定向:
| 变量 | 作用 |
|---|---|
ANTHROPIC_MODEL |
当前使用的模型 |
ANTHROPIC_DEFAULT_OPUS_MODEL |
opus 别名指向的模型;opusplan 在 Plan Mode 下用它 |
ANTHROPIC_DEFAULT_SONNET_MODEL |
sonnet 别名指向的模型;opusplan 执行阶段用它 |
ANTHROPIC_DEFAULT_HAIKU_MODEL |
haiku 别名;同时驱动所有后台功能 |
ANTHROPIC_DEFAULT_FABLE_MODEL |
fable 别名;第三方 provider 上的自动模型回退靠它识别 |
ANTHROPIC_SMALL_FAST_MODEL |
已废弃,被 ANTHROPIC_DEFAULT_HAIKU_MODEL 取代 |
优先级:--model 参数和 /model 命令覆盖 ANTHROPIC_MODEL,ANTHROPIC_MODEL 优先于 settings 里的 model 字段。
我的一套映射长这样:
1 | { |
思路就是三档映射:主力模型顶在 opus 和默认位,次一档给 sonnet,最便宜的塞给 haiku。日常 /model 一敲就能在几档之间切换,Plan Mode 的 opusplan 也会自动落到正确的档位。aihub/gpt-6.1-sol 这种写法是“网关名/模型名”的路由格式,具体命名以你的网关为准。
最容易被漏掉的是 HAIKU 这一行。它管的不只是 /model 菜单里的 haiku 选项,还有后台任务(后台 token 消耗走的就是这个别名)。不设的话,Claude Code 会向网关请求一个你的网关根本不存在的 haiku 模型名,后台任务要么静默失败,要么落到完全不合预期的模型上。第三方用户十条故障有两条半出自这里。
另外两个值得知道的:
CLAUDE_CODE_SUBAGENT_MODEL:给子 agent、agent team 队友、workflow agent 指定默认模型(v2.1.251 起优先级语义有调整,另有CLAUDE_CODE_SUBAGENT_MODEL_FORCE强制统一)。想让子 agent 烧便宜模型的,看这个。- 模型重定向这种事,交给网关做比在客户端折腾强。我的 new-api 上配好几条路由,Claude Code 这边一套 settings.json 从不改——这也是我觉得 cc-switch 这类客户端切换工具纯属多余的原因:网关侧换模型,客户端零改动。
四、把 /model 菜单收拾干净
映射完模型,/model 选择器里显示的还是一串裸 ID。一组显示类变量可以把它收拾得像个人样:
| 变量 | 作用 |
|---|---|
ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU,FABLE}_MODEL_NAME |
选择器里显示的名称 |
ANTHROPIC_DEFAULT_{...}_MODEL_DESCRIPTION |
选择器里的描述 |
ANTHROPIC_DEFAULT_{...}_MODEL_SUPPORTED_CAPABILITIES |
能力声明,逗号分隔,如 effort,thinking |
ANTHROPIC_CUSTOM_MODEL_OPTION(+ _NAME / _DESCRIPTION) |
往选择器追加一个自定义条目,不替换内置别名 |
更省事的是直接让网关自己报模型清单:CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 会让 Claude Code 从网关的 /v1/models 端点拉取模型填充 /model 选择器,new-api、LiteLLM、Kong 这类网关都支持。这个发现是 opt-in 的,不受后文“关闭非必要流量”的影响。
五、超时与流式:给慢网关续命
| 变量 | 作用 |
|---|---|
API_TIMEOUT_MS |
单次 API 请求超时,默认 600000(10 分钟),上限 2147483647——超过上限会因定时器溢出立即失败 |
API_FORCE_IDLE_TIMEOUT |
流式响应 5 分钟无字节则中止。非官方 API 上默认开启;慢网关/本地模型设 0 关闭 |
CLAUDE_STREAM_IDLE_TIMEOUT_MS |
流空闲 watchdog 超时 |
CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS |
字节级 watchdog,优先于上一项(v2.1.210+) |
CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS |
首字节超时(取代 v2.1.186 起已移除的 CLAUDE_CODE_CONNECT_TIMEOUT_MS) |
CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS |
子 agent 无进展超时,默认 600000 |
第三方网关的典型症状是排队:高峰期首 token 等一分钟很常见,本地大模型更慢。默认值按官方 API 的响应速度设计,在网关上容易触发各种 watchdog 把正常的慢连接掐断。如果经常看到流式响应中断,先调这一组。
六、上下文窗口与自动压缩:省钱的主战场
这一节是第三方用户最值得花时间的地方,因为上下文就是钱:按 token 计费的网关上,每一轮请求都要重新发送整个对话历史,缓存命中不理想的情况下,上下文越长,每一轮的输入费用越高,而且是线性上涨。
校正上下文窗口:CLAUDE_CODE_MAX_CONTEXT_TOKENS
Claude Code 对每个模型 ID 都有一个“假定的上下文窗口”。网关路由的模型(比如 aihub/gpt-6.1-sol)它不认识,假定值很可能跟真实窗口对不上——窗口报小了会过早压缩浪费上下文,报大了会撑爆上游。用这个变量校正,上下文达到阈值时会自动触发压缩:
1 | { |
行为细节(v2.1.193 起)取决于模型 ID 怎么被解析,分三种情况:
- ID 不以
claude-开头且不含[1m](网关路由名的常态):变量直接生效,按你声明的窗口做主动压缩。最简单的情况。 - ID 含
[1m]:Claude Code 直接假定 1M 窗口,本变量不单独生效;要校正需同时设CLAUDE_CODE_DISABLE_1M_CONTEXT=1。 - ID 能解析出它认识的 Claude 模型(比如
anthropic/claude-opus-5):本变量只在同时设了DISABLE_COMPACT时才生效。
提早触发压缩:CLAUDE_AUTOCOMPACT_PCT_OVERRIDE
1 | { |
设定自动压缩触发的窗口百分比(1-100),只能提前、不能延后,高于默认阈值的值会被忽略。对主对话和子 agent 都生效。
我设 36:272K 的窗口大约用到 98K 就压缩。配合按 token 计费的网关,这是最直接的成本控制手段——单轮输入 token 直接砍掉一大截。代价是压缩有信息损失,长任务的上下文记忆会被折衷掉,这个值是成本和记忆力的折中,按自己的账单调。
两个提醒:社区有过在 settings.json env 里设这个变量不生效的 issue 报告,别盲信,用 /context 看窗口实际占用验证一下;另外如果更喜欢绝对数值,CLAUDE_CODE_AUTO_COMPACT_WINDOW 直接按 token 数(100000~1000000)设压缩窗口,但它只认纯整数,且设置后状态栏的 used_percentage 就不再指示压缩时机了。
输出上限:CLAUDE_CODE_MAX_OUTPUT_TOKENS
对无法识别的模型 ID,单次输出上限默认 32000、最大 128000。调高它会让触发自动压缩前的有效窗口变小,跟上一条是跷跷板。除非模型经常写长文被截断,否则不用动。
七、网关兼容性开关
这一组变量解决的是“Claude Code 发的请求,网关看不懂”的问题。
CLAUDE_CODE_ATTRIBUTION_HEADER:缓存杀手
这是我最想安利的一条。Claude Code 默认在 system prompt 开头放一个 attribution 块,携带客户端版本号和 prompt 指纹。设为 0 可以去掉它:
1 | { |
为什么第三方用户应该关心:如果你的网关按请求体做前缀缓存(或者把请求转发给第三方 provider 再缓存),这个块会让缓存策略出问题。历史上(v2.1.181 之前)它在自定义 base URL 上还带一个每请求变化的 token,直接把前缀缓存打得稀碎,当时这行是刚需。现在块本身稳定了,但“网关按请求体缓存/转发第三方”的场景,官方文档仍然建议设 0。
其他兼容开关
| 变量 | 什么时候用 |
|---|---|
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 |
网关报 Unexpected value(s) for the anthropic-beta header 或 Extra inputs are not permitted 时,剥离 Anthropic 专属 beta 头和 beta schema 字段。代价是 MCP tool search 被一并关闭 |
CLAUDE_CODE_DISABLE_THINKING=1 |
网关拒绝 thinking 参数时的兼容开关,整个参数不发。第三方 provider 上它和 MAX_THINKING_TOKENS=0 等价 |
CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 |
网关上的自定义模型名支持 effort 参数但 Claude Code 不认识这个 ID 时,强制发送 effort |
ENABLE_TOOL_SEARCH=true |
网关能转发 tool_reference 块时,恢复 MCP tool search |
DISABLE_PROMPT_CACHING=1 |
上游不支持缓存字段、直接报错时关掉 prompt caching(另有按模型的 _FABLE 等变体) |
排障顺序建议:网关报 4xx 且报错信息带 beta、extra inputs、thinking 字样,先从这张表里找对症的开关,一个一个试,别一次全开——全开会掩盖真正的问题。
八、流量、遥测与版本锁定
1 | { |
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 是个省心开关,一并关闭:自动更新、遥测、错误上报、/feedback、release notes 拉取、PR 状态徽标检查、fast mode 可用性检查、插件命令的后台重跑。第三方网关用户基本应该开着——这些流量要么发往官方端点(在内网环境直接报错刷屏),要么没有意义。
再强调一次这个坑:这类变量只看是否被设置,写 "0" 也是开。想关掉就删掉这一行。另外它会让 feature-flag 拉取失效,Remote Control 等依赖它的功能随之不可用(不过走第三方网关时 Remote Control 本来就被禁用了,无所谓)。
其他几个按需:
| 变量 | 作用 |
|---|---|
DISABLE_TELEMETRY |
只关遥测,同为“设置即生效”型 |
DISABLE_ERROR_REPORTING |
只关错误上报,同上 |
DISABLE_INSTALLATION_CHECKS=1 |
屏蔽安装位置检查的警告,手动管理安装时用 |
DISABLE_AUTOUPDATER=1 |
关自动更新,手动 claude update 仍可用;需要彻底锁版本(网关兼容性经常绑版本)用更狠的 DISABLE_UPDATES=1 |
DISABLE_COST_WARNINGS=1 |
关费用警告 |
九、Windows 用户:离 PowerShell 远一点
个人经验,血泪教训:PowerShell 工具的编码问题非常烦人,尽量在 Git Bash 里启动 Claude Code。
官方的默认行为其实是友好的:Windows 上装了 Git Bash 时,shell 命令默认路由经过 Git Bash,而不是 PowerShell。CLAUDE_CODE_USE_POWERSHELL_TOOL=1 才会启用原生 PowerShell 工具(0 禁用);Windows 上没装 Git Bash 时它会被自动启用——所以 Git Bash 值得装。找不到 Git Bash 时用 CLAUDE_CODE_GIT_BASH_PATH 指定 bash.exe 的完整路径。
顺带一个终端玄学:Windows 终端里 Backspace 删整词删到崩溃的,CLAUDE_CODE_BS_AS_CTRL_BACKSPACE=0 专治此问题。
十、终端工作流:用 Herdr 一个 Tab 管一个项目
配置聊完,说个使用体验层面的加分项。
Claude Code 用多了会有个终端管理问题:主任务在跑,突然想问个只读的问题(“这个函数在哪被调用?”),不想打断主会话(也不想用 /btw 命令污染自己的视觉空间),就再开一个终端标签;前端要 run dev,再开一个;后端也要,再开一个。一个项目四五个标签页来回切,切着切着就迷失了——而且哪天直接关掉终端窗口,nohup 出去的 dev server 全变成孤儿进程,下次端口占用排查半小时。
Herdr 就是为这种场景做的:一个 tmux 式的终端复用器,官方口号是 “the runtime your coding agents live on”。它按 workspace / tab / pane 组织终端,天生 agent-aware,能感知 pane 里 Claude Code 这类 coding agent 的状态;pane 跑在一个后台服务上,关掉客户端甚至断掉 SSH,进程都还活着。
我现在的本地开发布局是一个项目一个 Tab,内部四个 Pane:
1 | ┌──────────────────┬──────────────────┐ |
两个 Claude Code 会话各司其职:左边专心改代码,右边随时问问题、看代码、做分析,互不打断;两个 dev server 在各自的 pane 里前台跑——不 nohup、不放后台,pane 的生命周期就是进程的生命周期,关 pane 即关服务,从此没有孤儿进程。一屏之内全部可见,不用再切标签页。这是我目前用下来最舒服的本地开发组合。
更高阶:让 Claude Code 自己操作 Herdr
上面的布局解决的是“人怎么看”的问题,还有一个“Agent 怎么干活”的问题:开发中经常要重启 dev server——装了新依赖、改了配置、加了环境变量。没有这层配合时,要么我手动切到对应 pane 按 Ctrl+C 再敲一遍 npm run dev,要么让 Claude Code 在自己的 shell 里把服务起在后台——又绕回孤儿进程的老路。
Herdr 配套了官方 Skill(仓库里的 skills/herdr/SKILL.md),一条命令安装:
1 | npx skills add herdrdev/herdr --skill herdr -g |
装好之后,主开发会话里的 Claude Code 就能反过来操作 Herdr。它需要重启服务时,会自己查询当前 workspace 的 pane 状态,定位前端/后端所在的 pane,向目标 pane 发送 Ctrl+C 结束旧的 npm run dev,再把命令重新跑起来,并盯着输出确认服务就绪。整个过程它自己完成,我不用碰键盘。Skill 教给 agent 的命令面大概长这样:
1 | herdr pane list --workspace "$HERDR_WORKSPACE_ID" # 查状态,定位目标 pane |
安全设计值得一提:Skill 的第一条规则是检查 HERDR_ENV=1——只有确认自己真的跑在 Herdr 管理的 pane 里,才会去碰本地 Herdr socket,防止 pane 外面的 agent 误操作不属于它的会话。
这一步的妙处是职责分清了:dev server 始终在 pane 里前台跑,生命周期归 Herdr 管;Claude Code 通过 Skill 拿到的是对 pane 的操作权——需要重启时精准重启,不需要时互不干扰。Agent 从“住在终端里的房客”,变成了握着房间钥匙的管家。完整的命令参考在 SKILL.md(也可以 herdr --skill 直接打印随二进制发布的版本)和官方文档。
Herdr 是 Rust 写的,开源在 GitHub,tmux 式前缀键和鼠标点击操作都支持,还有 CLI 可以编程控制 workspace / tab / pane。配合后台服务器特性,在 VPS 上远程开发也是同一套玩法。
十一、附录
方案 A:Claude 名称模型经网关(重点控成本)
1 | { |
方案 B:非 Claude 模型经网关
1 | { |
静默失效排查清单
环境变量配置的第一定律:它不生效的时候不会告诉你。怀疑配置没起作用时按这个顺序查:
- 变量名拼写。逐字符对照官方文档,不存在“差不多的名字”——拼错不会报错,只会静默失效。
- “设置即生效”型变量,检查是不是写了
"0"想关闭——那是开启。删行才叫关闭。 - 数值单位。
500k在有的变量里是 500,在有的变量里根本非法。 - settings 的
env覆盖 shell 环境变量,两边都设了时以 settings 为准。 - 版本行为差异。attribution 块(v2.1.181 前后)、
MAX_CONTEXT_TOKENS的三种生效情形(v2.1.193 起)、Remote Control 禁用(v2.1.196 起)都是版本敏感的。 - 用
/context、/status、/model实际验证,别盲信配置文件。
参考
如果你也在搭自己的 Agent 基础设施,希望这份核对过的清单能帮你省下“配置看起来对但就是不对”的那几个小时。有错漏欢迎评论区指正——毕竟连官方文档都是跟着版本跑的,这篇也一样。