工具大全
踩坑实录作者:Coocon2026年8月24日395 次阅读约 3 分钟阅读

ANTHROPIC_BASE_URL 设了却不生效

现象

给 Claude Code 挂第三方中转站(one-api / new-api 那类 API 网关),配置写得规规矩矩,~/.zshrc 里三行齐全:

export ANTHROPIC_BASE_URL="https://xxxx.example.com"
export ANTHROPIC_AUTH_TOKEN="sk-..."
export CLAUDE_CODE_USE_VERTEX=0

新开终端,claude 启动,顶部写着:

Fable 5 · Google Vertex AI

Vertex。中转站的 base URL 像是根本没被看见。

同一天还有第二件事:CloudCLI(claudecodeui 改名后的 Web UI,用来远程控制本机 claude)由 macOS launchd 拉起,登进去一直让选 provider,提示未认证。可命令行里 claude 明明已经能走中转站了——同一个用户,同一台机器。

两个现象,两个独立的坑,共同点是:环境变量你以为设上了,进程里其实不是那么回事。

坑一:settings.json 的 env 比 shell export 大

先查环境变量本身有没有生效。echo $ANTHROPIC_BASE_URL 是对的,echo $CLAUDE_CODE_USE_VERTEX 也是 0。shell 这层没问题。

那就翻 Claude Code 自己的配置。~/.claude/settings.json 的 env 块里躺着三行测试残留:

{
  "env": {
    "CLAUDE_CODE_USE_VERTEX": "1",
    "ANTHROPIC_VERTEX_PROJECT_ID": "hello",
    "CLOUD_ML_REGION": "global"
  }
}

ANTHROPIC_VERTEX_PROJECT_ID 值是 hello——一眼就知道是当初试 Vertex 时随手填的,试完忘了删。

根因清楚了:settings.json 的 env 字段是「强制注入」,优先级高于 shell 里的 export。 你在 zshrc 里写的 CLAUDE_CODE_USE_VERTEX=0,进程启动时被这里的 "1" 盖掉。Claude Code 检测到 Vertex 配置齐活,就走 Vertex 通道去了,ANTHROPIC_BASE_URL 从头到尾没人问津——它压根不在那条代码路径上。

修复就一件事:把这三行删掉。

claude -p "1+1"
# 正常出结果,走的是中转站

这里值得单独强调一句:env 的优先级,和 model 字段的优先级链(--model > ANTHROPIC_MODEL > settings.json > 默认,实测过)是两回事。model 那条链上 settings.json 排在环境变量后面,是「你没设我才用」;env 这个子字段反过来,是「我设了就盖你」。它还藏在 JSON 文件里,不像 shell 配置那样天天能看见——这才是它比 model 优先级更容易吃亏的地方。

坑二:launchd 启动的服务不读你的 shell 配置

命令行修好了,CloudCLI 那边还是未认证。

打开它的 plist:

<!-- ~/Library/LaunchAgents/com.xxxx.claudecodeui.plist -->
<key>EnvironmentVariables</key>
<dict>
    <key>PATH</key>
    <string>/usr/local/bin:/usr/bin:/bin</string>
    <key>HOME</key>
    <string>/Users/xxxx</string>
</dict>

只有 PATH 和 HOME。没有 ANTHROPIC_BASE_URL,没有 ANTHROPIC_AUTH_TOKEN。

根因:launchd 不读 ~/.zshrc。 它跟 Linux 上的 systemd 是一个道理——服务进程不是从交互 shell 里 fork 出来的,你在 .zshrc / .bashrc 里写的任何 export,对它统统不可见。CloudCLI 自己环境是空的,透传给 claude 子进程的自然也是空的。

修复不是往 plist 里塞环境变量(那等于把 token 写进一个 XML,还要多维护一处),而是把中转站配置落到 ~/.claude/settings.json 的 env 块:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://xxxx.example.com",
    "ANTHROPIC_AUTH_TOKEN": "sk-..."
  }
}

写在这儿,两条路都能读到:

  • Claude Code CLI 每次启动都读 settings.json 的 env,不依赖父进程给了什么;
  • CloudCLI 的认证逻辑专门读这个文件——它 loadSettingsEnv 的注释写得明明白白,「即使服务进程 env 为空也能用」。

同一个坑,坑一里 env 是加害者,坑二里它是解药。

验证:用 env -i 模拟服务环境

改完别急着重启 launchd 再登一次 Web UI 试——那一轮反馈太长。直接在终端里把环境清空,模拟服务进程的裸环境:

env -i HOME="$HOME" PATH="/usr/local/bin:/usr/bin:/bin" claude -p "1+1"

env -i 丢掉所有继承来的环境变量,只留你显式给的那两个——launchd 给什么,这里就给什么。这条命令能出结果,说明配置确实落在了「工具自己读得到」的地方,而不是靠 shell 喂进去的。

