上个月末帮一个小组统一开发环境,最后卡在同一个环节上:几个人想用 Claude Code 在终端里做代码重构和报错定位,装是几分钟就装完了,可一敲回车就出问题——要么一行红字 401,要么光标停在连接提示上半天没动静。排查下来,问题不在安装,而在“请求最终发给了谁”。默认的服务地址和结算方式跟团队现状对不上,而组里手头已经有一批国内大模型的调用额度,于是“先装下来、再把请求指向国内模型”这件事,从一条临时命令变成了一份需要认真对待的配置。
这篇记录就是围绕这两件事展开的:Claude Code 的下载安装,以及把它的模型端点改造成国内大模型服务的兼容接口。前一件事花十分钟,后一件事能让你在半夜两点还在翻日志。我会把端点改造里那些配置字段、验证手段、容易踩的坑一条条说清楚,代码和配置都是可以直接复制去改的。适合两类人看:一类是刚接触这类终端编程助手、想先把环境跑起来的新手;另一类是用过一阵子、但一直没把模型端点这套逻辑理顺的老哥。
1. 拆解需求:一个终端编程助手,为什么值得折腾端点
1.1 它和网页聊天窗口的本质区别
很多人第一次接触 Claude Code,会把它当成“命令行版的聊天框”,这个理解会直接影响后面所有配置决策。它不是聊天框,它是一个带工具调用能力的执行循环。你给一句需求,它对本地文件系统和终端发起操作请求,本地执行完把结果回传,然后继续下一轮,直到它认为任务完成或者你喊停。
这个循环决定了三件事。第一,它必须能读写文件、执行 shell 命令,权限边界需要你亲自划定,不能像聊天那样随便说说。第二,它对模型的工具调用(tool use)能力有硬性依赖,一个只会输出文字、不会返回结构化工具调用请求的模型,接进来也只能当打字机用。第三,它需要流式响应,因为一轮对话可能要跑几十秒甚至几分钟,没有流式输出你根本不知道它在做什么。
理解了这三点,后面的端点配置就有了判断标准:能不能返回标准 SSE 流、能不能正确解析 tools 字段、上下文窗口够不够塞下几个文件和一堆命令输出。这三个问题只要有一个答案是否定的,配置再正确也跑不顺。
1.2 把请求指向国内模型的三个现实动机
动手改端点之前,先把动机想明白,否则你会在配置到一半时怀疑自己。我接触到的情况大致归为三类。
第一类是成本和额度的复用。团队已经采购了某个国内大模型平台的额度,API 计费方式更接近预算模型,按月结算、有封顶,比按量付费的美元账单更好管理。这种情况下把 Claude Code 的请求导过去,等于让已有的额度多了一个使用入口。
第二类是延迟和响应体验。/v1/messages这种长连接请求对链路质量很敏感,尤其是在连续做十几轮工具调用的场景,每轮多几百毫秒,累计下来就是明显的体感差异。请求打到地理位置更近的服务节点,交互的流畅度会有肉眼可见的改善。
第三类是数据落地和合规要求。这一条在某些团队里是硬门槛:代码片段、配置内容、日志输出都会进入模型上下文,如果这些内容必须留在特定范围内,那把请求指向自建或私有部署的模型服务就是唯一选择。这类场景通常还会配上内网网关,配置方式跟公网端点略有不同,后面第 3 章会单独提。
提示:先确认你的模型服务商是否提供“Anthropic 兼容端点”,这是整件事成立的前提。多数平台的接入文档里会单独列一节,关键词是兼容协议、/v1/messages、Claude Code 接入。找不到这一节,说明该平台只提供自己的原生协议,需要额外的协议转换层。
1.3 动手前的三项能力核对
我把需要提前确认的东西整理成了下面这张表,建议你在改任何配置之前先逐条打勾。这张表能省掉你至少两个小时的无效调试。
| 核对项 | 具体要求 | 不满足时的表现 |
|---|---|---|
| 协议路径 | 服务地址需响应POST /v1/messages | 一律 404,日志里能看到路径拼错 |
| 鉴权头 | 支持Authorization: Bearer或x-api-key之一 | 401,且换 key 无效 |
| 流式输出 | 返回text/event-stream分块数据 | 界面长时间空白,最后一次性吐出来 |
| 工具调用 | 能解析tools字段并返回tool_use块 | 模型只说不做,一直在描述方案 |
| 上下文长度 | 至少 64K,建议 128K 以上 | 处理中等规模文件时反复截断报错 |
| 模型标识 | 有明确的模型 ID,可从控制台复制 | 404 或提示模型不存在 |
这张表里最容易被忽略的是“模型标识”。不同平台对同一个模型的 ID 命名五花八门,有的带版本后缀,有的带日期,有的区分思考版和普通版。你在配置里填错一个字符,请求就会被路由到一个不存在的位置。
2. 安装:三条路径,按你的环境挑
2.1 前置依赖与版本选择
Claude Code 的运行依赖 Node.js,官方要求 18 以上,我的建议是直接用 20 或 22 的 LTS 版本。这不是保守,是因为老版本 Node 在流式响应的处理上有一些边界问题,跑短请求没事,跑长连接容易在中途断开,排查起来非常费劲。
如果你机器上有多个项目依赖不同的 Node 版本,别直接覆盖全局,用版本管理器更省心:
# 安装并切换到 Node 20 LTS nvm install 20 nvm use 20 node -v # 确认输出 v20.x npm -vWindows 用户如果用官方安装包装的 Node,一般不需要额外处理。但如果你在 PowerShell 里遇到脚本被拦截的提示,需要调整执行策略:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned这个改动只影响当前用户,比全局放开安全得多。改完之后重开一个终端窗口,让策略生效。
2.2 三种安装方式的取舍
目前主流的安装方式有三种,适用场景差别不小,我按推荐顺序说。
第一种是 npm 全局安装,也是我日常用的方式:
npm install -g @anthropic-ai/claude-code优点是升级方便,npm update -g一条命令搞定,而且包管理器会帮你处理依赖。缺点是对 Node 版本敏感,如果全局 Node 版本太老会直接报错。另外在 Linux 上如果是用系统包管理器装的 Node,全局目录可能需要 sudo,这里建议配置 npm 的用户级前缀,别用 sudo 装,后患很多。
第二种是官方提供的一键安装脚本,适合不想折腾 Node 环境的机器:
# macOS / Linux curl -fsSL https://claude.ai/install.sh | bash# Windows PowerShell irm https://claude.ai/install.ps1 | iex这条路会把可执行文件放到用户目录下,不依赖全局 Node。适合临时机器、CI 环境,或者你纯粹不想被 Node 版本问题烦。缺点是升级要重新跑一遍脚本。
第三种是容器化隔离。如果你要在一台机器上跑多个不同版本的工具,或者需要严格控制它能访问哪些目录,那就在容器里装。这种方式配置成本最高,但边界最清晰,适合团队统一分发。
2.3 装完先自检,别急着配置
装完之后有三步自检,一步都不能省。
# 1. 确认命令可用 claude --version # 2. 跑一遍环境诊断,它会检查 Node 版本、配置文件、网络连通性 claude doctor # 3. 看看配置目录有没有生成 ls -la ~/.claudeclaude doctor这个命令值得单独说一句。它会输出一份体检报告,包括 Node 版本是否达标、全局安装路径是否正确、配置文件语法有没有问题。我遇到过的几次“命令能跑但一进交互就崩”,最后都是靠它定位到配置文件的 JSON 语法错误——多了一个逗号,肉眼根本看不出来。
~/.claude目录是用户级配置的家,里面通常会有settings.json、会话历史、项目缓存。这个目录的结构值得你花两分钟看一眼,后面调端点全靠它。
2.4 Windows 环境下的两个高频问题
Windows 上的坑比 macOS 和 Linux 多一些,集中在这两个地方。
第一个是路径带空格。如果你的用户名或者项目路径里有空格,某些工具调用会解析失败,表现为命令执行超时或者文件读写报错。解决办法要么把项目放在没有空格的路径下,要么在 Windows 上使用 WSL,把工作目录映射到 Linux 侧。
第二个是终端选择。在 Git Bash 下跑交互模式,偶尔会遇到 TTY 识别异常,输出乱码或者按键无响应。实测下来 Windows Terminal 加 PowerShell 7 的组合最省事,cmd 老窗口在处理 ANSI 颜色和光标控制时容易出问题。如果你一定要用 Git Bash,建议用winpty包一层。
3. 端点改造:让 CLI 说上国内模型的话
3.1 环境变量清单与优先级
这是全文最核心的一节。Claude Code 读取模型端点的逻辑,全部靠环境变量驱动,搞清楚每个变量的作用,比翻十篇教程都有用。
| 变量名 | 作用 | 是否必设 |
|---|---|---|
ANTHROPIC_BASE_URL | 请求的基础地址 | 必设 |
ANTHROPIC_AUTH_TOKEN | 以Authorization: Bearer头发送的令牌 | 二选一 |
ANTHROPIC_API_KEY | 以x-api-key头发送的令牌 | 二选一 |
ANTHROPIC_MODEL | 主模型 ID | 建议设 |
ANTHROPIC_SMALL_FAST_MODEL | 后台小任务用的轻量模型 | 建议设 |
API_TIMEOUT_MS | 单次请求超时,单位毫秒 | 建议设 |
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC | 关闭非必要的外部请求 | 可选 |
第一个必须记住的规则:ANTHROPIC_BASE_URL只填到域名或域名加前缀,绝对不要带/v1。客户端会自己在后面拼/v1/messages。你填成https://xxx.com/v1,实际请求就变成https://xxx.com/v1/v1/messages,直接 404。这个错误我见过太多次,日志里那一长串重复的路径特别显眼。
第二个规则是令牌头的选择。ANTHROPIC_AUTH_TOKEN走的是Authorization: Bearer,ANTHROPIC_API_KEY走的是x-api-key。国内兼容端点绝大多数只接受前者,所以优先用ANTHROPIC_AUTH_TOKEN。如果配置完还是 401,把另一个也设上试试,注意两个都设的时候不要互相覆盖。
第三个规则是超时。默认 60 秒,在处理大文件或者连续工具调用时经常不够用,建议调到 300000 到 600000 之间:
export API_TIMEOUT_MS=6000003.2 用 settings.json 把配置固化下来
环境变量写在 shell 配置文件里有个问题:换终端、换 IDE 内置终端、用脚本调用,都不一定能读到。更可靠的做法是写进配置文件的env字段。
用户级配置在~/.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://your-endpoint.example.com", "ANTHROPIC_AUTH_TOKEN": "sk-your-token-here", "ANTHROPIC_MODEL": "your-model-id", "ANTHROPIC_SMALL_FAST_MODEL": "your-small-model-id", "API_TIMEOUT_MS": "600000", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" } }项目级的放在项目根目录的.claude/settings.json,格式一样。如果你想让某个项目用不同的模型,就把配置写在项目级,它会覆盖用户级。还有一层.claude/settings.local.json,这个文件通常不纳入版本管理,适合放个人令牌。
优先级从高到低大致是:命令行环境变量 > 项目本地配置 > 项目配置 > 用户配置。调试的时候如果发现改了没生效,先怀疑是不是有个更高优先级的配置在覆盖。
注意:把令牌写进 settings.json 就意味着它会以明文形式躺在磁盘上。团队协作时务必把
.claude/settings.local.json加进 .gitignore,不要提交到仓库。已经有apiKeyHelper这种从外部命令动态取值的机制,如果你的环境有密钥管理服务,用它更稳妥。
3.3 模型 ID 映射:大模型和小模型要分开填
很多人在这一步栽跟头。Claude Code 内部至少在两个地方调用模型:主对话用一个能力强的模型,生成会话标题、判断是否需要压缩上下文这类后台任务用一个小而快的模型。如果你只配了主模型,小模型会走默认值,结果就是那些后台请求全部失败,表现是会话标题永远是空的,或者间歇性弹出一堆报错。
所以两个都要填,而且要填服务商真实存在的模型 ID。怎么拿到准确的 ID?去控制台看模型列表,直接复制,别手打。有些平台的 ID 带日期后缀,比如某个模型区分-0905和-1106两个版本,填错了就是 404。
如果服务商只提供一个模型,那就两个变量填同一个值,能跑,只是后台任务会稍微贵一点。
3.4 先用 curl 打通链路,再回来开工具
这一节是我最想强调的。很多人配完环境变量直接启动 Claude Code,看到报错就一头扎进配置里反复改,实际上应该先用一条 curl 把整条链路验证清楚,把问题分层隔离。
先测基础连通性和鉴权:
export BASE="https://your-endpoint.example.com" export TOKEN="sk-your-token-here" curl -sS -i -X POST "$BASE/v1/messages" \ -H "Authorization: Bearer $TOKEN" \ -H "content-type: application/json" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "your-model-id", "max_tokens": 64, "messages": [{"role": "user", "content": "reply with ok"}] }'看三个地方:HTTP 状态码是不是 200,响应头里content-type是不是含text/event-stream,body 里有没有正常的内容块。这一步过了,说明地址、鉴权、模型 ID 都没问题。
再测工具调用能力,这是 Claude Code 能不能干活的关键:
curl -sS -X POST "$BASE/v1/messages" \ -H "Authorization: Bearer $TOKEN" \ -H "content-type: application/json" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "your-model-id", "max_tokens": 256, "tools": [{ "name": "read_file", "description": "read a file from disk", "input_schema": { "type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"] } }], "messages": [{"role": "user", "content": "read the file at /tmp/demo.txt"}] }'期望看到返回的content数组里有一个type为tool_use的块,里面带着input.path。如果返回的是纯文本,比如“好的,我将为你读取文件”,那说明这个端点没有正确实现工具调用,接进来也只会给你讲方案不动手。
这条 curl 能省掉后面 80% 的困惑。链路层的问题和模型能力层的问题,用两条命令就能区分开。
4. 跑通之后:把工具真正用起来
4.1 第一次启动会遇到什么
配置就绪后,在项目目录下敲claude就能进交互界面。正常情况下它会直接进入对话,不再弹网页授权流程——因为你已经通过令牌鉴权了。
如果发现它仍然要求你登录,九成是环境变量没有进到启动进程里。常见原因有三种:把变量写在了.zshrc但当前用的是 bash;用 IDE 的内置终端启动,没继承 shell 配置;配置文件的 JSON 语法有误被静默忽略。逐一排查,最快的验证方式是在启动它的同一个终端里先echo $ANTHROPIC_BASE_URL看一眼。
进去之后先跑/status,它会告诉你当前用的是哪个模型、哪个端点。这一步确认完,再开始干活。
4.2 给它一份项目说明书
CLAUDE.md这个文件值得单独写一节。它会在每次会话开始时被读进上下文,相当于你给模型的一份入职说明。写得好,后面省一半沟通成本;写不好,每次都要重复交代同样的事。
我的建议是控制在 100 行以内,只放这三类信息:项目用什么技术栈和目录结构、构建和测试命令是什么、有哪些绝对不能碰的目录或文件。
# 项目说明 ## 技术栈 - 后端:Node.js 20 + TypeScript,入口 src/server.ts - 前端:React 18 + Vite,源码在 web/src - 数据库迁移脚本在 db/migrations,执行前必须备份 ## 常用命令 - 本地启动:npm run dev - 跑测试:npm run test -- --run - 类型检查:npm run typecheck ## 禁止事项 - 不要修改 .env.production 和任何以 .pem 结尾的文件 - 不要在 src/legacy 目录下新增代码,该目录只做删除不改写第一次进项目可以直接用/init,它会扫描目录自动生成一份初稿,然后你在上面改,比从零写快得多。
4.3 权限边界:让它跑到什么程度
Claude Code 请求执行命令或写文件时会弹确认。你可以用/permissions管理白名单,把高频且安全的操作放行,比如npm run test、git diff、ls。这一步的意义不是让它跑得更快,而是减少你在无关确认上消耗的注意力。
相对的,--dangerously-skip-permissions这个参数我建议只在完全隔离的容器里用。它的作用是完全跳过确认,模型想执行什么就执行什么。在本地主工作目录里开这个开关,等于把rm -rf的决定权交出去了。我见过一次误删,好在有 git,但那一下心跳的体验不想再来第二次。
配置写在 settings 里更清晰:
{ "permissions": { "allow": [ "Bash(npm run test:*)", "Bash(git diff:*)", "Bash(ls:*)", "Read(src/**)" ], "deny": [ "Bash(rm -rf:*)", "Read(.env*)" ] } }4.4 上下文和成本:账单是怎么涨上去的
用国内模型一个好处是单价可控,但量大了一样肉疼。有几个习惯能显著压低消耗。
第一,善用/compact。会话跑长了上下文会被一堆命令输出塞满,及时压缩能把它归纳成摘要继续用,比开新会话丢失全部上下文划算。第二,别让它一次性读大文件。真要分析一个大文件,先让它用grep定位关键函数,再读那一段,能省下大量 token。第三,后台小模型一定要配,那些生成标题的请求如果走了主模型,属于纯浪费。
/cost命令能看当前会话的消耗,养成隔一阵看一眼的习惯。
我拿一个虚构的后台管理系统练过手,任务是“把三个接口的错误处理统一成中间件”。整个过程跑了 23 轮工具调用,读改了 11 个文件。第一版我直接让它读整个src/api目录,上下文瞬间被塞满,触发了压缩,后面的判断质量明显下降;第二版改成先列目录、再按需读,总轮次降到了 15 轮,输出质量反而更一致。这个对比挺说明问题的:上下文管理比模型选择更影响最终效果。
5. 报错排查实录
5.1 连接与鉴权类错误的定位顺序
拿到报错别急着改配置,先按状态码分层。
| 现象 | 大概率原因 | 处理动作 |
|---|---|---|
| 401 Unauthorized | 令牌头不对或 key 过期 | 换ANTHROPIC_AUTH_TOKEN与ANTHROPIC_API_KEY再试 |
| 403 Forbidden | 令牌无该模型权限 | 控制台确认模型是否已开通 |
| 404 Not Found | 地址带了/v1,或模型 ID 错 | 检查 base_url 与模型 ID |
| 400 Bad Request | 请求体字段不被支持 | 检查是否传了端点不认的参数 |
| 请求超时 | 大文件或长上下文 | 调大API_TIMEOUT_MS |
| 连接被拒 | 地址不可达或端口不对 | 先用 curl 单独验证 |
这张表覆盖了我遇到过的九成情况。特别说一下 400 这一类,有些兼容端点对参数很挑剔,比如不接受某些扩展字段,或者对max_tokens有上限要求。表现是配置全对但请求一直被拒,这时候用 curl 复现一次,把返回的 error message 完整看一遍,通常写得很明确。
5.2 请求通了但回复是空的
这个现象很迷惑人:状态码 200,日志显示请求成功,界面上什么都没有。根本原因通常是流式数据的格式差异。
标准 SSE 每一行是data: {...},最后以data: [DONE]收尾。有些兼容实现漏了换行符,或者把多个事件粘在一块发,客户端解析时整段丢弃。诊断方法还是 curl,加-N参数关闭缓冲:
curl -N -sS -X POST "$BASE/v1/messages" \ -H "Authorization: Bearer $TOKEN" \ -H "content-type: application/json" \ -H "anthropic-version: 2023-06-01" \ -d '{"model":"your-model-id","max_tokens":128,"stream":true,"messages":[{"role":"user","content":"count to five"}]}'如果这里能看到一行行的data:输出但工具里没反应,问题就在客户端的解析层;如果连 curl 都是一片空白,那就是服务端的问题,找平台确认去。
5.3 模型只说不做
这个我单独拎出来讲,因为它和配置无关,很容易被误判成配置错。
表现是:你让它改代码,它回一大段“我来帮你修改,首先打开文件……”,然后就没有然后了。原因是这个模型不支持工具调用,或者端点在上游把tools字段丢掉了。
判断方法就是第 3.4 节那条 curl。返回里有tool_use块,说明能力没问题,是客户端参数没传对;返回纯文本,说明这个模型接不了这个活,换模型。
还有一种中间情况:模型偶尔能调用工具,但参数格式经常不对,比如该给对象给了字符串。这是模型对 schema 的遵循能力问题,换更强的模型通常能缓解,调提示词的效果有限。
5.4 速查表与几个踩坑心得
我把散落在各处的经验合并成一张表,方便你直接对照。
| 症状 | 先查什么 | 再查什么 |
|---|---|---|
| 启动就 401 | 令牌变量名 | 令牌是否带多余空格 |
| 一直卡在连接中 | API_TIMEOUT_MS | curl 验证端点可达 |
| 会话标题一直空白 | 小模型 ID | 小模型是否已开通 |
| 改了配置不生效 | 配置优先级 | JSON 语法是否合法 |
| 长任务中途断掉 | 超时设置 | 上下文是否超限 |
| 工具调用报参数错 | 模型能力和 schema | 是否传了错误类型 |
| 中文输出乱码 | 终端编码 UTF-8 | 终端类型 |
几个心得,都是花钱花时间换来的。
第一,永远先用 curl 验证,再动客户端配置。分层排查能让你少走很多弯路,很多人一开始就在改 JSON,改到怀疑人生,其实问题在服务端根本没开兼容接口。
第二,令牌不要用回车带出来的多余空格。从控制台复制的时候末尾经常粘一个换行,粘贴进配置文件看不见,报错就是 401,能查半小时。
第三,配置改动后必须重开终端。环境变量只在进程启动时读取,source有时候也不够,尤其是 IDE 内置终端,得整个窗口关掉重开。
第四,把项目的CLAUDE.md当成文档维护,不是一次写完就扔。每次发现有重复交代的事情,就补一行进去,两三周之后你会发现沟通成本显著下降。
第五,准备一个最小可复现的项目。遇到诡异问题,新建一个只有两个文件的空项目重试,如果那里正常,说明问题和你的项目结构有关,比如文件太多触发了上下文截断,或者被.gitignore影响到了目录扫描。
这套配置我在三台不同系统的机器上跑过一遍,最后稳定下来的是:用户级 settings.json 放端点和小模型,项目级 settings.json 放权限白名单,令牌单独放 local 文件并加进忽略列表,API_TIMEOUT_MS统一调到十分钟。这一套跑下来最省心,也最不容易在换机器时出岔子。真要说还有什么可以继续折腾的,就是把模型端点做成按项目切换——前端项目用响应快的,后端重构用上下文长的,在项目级配置里各写一份,切目录就切模型,比来回改全局变量顺手得多。