1. 为什么叫“Harness-0”:先想清楚要控制什么
最近在系统整理自己的 Claude Code 学习笔记,起了个系列名叫 learn-claude-code。第一篇我故意没有写“快速上手”或者“安装教程”,而是先搭了一个叫 Harness-0 的东西。
很多人学这类 AI 编程工具,节奏基本都是:装好、打开、开始对话、用完关掉。看起来会用了,但两个月后回头,发现自己除了“聊过”什么都没沉淀下来。真正的问题不在工具本身,而在于你从来没有给工具搭一个可控的实验环境。Harness 在软件工程里是“测试夹具”的意思,我借用这个词,是想给 Claude Code 装一个操作台:让它的运行过程可控、可重复、可观测。
1.1 从“会用”到“能驱动”:Claude Code 学习的分水岭
我见过不少开发者,Claude Code 用得挺勤,但始终停留在编辑器里打几个斜杠命令的水平。不是说这样不行,而是当你想让它批量处理代码、接入自己的工程流程、或者对比不同模型参数效果的时候,没有控制层的用法会非常吃力。
所谓的“能驱动”,指的是三件事:
- 能通过脚本或命令行参数调用 Claude Code,而不是每次都手动敲对话;
- 能控制它的输入输出,把结果落盘、解析、再注入到下一步流程;
- 能清晰看到每一次调用的模型、token 消耗和错误信息,而不是黑盒运行。
Harness-0 就是围绕这三点设计的最小框架。它不追求功能完善,目标只有一个:把 Claude Code 从“聊天窗口”变成“可编程单元”。
1.2 Harness 的本质:给 AI 工具装一个可控的操作台
举个例子你就明白了。手工测试一个 Web 接口,你在浏览器里点几次按钮,也能确认它通不通。但你要回归测试、要压测、要在 CI 里跑,就必须写一套测试脚本。Claude Code 也一样:日常对话很好用,可一旦进入工程化场景,就必须有 harness。
Harness-0 这个名字还有个含义——“第 0 版”。我不指望它一步到位,而是通过这个骨架把整个学习链路打通:安装、配置、调用、输出解析、错误处理。后续的文章都会在这个骨架上演进,比如改成异步批量任务、接进 Git Hook、或者挂到一个简单的 Web 服务上。
有一个很朴素的道理:先让笨办法跑通,再去优化。Harness-0 就是那个“笨办法”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:Windows 下安装 Claude Code 的完整过程与踩坑记录
安装是第一个坑最多的环节,特别是 Windows。官方文档写得简单,一行 npm 全局安装,实际执行起来会遇到一堆环境问题。我把完整过程拆开讲,每一步都说明为什么这么干。
2.1 Node.js 版本管理:为什么推荐用 nvm-windows 而不是直接装
Claude Code 本质是一个 npm 包,底层依赖 Node.js 运行时。在 Windows 上装 Node,我强烈建议先用 nvm-windows 做版本管理,而不是跑到官网下载一个最新版安装包。
原因很实际:Claude Code 对 Node 版本有最低要求,但你的电脑上其他项目可能依赖旧版本。直接装全局最新版,等下一个项目要求 Node 16 的时候就傻眼了。我有个习惯,任何会装到全局的命令行工具,统一用 nvm 切 Node 版本,装完再切回去,互不干扰。
安装 nvm-windows 之后,依次执行:
powershell复制nvm install 20
nvm use 20
node -v
npm -v
这里有个小细节,nvm-windows 安装路径尽量不要带空格,否则后面某些工具解析路径会出问题。我自己装在 C:\nvm4w,看起来像个很随意的目录名,但实际使用中极少遇到路径问题。
2.2 npm install -g 的 EPERM 错误与三种解决方案
接下来就是很多人卡住的地方:
powershell复制npm install -g @anthropic-ai/claude-code
然后冒出一大段报错,核心是:
code复制npm error code eperm
npm error syscall mkdir
npm error path C:\Users\xx\AppData\Roaming\npm\node_modules
EPERM 是 Windows 权限问题的经典错误。npm 试图在 AppData\Roaming\npm 目录下创建全局链接,但没有写权限。三种解法我按推荐顺序列出来:
- 以管理员身份运行 PowerShell:右键终端图标,选择“以管理员身份运行”,再执行安装。这是最省事的方法,但副作用是你以后每次装全局包都要记得用管理员终端。
- 调整 npm 全局目录到用户目录:执行
npm config set prefix "$env:APPDATA\npm",让 npm 把全局包装到当前用户完全可控的路径下。这个方法一次性解决问题,推荐。 - 检查杀毒软件或系统还原保护:某些安全软件会锁定 AppData 目录下的文件变更,导致 npm 写入失败。这种情况管理员权限也救不了,需要在安全软件里加信任区。
第二个方法我建议优先试。它把全局包的安装位置从系统保护目录挪走,从根源上绕开了权限问题。
2.3 安装之后的验证与 CLI 入口配置
安装成功后,执行:
powershell复制claude --version
如果提示“无法识别 claude 命令”,两个排查方向:
- 确认 npm 全局目录在 PATH 里。执行
npm prefix -g,再把输出目录加到系统环境变量 PATH。 - 检查 nvm 当前激活的 Node 版本。有时候安装成功了,但 nvm 切换版本后全局包“消失”,因为每个 Node 版本有独立的全局目录。
另外,很多人会在 C:\nvm4w\nodejs\node_modules\@anthropic-ai\claude-code\bin\claude.e 这个路径下找可执行文件,这个方向没错,但日常使用不需要手动去碰它。npm 全局安装时已经帮你在 PATH 目录下生成了 claude.cmd 和 claude 两个入口文件,正常使用直接敲 claude 即可。
3. 连接模型服务与计费边界:Claude Code 背后的接口逻辑
安装只是第一步,真正影响使用体验的是模型服务的接入。Claude Code 本身只是一个客户端壳子,它本身不带模型,所有对话能力都来自模型服务商提供的 API。
3.1 Claude Code 如何工作:CLI、认证、模型调用的链路
拆开看,Claude Code 的工作链路是:
code复制你敲命令 → CLI 解析参数 → 读取配置文件 → 组装 API 请求 → 发送给模型服务 → 拿到结果 → 输出到终端
认证方式通常有两类:一类是官方订阅账号直接登录,走官方认证链路;另一类是通过环境变量注入 API Key 或 Token,适合企业级或自定义接入场景。常用环境变量包括:
| 环境变量 | 作用 |
|---|---|
ANTHROPIC_API_KEY |
指定官方 API Key |
ANTHROPIC_BASE_URL |
指定 API 端点地址 |
ANTHROPIC_AUTH_TOKEN |
指定 Bearer Token |
ANTHROPIC_MODEL |
指定默认模型 |
这意味着 Claude Code 并不锁死只能连官方服务。任何兼容 Anthropic API 协议的服务商,理论上都可以通过调整 ANTHROPIC_BASE_URL 接入。这也是很多人会在搜索引擎里问“Claude Code 调用 DeepSeek 如何计费”的原因。
3.2 用 DeepSeek 等第三方模型时的配置方法与计费要点
如果你想把 Claude Code 接到 DeepSeek 这类第三方模型服务,首先要明确:这不是破解或者绕过官方限制,而是模型服务商提供了标准 API,Claude Code 作为客户端去对接它。操作上就是设置环境变量:
powershell复制$env:ANTHROPIC_BASE_URL = "https://api.deepseek.com/anthropic"
$env:ANTHROPIC_AUTH_TOKEN = "你的DeepSeek_API_Key"
claude
计费这块,核心是搞清楚各家服务的计费单元。通常按 token 计费,输入 token 和输出 token 价格不同,不同模型档位价格也不同。在 DeepSeek 开放平台的后台,可以看到每次调用的 token 消耗明细和费用记录。我建议不要只看单价,要同时关注上下文长度配置,因为 Claude Code 默认会携带大量上下文,同样的任务,不同配置下 token 消耗可能有数倍差距。
这里有个比较隐蔽的问题:Claude Code 这类工具会主动做多轮调用。也就是说,你问一个问题,它内部可能先让模型“思考”一步、再调用工具、再继续对话。每轮都是独立计费的。所以实际费用和你的预期之间经常存在偏差,这是正常现象。
为了控制成本,建议做三件事:
- 在 Cloude Code 配置里限制单次任务的模型调用轮数上限;
- 设置 token 消耗告警,用量到阈值自动提示;
- 定期导出会话记录,分析哪些类型的请求消耗占比最高。
我的经验是:先用小规模任务测试完整链路,确认计费符合预期,再放量。直接跑大任务,月底账单出来的时候心情通常不会太好。
4. Harness-0 实战:搭建最小可用的自动化驱动脚本
环境通了、模型能调了,接下来进入正题——写 Harness-0。它做的事情很简单:用 Python 脚本调用 Claude Code,让它读取一个代码仓库的变更列表,自动生成规范的 Git commit message。
4.1 需求拆解:我想让 Claude Code 替我做哪些重复工作
选择一个足够简单但有真实价值的场景来验证 harness。我每天都会遇到这个问题:改完几个文件,要写一个看得过去的 commit message。写中文还是英文、怎么描述改动影响范围,每次都要想半天。
把这个需求拆成几个环节:
- 获取当前工作区的变更文件列表;
- 把文件列表和 diff 内容组装成提示词;
- 调用 Claude Code,让它基于实际代码改动生成 commit message;
- 把结果展示出来,用户确认后写进 commit message 文件。
其中第 3 步是核心,其他步骤都是围绕它搭流水线。
4.2 脚本实现:用 Python 封装 Claude Code 的交互流程
Claude Code 提供了非交互模式,也就是 -p 参数,可以直接把提示词当作命令行参数传入,结果输出到标准输出。这正好适合在脚本里调用。
我用 Python 写一个最小实现,注意这里只用标准库,不引入额外依赖,保持 Harness-0 的轻量特征:
python复制import subprocess
import sys
def get_staged_diff():
result = subprocess.run(
["git", "diff", "--cached"],
capture_output=True,
text=True,
encoding="utf-8",
)
if result.returncode != 0:
print("获取 git diff 失败", file=sys.stderr)
sys.exit(1)
return result.stdout
def generate_commit_message(diff_text):
prompt = (
"你是一位资深开发工程师。请根据以下代码变更内容,"
"生成一条符合 Conventional Commits 规范的 commit message。\n"
"要求:使用英文,格式为 type(scope): subject,"
"subject 不超过 50 个字符。\n\n"
f"代码变更如下:\n{diff_text[:8000]}"
)
result = subprocess.run(
["claude", "-p", prompt, "--output-format", "text"],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
if result.returncode != 0:
print(f"调用 Claude Code 失败: {result.stderr}", file=sys.stderr)
sys.exit(1)
return result.stdout.strip()
if __name__ == "__main__":
diff = get_staged_diff()
if not diff:
print("暂存区没有变更,请先执行 git add")
sys.exit(1)
message = generate_commit_message(diff)
print("生成的 commit message:")
print("-" * 60)
print(message)
print("-" * 60)
这段代码的核心只有两步:把 git diff 内容拼进提示词,然后通过 subprocess 调用 claude -p。-p 参数表示 print 模式,不会进入交互对话框,直接输出结果。
4.3 运行效果与关键参数调试
实际跑一次,假设我修改了一个登录模块的密码校验逻辑,脚本输出类似:
code复制generated commit message:
fix(auth): fix password strength validation bypass
整个过程不到 5 秒,效果完全可用。但调试过程中有几个参数选项值得留意:
--output-format text:默认输出可能是带格式的,指定 text 后脚本解析更干净。--model:可以指定具体模型,不同任务对模型档位要求不同,简单任务用轻量模型就够了。timeout:subprocess 的 timeout 参数一定要设。否则模型服务异常时,脚本会无限挂起,CI 流水线会被卡死。
多跑几次之后,你可以把生成的提示词模板单独抽出来放到 prompts/ 目录,以后针对不同场景写不同模板,这是 Harness-0 自然演进的方向。
5. 调试心得:几个常见的坑和处理思路
动手搭完 Harness-0,很多隐藏的问题会浮出水面。挑几个我在 Windows 上反复踩过的坑讲讲,这些都是文档里不会写的细节。
5.1 EPERM 和路径问题的同源根因
前文提到的 EPERM 错误,其实和 nvm-windows 的路径解析机制是同一个根因:Windows 对目录权限和符号链接的支持方式跟 Linux/macOS 差异很大。npm 在 Windows 上创建 .cmd 快捷方式时,经常因为目录权限、终端会话权限不一致而失败。
有一个很典型的场景:你上午用普通终端装了一个全局包,下午用管理员终端运行时发现找不到命令。原因就是两个终端会话的 PATH 环境变量可能指向不同位置的全局目录。解决办法是统一用用户级前缀,并确保 PATH 里只保留一个 npm 全局目录。
5.2 确认调用的是哪个模型、花多少钱:日志与配额检查
脚本跑通了,但你怎么知道刚才那次调用用了哪个模型?花了多少 token?
Claude Code 的日志通常写在用户目录下,Windows 路径大致是 C:\Users\你的用户名\.claude\projects\,每次会话会有独立的 JSONL 日志文件。用文本编辑器打开,可以看到每次请求的模型名称、输入输出 token 数和耗时。
建议在 Harness-0 里加一个日志采集步骤,每次调用后自动解析 JSONL 文件,把关键字段汇总。这样就能回答“我这个月在这个项目上到底花了多少 token”这类问题,而不是等到账单出来才后悔。
5.3 “第一版能跑就好”:Harness 迭代的节奏
最后分享一个关于学习节奏的经验。很多人搭这类工具骨架时,总想一步到位:要支持多模型、要异步并发、要带 Web 界面。我的建议是不要。
Harness-0 的价值就是“最简可用”,它甚至不需要处理错误重试,不需要漂亮的输出格式,能跑通一次完整链路就算成功。因为只有跑通了,你才知道真正的瓶颈在哪里。比如我做的第一个版本里,完全没有考虑 git diff 太大导致提示词超长的问题,跑起来之后才意识到需要按文件分批发送请求。这个认知只有在实际运行中才能获得。
先在真实场景里跑三天,把不舒服的地方记下来,再迭代到 Harness-1。刚开始可能一天改一次,后面会越来越稳定,最终形成一个自己真正用得顺手的工具链。
我个人目前的做法,是把 Harness 脚本放在一个单独的 tools/ 目录,配合 Makefile 封装常用命令。这样不管过多久,只要跑一句 make commit-msg,就能复用整套流程。工具这种东西,做出来放在那里不用,才是最大的浪费。