这个手法对付一切「命令行能跑、服务里跑不了」都好使:cron、systemd、Docker entrypoint,都是同一类环境断裂。

带走的教训

  1. 排查「环境变量设了却不生效」,第一站是 ~/.claude/settings.json 的 env。 有同名键就是它赢,shell 里 export 多少遍都没用。这跟 model 的优先级链方向相反,别拿一套记忆套两处。
  2. 服务管理器不读 shell 配置。 launchd、systemd、cron 启的进程都看不见你的 .zshrc。依赖环境变量的工具一旦交给它们启动,配置就得落到「工具自己读得到的地方」——settings.json、服务的 EnvironmentVariables、独立 env 文件,三选一。
  3. env -i 是模拟干净服务环境的最快验证手段。 不用重启服务、不用重登,一条命令就知道配置落点对不对。
  4. 测试残留必须清。 ANTHROPIC_VERTEX_PROJECT_ID: "hello" 这种一看就是临时填的值,试完当场删。它不会报错,只会在几个月后跟你的新配置打架,而你完全想不到往那儿看。

这类实测,每周六汇总一封

订阅码农早餐:每天 8:00 一封 AI 编程早报,每周六另附本周 Claude Code / Codex / 本地模型的实测和踩坑汇总。

相关文章

Claude Code 上下文太长怎么办:Prompt is too long 会自动压缩,中转站 / DeepSeek 的 maximum context length 却不会(实测)

Claude Code 靠报错文案判断「上下文太长」:后端说 prompt is too long 或 input is too long for requested model,它会自动压缩对话后重发,用户无感;DeepSeek 和 OpenAI 风格中转返回的 This model's maximum context length is …,它不认识,直接报 API Error: 400,每轮都失败。手动 /compact 有效;更好的办法是用 CLAUDE_CODE_MAX_CONTEXT_TOKENS(非 claude- 模型 ID)或 CLAUDE_CODE_AUTO_COMPACT_WINDOW(claude- 模型 ID)告诉它真实上限,让它提前压缩。Claude Code 2.1.285 + 本地 stub 实测。

claude-codedeepseek+6
pitfalls2026年10月5日8 min
89

Claude Code 一直卡住、转圈没反应怎么办:后端不回时它要等 6 分钟,重试满 10 次可能卡一个多小时(实测)

Claude Code 转圈不动、或者停在 Retrying in 0s,多半是后端没有回数据。实测 2.1.285(API key + ANTHROPIC_BASE_URL):后端不回响应头时每次等 6 分钟(360 秒)才判超时,把 API_TIMEOUT_MS 调到 60 万、90 万也不变,只能调小;默认重试 10 次,总共可能卡一个多小时。中转站如果把回复缓冲到生成完才返回,超过 6 分钟的回复永远拿不到。按 Esc 可以随时中断。全部在本地 stub 上实测。

claude-code中转站+6
pitfalls2026年10月5日10 min
90

Claude Code 429 怎么办:Request rejected (429) 原文、会重试多久、retry-after 超过 60 秒直接放弃(实测)

Claude Code 遇到 429 会先自动重试,最多 10 次、约 3 分钟。retry-after 不超过 60 秒时会等满再试(实测 10 秒、60 秒都恢复成功),61 秒及以上一次都不重试,立刻报 API Error: Request rejected (429)。中转站(new-api)的中文限流提示会原样显示,空 body 显示 status code (no body)。交互模式下每句话会同时发 2 个请求,限流额度消耗也是 2 倍。全部在本地 stub 上实测,Claude Code 2.1.285。

claude-code中转站+5
pitfalls2026年10月4日9 min
87
Claude Code MCP 显示 Connected 却 0 个工具:Invalid result for tools/list(ttlMs / cacheScope)实测与修法

Claude Code MCP 显示 Connected 却 0 个工具:Invalid result for tools/list(ttlMs / cacheScope)实测与修法

MCP server 显示已连接、工具数却是 0,日志里是 Invalid result for tools/list,ttlMs 与 cacheScope 校验失败。用自写 stub 在 Claude Code 2.1.280 / 2.1.285 / 2.1.288 上复现:根因不是「多了未知字段被严格校验拒掉」,而是 server 协商到 MCP 2026-07-28 后漏了这一版的必填字段(resultType、ttlMs、cacheScope),多加未知字段反而能正常通过。stdio 是否走新协议由一个默认关闭的远程开关决定,所以同一个版本有人中招、有人没事;2.1.280 打开协商后同样失败。用户侧设 MCP_PROTOCOL_NEGOTIATION=legacy(settings.json 的 env 也行)立即恢复,server 侧补上三个字段即可。

mcpclaude-code+4
pitfalls2026年10月3日7 min
73