claude-code-custom-model-per-directory · ZH · 2026-10-26

按仓库给 Claude Code 换后端:在同一把聚合站 key 上做目录级模型路由

介绍如何让 Claude Code 按启动目录选择不同后端,同时共用聚合站的一把 API key:用目录级的轻量包装脚本读取配置文件、注入对应的 base URL 与模型名,并说明跨目录切换会话时的注意点与验证方法。

Claude Code 的默认行为是全局读一份配置:ANTHROPICBASEURL、ANTHROPICAUTHTOKEN(或 ANTHROPICAPIKEY)以及模型名。多数人并不想为每个工程各维护一套 key,尤其在使用聚合站时,一把 key 就能调多个模型。这里要解决的只是另一件事:让「启动 Claude Code 时所在的目录」决定它连哪个后端、用哪个模型,而 key 始终是同一把。

先分清三层概念

  • 凭据(key):身份与计费主体,通常全局唯一。聚合站的 key 可以在多个模型间复用,因此不需要按目录拆分。
  • 端点(base URL):请求发往哪里。同一把 key 下,端点通常不变。
  • 模型与参数:真正会随工程变化的部分,比如这个仓库偏好长上下文模型,那个仓库偏好推理型或更便宜的模型。

所以「按目录换后端」在实践中多数是按目录换模型与少量请求参数,端点与 key 共用。只有当你想让某些目录走直连官方、另一些走聚合站时,才需要端点级切换。

用目录级配置文件描述意图

在每个工程根目录放一个纯文本配置文件(不要提交到共享仓库,或按团队约定处理)。内容只描述差异,不含密钥:

# .claude-backend
MODEL=claude-sonnet-4-5
SMALL_MODEL=claude-haiku-4-5
MAX_OUTPUT_TOKENS=8192

另一个仓库可以写成 MODEL=deepseek-chat,第三个写成 MODEL=qwen-max。key 不写在这里,而是从环境变量或上一级私有配置读取,避免把凭据散落到几十个仓库中。

加一层很薄的包装

思路是:一个脚本从当前工作目录向上查找最近的那个配置文件,导出对应环境变量,然后 exec 真正的 Claude Code 进程。伪代码大致如下:

#!/usr/bin/env bash
set -euo pipefail

# 全局凭据,来自你的 shell 环境或私有 rc 文件
: "${AGGREGATOR_API_KEY:?需要先设置 AGGREGATOR_API_KEY}"
export ANTHROPIC_AUTH_TOKEN="$AGGREGATOR_API_KEY"
export ANTHROPIC_BASE_URL="https://你的聚合站端点"

# 从当前目录向上找最近的 .claude-backend
dir="$PWD"
cfg=""
while [ "$dir" != "/" ]; do
  if [ -f "$dir/.claude-backend" ]; then cfg="$dir/.claude-backend"; break; fi
  dir="$(dirname "$dir")"
done

if [ -n "$cfg" ]; then
  # 逐行读取 KEY=VALUE,仅接受白名单键
  while IFS='=' read -r k v; do
    case "$k" in
      MODEL) export ANTHROPIC_MODEL="$v" ;;
      SMALL_MODEL) export ANTHROPIC_SMALL_FAST_MODEL="$v" ;;
      MAX_OUTPUT_TOKENS) export CLAUDE_CODE_MAX_OUTPUT_TOKENS="$v" ;;
    esac
  done < "$cfg"
fi

exec claude "$@"

要点有三:

  • 白名单:只接受你认识的键,避免配置文件意外注入其他环境变量。
  • 向上查找:在子目录里启动也能命中仓库根的配置,不必每次都回到根目录。
  • exec:让 Claude Code 取代包装脚本成为前台进程,信号和退出码直通,Ctrl-C 行为正常。

把这个脚本命名为 cc 或 ccd,放进 PATH 即可。之后在哪个仓库里敲 cc,就自动带上该仓库的模型选择。

为什么不用 alias 硬编码

alias 绑定的是固定字符串,无法随目录变化;即使写函数去判断路径,也容易随着仓库增多而膨胀成一张难维护的映射表。目录内配置文件的好处是:工程自己的选择跟着工程走,克隆下来就能用,review 时也看得见它选了什么模型。

跨目录与会话延续的注意点

这是最容易出问题的地方:

  • 会话恢复不会重读配置。claude --continue / --resume 恢复的是历史消息,模型若在启动时被换掉,上下文仍在但后续生成的风格和质量可能变化。跨仓库恢复旧会话时,建议新开会话,而不是强行续接。
  • 路径依赖的工具调用。Claude Code 会读写当前工作目录下的文件。在 A 仓库启动、中途 cd 到 B 仓库,工具仍按新的相对路径工作,但后端配置不会跟着变。要么在目标目录重新启动,要么显式接受这次会话仍用 A 的模型。
  • 子代理与工具调用的模型。主模型与「小模型」(用于摘要、命名等轻量任务)是两条独立的设置,只改主模型会留下不一致;把两者都写进配置文件更稳妥。
  • 长上下文差异。不同模型上下文窗口不同,跨模型恢复一段很长的历史可能直接超出上限,表现为请求失败而非静默截断,先确认再续接。

验证配置是否真的生效

不要凭感觉判断。启动后先在会话里问一句「你现在使用的模型标识是什么」,或让它复述一次简单指令观察响应特征;也可以在包装脚本里加一个 --dry-run 分支,只打印最终生效的环境变量而不启动进程。对计费敏感的话,到聚合站的使用记录里核对这条请求落在了哪个模型上——这是最可靠的确认方式。

共用一个 key 时的成本认知

聚合站按官方价 ×1.3 计费,贡献 key 按 ×1.1(优质 ×1.2)返 USDC 结算。也就是说,目录级路由优化的是选哪个模型,而不是绕开计费;把轻量任务指向便宜模型,是在这个倍率之上再做的一层节约。不要指望通过换端点或换 key 改变单价。

小结

  • key 与端点通常全局共用,按目录变化的是模型和少量参数。
  • 用「向上查找的目录配置文件 + 薄包装脚本 + exec」实现,保持白名单与最小差异。
  • 会话恢复、跨目录 cd、主/小模型一致性、上下文窗口是四个主要坑点。
  • 用使用记录核对生效模型,比凭观感判断可靠。