省流:一句 prompt 让 Claude Code 自己配好

想看清楚为什么非要走 --settings 不可,继续往下读。

背景

我平时 claude 命令走的是中转站(~/.claude/settings.jsonenv 块里配了 ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN)。想加一个 claudex 命令,专门切到中转站上的 GPT 模型(gpt-5.6-sol 当主模型,haiku 位置本想用 gpt-5.6-luna,但调不通,改用 gpt-5.6-terra),但不想动 settings.json 里正在用的主配置。

第一版思路很直觉:写个 zsh alias,用环境变量前缀覆盖:

alias claudex='ANTHROPIC_BASE_URL=https://your-proxy.example.com \
  ANTHROPIC_AUTH_TOKEN=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
  ANTHROPIC_MODEL=gpt-5.6-sol \
  claude --model gpt-5.6-sol'

看起来没问题——shell 里 VAR=value command 这种前缀写法,理论上应该只在这一次调用里生效,覆盖掉继承来的环境变量。

问题

实测下来,claudex 发出去的请求用的还是 settings.json 里原来的 token,新 token 完全没生效。

排查后发现:Claude Code 启动时会把 ~/.claude/settings.jsonenv 字段的内容主动写回自己的进程环境,而且是无条件覆盖,不只是”没设置才补全”。也就是说:

  • 你在 shell 里 export 或者用前缀语法传的 ANTHROPIC_AUTH_TOKEN / ANTHROPIC_BASE_URL
  • 会先被继承进 claude 进程
  • 但紧接着又被 settings.jsonenv 块原样覆盖回去

这是有意为之的设计(大概率是为了让企业/团队的策略配置始终优先,不被本地 shell 环境意外顶掉),但对我这种”临时切一下模型”的场景就很不友好——shell 层面的覆盖直接失效。

修复思路

claude --help 里有个 --settings <file-or-json> 参数,专门用来在启动时额外加载一份设置,优先级比用户级 settings.json 高。把中转站的 base_url、token、模型相关的 env 都塞进这份内联 JSON,而不是塞进 shell 环境变量:

alias claudex='CLAUDE_CODE_SUBAGENT_MODEL=gpt-5.6-sol \
  CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 \
  CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY=3 \
  ENABLE_TOOL_SEARCH=false \
  claude --settings "{\"env\":{\"ANTHROPIC_BASE_URL\":\"https://your-proxy.example.com\",\"ANTHROPIC_AUTH_TOKEN\":\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\"ANTHROPIC_MODEL\":\"gpt-5.6-sol\",\"ANTHROPIC_DEFAULT_SONNET_MODEL\":\"gpt-5.6-sol\",\"ANTHROPIC_DEFAULT_OPUS_MODEL\":\"gpt-5.6-sol\",\"ANTHROPIC_DEFAULT_HAIKU_MODEL\":\"gpt-5.6-terra\"}}" \
  --model gpt-5.6-sol'

其中 gpt-5.6-sol 是 sonnet/opus 都对应的主模型,haiku 本来想配 gpt-5.6-luna,但中转站上这个模型调不通,退而求其次用 gpt-5.6-terra,成本也没上升多少——具体用哪个模型名,看你中转站上暴露的模型别名,替换掉即可。

要点:

  • CLAUDE_CODE_SUBAGENT_MODEL / CLAUDE_CODE_ALWAYS_ENABLE_EFFORT 这类不属于 settings.json env 覆盖范围的变量,还是可以用普通 shell 前缀传,只影响这一次调用。
  • 真正会被 settings.json 抢回去的(ANTHROPIC_BASE_URLANTHROPIC_AUTH_TOKENANTHROPIC_MODEL 及三个 ANTHROPIC_DEFAULT_*_MODEL),一律走 --settings 内联 JSON。
  • ~/.claude/settings.json 本身完全不用动,平时的 claude 命令行为不受影响。

验证

  1. source ~/.zshrcalias claudex 确认定义生效。
  2. 新终端跑 claudex,进去用 /status 看当前 base URL 和 model——应该显示中转站地址和目标模型,而不是 settings.json 里的默认值。
  3. 另开一个终端跑普通 claude,确认还是走原来的 token 和默认模型,没被 claudex 的配置污染。

题外话

这类”我传的环境变量为什么没生效”的坑,本质都是优先级链路不透明:CLI 参数、shell 环境变量、用户级配置文件、项目级配置文件之间到底谁盖谁,得靠 --help 或实测才能确认,不能想当然地认为”离执行最近的赋值优先级最高”。遇到类似问题,先想办法验证优先级(比如故意传一个能观察到的值),再决定往哪一层写配置。