同一条 claude 命令,背后可能跑在两种完全不同的账上:订阅账号的用量额度,或 Anthropic 平台的 API 计费。前者适合人坐在终端前写代码,后者适合 CI、脚本、团队统一网关。选错不是功能不能用,而是账单会以你没预料的方式出现——最常见的是"以为在走公司网关,其实一直在扣自己的订阅"。
这篇按 选 → 配 → 隔离 → 验证 → 排错 五段走。
1. 两条认证路径:差别不在功能,在账
| 维度 | 订阅登录(OAuth) | API key |
|---|---|---|
| 身份载体 | 浏览器授权后落在本机的凭据 | ANTHROPIC_API_KEY 字符串 |
| 计费方式 | 计入订阅套餐的用量额度 | 按 token 计入平台账单 |
| 用尽时表现 | 额度/速率限制提示,等窗口重置 | 429,平台侧配额见底 |
| 模型范围 | 随订阅档位变化 | 随平台账号权限与区域 |
| 多机使用 | 每台机器各登录一次 | 一把 key 可分发,配合网关更好 |
| 无人值守(CI、cron) | 不适合,需要交互授权 | 适合 |
判断口诀:有活人坐在终端前 → 订阅登录;无人值守、多人共享、要审计 → API key 或企业网关。 两条路径可共存,谁生效看第 3 节的优先级,不是"后配的赢"。
2. 四个环境变量各自管什么
| 变量 | 管什么 | 细节 |
|---|---|---|
ANTHROPIC_API_KEY |
认证,请求头 x-api-key |
与下面那个 token 是两条认证路线,别同时给 |
ANTHROPIC_AUTH_TOKEN |
认证,请求头 Authorization: Bearer <token> |
自建网关、中转服务常用这条 |
ANTHROPIC_BASE_URL |
请求发往哪里 | 只写到域名/前缀,/v1/messages 由客户端拼 |
ANTHROPIC_MODEL |
主模型标识 | 服务端不认识的 id 会返回 404,不是 400 |
export ANTHROPIC_API_KEY='sk-ant-...'
export ANTHROPIC_BASE_URL='https://api.anthropic.com'
export ANTHROPIC_MODEL='MODEL_ID' # 用账号实际可用的 id,不要照抄旧文章
两个容易忽略的点:ANTHROPIC_BASE_URL 多写路径是最高频的 404 来源(写 .../v1 就会被拼成 /v1/v1/messages);子任务通道(生成标题、压缩上下文)的变量名与主模型不同,各版本改过名,配前按当前版本核对。
3. 谁覆盖谁:优先级与合并语义
| 优先级 | 位置 | 作用范围 | 典型用途 |
|---|---|---|---|
| 0(最高) | 企业管理策略 | 全机、所有项目 | 公司统一网关,普通用户改不动 |
| 1 | 进程环境变量 | 当前 shell 及其子进程 | 临时切换、CI 注入 |
| 2 | .claude/settings.local.json |
本项目、仅自己,不进 git | 个人覆盖、本机路径 |
| 3 | .claude/settings.json |
本项目、进 git,团队共享 | 团队约定 |
| 4 | ~/.claude/settings.json |
当前用户所有项目 | 个人默认值 |
两条结论要记住:
- 认证类变量以进程环境为准。 shell 里
export的 key 压过 settings 的env同名键;"临时换一把 key 跑一次"用前缀式赋值,不碰文件。 - settings 文件之间是"项目覆盖用户",跟"用户设置更高"的直觉相反:用户级放默认值,项目级放例外。
{
"env": {
"ANTHROPIC_BASE_URL": "https://llm-gateway.corp.example.com/anthropic",
"ANTHROPIC_MODEL": "MODEL_ID"
}
}
这段只该出现在 settings.json / settings.local.json 里,key 不要写进去——项目级配置跟着仓库走,等于把密钥提交到 git。
4. 多项目多 key:三种隔离
4.1 direnv:进目录自动切换
# .envrc(可提交,只放非敏感项;密钥放 .envrc.local 并 gitignore)
export ANTHROPIC_BASE_URL="https://gw-a.example.com"
export ANTHROPIC_MODEL="MODEL_ID"
[ -f .envrc.local ] && source .envrc.local
direnv allow .
好处是进入目录即切、离开即还原。代价是新机器要重新 allow,忘了就会莫名用上全局 key。
4.2 shell 函数:一行前缀,最轻
cc-a() { ANTHROPIC_API_KEY="$(security find-generic-password -s anthropic-a -w)" claude "$@"; }
cc-b() { ANTHROPIC_API_KEY="$(security find-generic-password -s anthropic-b -w)" claude "$@"; }
Linux 上换成 secret-tool lookup service anthropic key a。密钥只存在于该进程环境,history 里只有函数名。
4.3 独立 settings.local.json:按仓库固化网关
{ "env": { "ANTHROPIC_BASE_URL": "https://gw-c.example.com", "ANTHROPIC_MODEL": "MODEL_ID" } }
把网关锁在仓库里(不进 git),换机器只需补 key。
| 做法 | 隔离粒度 | 密钥存放 | 适合 | 缺点 |
|---|---|---|---|---|
| direnv | 目录 | 密码管理器/文件 | 长驻项目、多仓库 | 新机器要重新 allow |
| shell 函数 | 命令 | 系统钥匙串 | 频繁切换、临时会话 | 要记函数名 |
| settings.local.json | 仓库 | 环境变量 | 团队共用同一网关 | 只管非敏感项 |
三种可以叠:项目级定网关,个人 key 走钥匙串,CI 走 secrets。
5. 额度与限流的报错形态
| 现象 | 常见原因 | 应对 |
|---|---|---|
401 / invalid x-api-key |
key 错、已吊销,或 key 与 base_url 不匹配 |
成对检查:哪把 key 配哪个网关 |
403 / permission |
账号无该模型权限、区域限制 | 换模型或让管理员开权限 |
404 / model not found |
ANTHROPIC_MODEL 写错,或 base_url 多了路径 |
用服务端模型列表核对 |
429 rate_limit_error |
订阅额度撞顶,或平台 RPM/TPM 超限 | 退避重试、降并发、换小模型 |
| 连接超时 / TLS 错误 | 企业代理拦截、根证书不全 | 指定 NODE_EXTRA_CA_CERTS |
| 长时间无输出后断开 | 网关缓冲了 SSE 流,或超时太短 | 网关侧关缓冲、调长超时 |
先用一条 curl 把"客户端问题"和"服务端问题"分开:
curl -sS "$ANTHROPIC_BASE_URL/v1/models" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" | head -40
curl 通、Claude Code 不通 → 客户端配置或登录态;两个都不通 → key / 网关 / 网络。
6. 企业网关 / 代理接入的注意点
| 点 | 说明 |
|---|---|
| base_url 形态 | 只到前缀,不带 /v1/messages;网关要求带前缀(如 /anthropic)就照网关文档写 |
| 头部透传 | anthropic-version、anthropic-beta 必须透传,否则 beta 能力静默失效 |
| 流式响应 | SSE 必须边收边转,整包缓冲会表现成"卡住不出字" |
| 超时 | 网关默认 60s 常把长任务掐断,调到几分钟量级 |
| 认证方式 | 网关多用 Bearer,用 ANTHROPIC_AUTH_TOKEN,别塞 ANTHROPIC_API_KEY |
| 证书 | 企业自签根证书走 NODE_EXTRA_CA_CERTS=/path/ca.pem,别全局关校验 |
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-root.pem
export ANTHROPIC_AUTH_TOKEN="$GATEWAY_TOKEN"
export ANTHROPIC_BASE_URL="https://llm-gateway.corp.example.com/anthropic"
export ANTHROPIC_MODEL="MODEL_ID"
网关侧记三样:调用方标识、模型 id、token 用量——客户端日志只能证明"我发了"。
7. 密钥不落盘:四条硬约束
- 不进仓库。
settings.json、.env、.envrc都不写 key;.gitignore覆盖.env*、.claude/settings.local.json。 - 不进 shell history。 交互输入加前缀空格(
HISTCONTROL=ignorespace)或临时关历史。 - 不进
ps。 命令行参数在ps里是明文;环境变量只对同用户可见。 - 不进聊天与工单。 截图、粘贴配置前先过一遍。
# 不回显、不进 history 的读入方式
read -r -s -p "key: " ANTHROPIC_API_KEY; echo
export ANTHROPIC_API_KEY
8. 切换之后怎么确认真的生效
配置对不对不看文件,看会话里的模型标识和网关侧有没有收到请求。
| 验证点 | 看哪里 | 正常表现 |
|---|---|---|
| 模型标识 | 会话内 /status 或界面状态行 |
显示的就是你设置的 id 或网关别名 |
| 单次请求 | claude -p 'ping' 后看网关日志 |
日志有新请求,来源是你的机器 |
| 认证头 | 网关侧抓 header | x-api-key 或 Authorization: Bearer,只出现一个 |
| 计费归属 | 平台 usage 页面 | 对应 key 的用量在涨,订阅额度不动 |
env | grep -i anthropic # 先确认这个 shell 到底有什么
claude -p 'reply with ok' # 发一次最小请求,再去网关日志对时间
/status 仍显示订阅账号、网关日志没请求,说明登录态优先:显式设 key 后仍不生效,先退出登录再重开。
9. 排错:六个高频坑
| 现象 | 原因 | 处理 |
|---|---|---|
| 换了 key 行为没变 | 同 shell 有旧 export;或变量没传到子进程 | env | grep ANTHROPIC,必要时 exec $SHELL |
| IDE 内置终端里配置不生效 | GUI 启动的 IDE 不继承登录 shell 的环境 | 从终端启动 IDE,或在 IDE 设置里显式配 |
| 401 但 key 确实有效 | key 与 base_url 不配对(A 平台 key 发到 B 网关) | 成对核对,别单独验 |
| 404 model not found | 模型 id 拼错、大小写不符,或 base_url 带了 /v1 |
用服务端模型列表比对,去掉多余路径 |
| 429 但平台显示额度充足 | 撞的是 RPM/TPM 而非总额度 | 降并发、串行化批量任务 |
| 证书/代理报错 | 企业 TLS 拦截,根证书未加载 | NODE_EXTRA_CA_CERTS 指向企业根证书 |
第 2 条最隐蔽:终端正常、IDE 不对,根因是进程启动方式决定环境继承。
10. 边界:什么情况本就不该用这套
| 场景 | 更合适的做法 | 理由 |
|---|---|---|
| CI / 无人值守 | API key 放 secrets,显式注入 | 订阅登录需要交互授权,跑不起来 |
| 团队十几人共用 | 统一网关 + 网关侧配额 | 一人一把 key 无法审计与限额 |
| 需要逐次调用审计 | 网关记录请求与用量 | 客户端日志不完整 |
| 走云厂商托管模型 | 用对应的云接入开关(变量名按当前版本核对) | 认证与计费都归云账号 |
一句话:目标不是"能跑",而是"每次跑在哪条账上,事后能说清"。
11. 自测
ANTHROPIC_BASE_URL写成https://gw.example.com/v1/messages,最可能报什么错,为什么?- 同一台机器既有订阅登录态又 export 了
ANTHROPIC_API_KEY,哪个生效? - 项目级
settings.json与用户级~/.claude/settings.json同时配了env.ANTHROPIC_MODEL,谁赢? - curl 直连网关能通、Claude Code 报 401,先查哪两件事的配对关系?
- IDE 内置终端里环境变量不生效,根因通常在哪一层?
- 要把"这个仓库走哪个网关"固化下来但又不提交密钥,配置该怎么放?