Harness 实战:让 AI Agent 可靠地写代码
模型是引擎,Harness 是车——最好的引擎没有方向盘和刹车也没用。
为什么做这个项目
2025 年,我们学会了让 AI 写代码。2026 年,我们发现真正的难题不是写代码,而是持续、可靠地写代码。
让 Claude Code 完成一个小任务很容易。让它连续完成 20 个任务、跨越多个会话、不偏离方向、不降低质量——这才是真正的工程挑战。
我们都见过这些失败模式:
- Agent 给自己打高分,实际上测试根本没覆盖验收标准
- 上下文窗口快满时,Agent 开始”草草收工”
- 前一个会话留下的 bug,下一个会话在上面继续堆代码
- Prompt 说了”先写测试”,Agent 微笑着跳过了这步
- 占位符
TODO藏在接口后面,表面上代码”能跑”
这些不是 Agent 的”偶尔失误”。这是系统性的失败模式,需要系统性的解决方案。
Harness 就是这个解决方案。它不是一个库,不是一个框架——它是一套你放进任何项目的文件,让 AI Agent 像靠谱的工程师一样工作,而不是像实习生一样需要盯着。
核心洞察:从 GAN 到 Agent 工程
让写代码的和审代码的互相不认识
Harness 的核心思想借鉴自 GAN(生成对抗网络)。
在 GAN 中,Generator 生成,Discriminator 判别,两者对抗产生高质量输出。我们把同样的思路用到了 Agent 开发上——如果让同一个 Agent 既写代码又评估代码,它永远觉得自己写得不错。这不是 Agent 的缺陷,这是人类也有的认知偏差:沉没成本效应。
所以 Harness 把”写”和”评”拆到两个完全独立的上下文窗口中:
┌──────────────┐
│ Planner │ 把模糊需求变成结构化计划
└──────┬───────┘
│
┌──────▼───────┐
┌────►│ Generator │ 一次一个任务,TDD 实现
│ └──────┬───────┘
│ │
│ ┌──────▼───────┐
FAIL │ │ Evaluator │ 独立会话,怀疑论审查
(max 2x) │ └──────┬───────┘
│ │
│ PASS │ FAIL
│ │
└────────────┘
Generator(生成器)负责写代码,遵循 TDD,跑测试。它有完整的编辑权限,可以创建文件、运行命令。
Evaluator(评估器)在全新的 Claude Code 会话中启动,没有看过 Generator 的实现过程。它只能读代码、跑验证、看结果。它的默认心态是”大概是有问题的”——5 个维度全部通过,才给 PASS。
任何一项 FAIL,整体 FAIL。Generator 收到反馈后修复,再由全新的 Evaluator 重新审查。最多 2 次重试,防止无限循环。
一个真实的例子
我们在自己的项目上测试了这个流程。任务是给首页加一个”回到顶部”按钮,我们故意在代码里埋了一个 bug——把滚动检测条件写反了(scrollY < 200 应该是 scrollY > 200)。
结果:
- Generator 完成了实现,代码能跑,
npm run build通过 - Evaluator 在全新会话中审查代码,发现条件反转——FAIL
- Generator 收到反馈,修复条件为
scrollY > 200 - 新的 Evaluator 重新审查——PASS
- 计划自动标记为完成,进度笔记记录了整个过程
人工介入:零。整个 FAIL → Fix → Re-evaluate → PASS 循环自动完成。
两层防护:概率 + 确定
为什么一层不够?
光有 Agent 层面的对抗还不够。Prompt 是概率性的——你告诉 Agent “提交前跑 lint”,它 90% 的时候会照做,但那 10% 的偏移就是 bug 的来源。
所以 Harness 加了第二层:Hook 确定性护栏。
┌─────────────────────────────────────────────────────┐
│ 概率层(Skill / Prompt) │
│ "请遵循 TDD" "请先验证基线" "请不要跳过测试" │
├─────────────────────────────────────────────────────┤
│ 确定层(Hook / 机械执行) │
│ pre-commit: 代码文件? → lint + typecheck │
│ pre-push: → 完整验证套件 │
│ post-edit: → 即时语法检查 │
└─────────────────────────────────────────────────────┘
Skill 告诉 Agent 应该做什么——这是概率性的,有时候会被忽略。
Hook 确保关键步骤不被跳过——这是确定性的,不管 Agent 怎么想,代码提交前 lint 一定会跑。
这不是二选一,而是两层叠加。就像飞机有自动驾驶(概率)也有机械备份(确定)——两者共存才安全。
三种 Hook 护栏
| Hook | 触发时机 | 做什么 | 为什么 |
|---|---|---|---|
| pre-commit | git commit | 检测暂存文件类型,仅对代码文件跑 lint/typecheck | 文档提交不需要跑 lint,节省时间 |
| pre-push | git push | 完整验证套件 | 代码离开本地前的最后一道关 |
| post-edit | Write/Edit | 即时语法检查 | 不等到验证阶段才发现语法错误 |
所有 Hook 从 config.json 读取设置,可以逐项启用/禁用。没有黑盒,一切可控。
七条设计哲学
这些不是我们凭空想出来的——它们提炼自 Anthropic(两篇)、OpenAI、Geoffrey Huntley 的四篇研究论文,加上我们自己的实践验证。
1. 不信任,要验证
Agent 的自我评估永远过于乐观。Evaluator 在独立的上下文窗口中运行,没有 Generator 的沉没成本压力,默认假设”大概是有问题的”。
它按 5 个维度打分:
| 维度 | 检查什么 |
|---|---|
| 验证通过 | npm test、make check 等项目验证命令是否通过 |
| 验收标准 | 计划中列出的每一条标准是否都满足 |
| 测试覆盖 | 新增功能是否有对应的测试 |
| 无占位符 | 代码中没有 TODO、FIXME、NotImplementedError、... |
| TDD 合规 | 是否先写了测试再实现(后端任务) |
任何一项 FAIL,整体 FAIL。
2. 概率 + 确定 = 完整防护
Skill 告诉 Agent 该做什么,Hook 确保关键步骤不被跳过。这是 Harness 最核心的创新——业界首次将 Claude Code Hook 系统性地用于 Agent 质量保障。
3. 上下文是稀缺资源
每个会话只做一件事。状态通过 JSON 计划和 Markdown 笔记在会话间传递,而不是塞进上下文窗口。
Anthropic 发现了一个叫 Context Anxiety(上下文焦虑)的现象:当上下文快满时,Agent 会开始”草草收工”。解决方案不是给更大的窗口,而是管理好你已有的窗口。
4. 仓库即真相
Agent 访问不到的信息等于不存在。所有决策、架构、需求都推入仓库。CLAUDE.md 是地图而非百科——30 行以内,指向更深的文档。
这来自 OpenAI 的实践:在 Codex 百万行生产代码的经验中,他们发现 AGENTS.md 越短越好,因为 Agent 不需要记住所有信息,只需要知道去哪里找。
5. 验证即反压(Backpressure)
lint、typecheck、测试套件构成快速反馈回路。回路必须快——慢验证 = 少迭代。Agent 在有限时间内能尝试的修复就更少。
Geoffrey Huntley 用一个极端例子证明了这点:他用 $297 完成了一个 $50,000 的合同,关键就在于把验证回路压缩到秒级。
6. Git 是安全网,不是仪式
每个任务完成后提交。不是因为”应该提交”,而是因为恢复只需要 git reset --hard。当 Agent 搞砸时(它会的),你需要一个可靠的回退点。
7. 简化,再简化
每个 Harness 组件都编码了一个假设:“模型不能自己做到这个”。模型在进步,假设在过时。定期检查:这个组件还有必要吗?
三行重复代码好过一个过早抽象。今天需要 Hook 保障的东西,明年可能模型原生就支持了。
架构全景
harness/
├── .claude/
│ ├── settings.json Hook 配置(确定性护栏)
│ └── skills/harness/ 交互式工作流技能
│ ├── SKILL.md 入口:分类 → 澄清 → 计划 → 执行 → 评估
│ └── references/ 计划格式、会话协议、评估指南
├── .harness/
│ ├── config.json 唯一需要编辑的文件
│ ├── runner.py 无头执行器(CI / 批量处理)
│ ├── evaluator.py 怀疑论评估器(独立会话)
│ ├── hooks/ Hook 脚本
│ │ ├── pre-commit-check.sh 仅代码文件触发 lint/typecheck
│ │ ├── pre-push-verify.sh 推送前完整验证
│ │ └── post-edit-check.sh 编辑后即时语法检查
│ ├── plans/ 任务计划(JSON)
│ ├── eval_feedback/ 评估判定结果
│ └── progress.md 跨会话记忆
├── docs/
│ ├── best-practices.md 设计原则
│ └── research/ 四篇原始研究论文
└── CLAUDE.md Agent 入口(地图,非百科)
关键组件
config.json — 唯一需要编辑的文件
{
"verify_cmd": ["npm", "test"],
"source_dirs": ["src/"],
"test_dirs": ["src/__tests__/"],
"hooks": {
"pre_commit_lint": true,
"pre_commit_typecheck": true,
"pre_push_verify": true
}
}
不管是 Go 后端、Node.js 前端、Rust CLI 还是 Python 数据管道——改 config.json 就行,不需要重写 Harness。
runner.py — 无头执行器
用于 CI 流水线或批量处理,不需要人工介入:
# 执行计划中的下一个任务
python3 .harness/runner.py --plan .harness/plans/fix-login.json
# 循环执行所有任务
python3 .harness/runner.py --plan .harness/plans/fix-login.json --loop
# 只看状态,不执行
python3 .harness/runner.py --status
SKILL.md — 交互式工作流
在 Claude Code 中直接使用,适合日常开发。贴入一段 bug 报告或功能需求,Skill 自动引导完整流程:
你贴入反馈
│
▼
分类 → 归类为 bug / feature / improvement / chore
│
▼
澄清 → 提出针对性问题(最多 2 轮)
│
▼
计划 → 创建 .harness/plans/{slug}.json
│
▼
执行 → 验证基线 → TDD 实现 → 验证 → 评估
│ ↑ │
│ └── FAIL (最多 2 次) ──────┘
▼
完成 → 提交,更新进度笔记
通用性:一套 Harness,所有项目
Harness 不绑定任何语言或框架。项目类型的差异全部通过 config.json 吸收:
| 项目类型 | verify_cmd | source_dirs | 说明 |
|---|---|---|---|
| Astro 前端 | ["npm", "run", "build"] | ["src/"] | 本站使用的配置 |
| Go 后端 | ["make", "check"] | ["cmd/", "internal/"] | lint + test + build |
| Rust CLI | ["cargo", "test"] | ["src/"] | Cargo 原生测试 |
| Python 数据 | ["pytest"] | ["src/"] | pytest 驱动 |
| Node.js API | ["npm", "test"] | ["src/", "lib/"] | Jest / Vitest |
Hook 脚本自动检测项目类型(Makefile / package.json / pyproject.toml / Cargo.toml),无需手动配置。
研究基础
Harness 站在巨人的肩膀上。我们从四篇文献中提炼出了共同的设计原则,并在此基础上加入了 Hook 确定性护栏——这是我们的原创贡献。
| 文献 | 核心贡献 | 来源 |
|---|---|---|
| Harness Design for Long-Running Apps | Generator + Evaluator 对抗模式 | Anthropic, 2026.3 |
| Effective Harnesses for Long-Running Agents | 两阶段 Agent 架构;Context Anxiety | Anthropic, 2025.11 |
| Harness Engineering for Codex | 仓库即真相;AGENTS.md 是地图 | OpenAI, 2026.2 |
| The Ralph Wiggum Technique | 一次一个任务;验证即反压 | Geoffrey Huntley, 2025.7 |
更深入的文献交叉解读,请参阅 Harness Engineering 学习指南。
十大共识原则
从 Anthropic、OpenAI 和社区的实践中,我们提炼出十条跨团队共识的设计原则:
- 上下文管理 — 窗口是稀缺资源,不是垃圾桶。每次会话聚焦一件事。
- 结构化交接 — 会话间通过 JSON 计划 + Markdown 笔记传递状态,不靠上下文窗口记忆。
- 反馈回路 — 验证必须快。慢反馈 = 少迭代 = 低质量。
- 任务分解 — 大需求拆成小任务,每个任务有明确的验收标准。
- 生成与评估分离 — 写代码的和审代码的必须互相不认识(独立上下文)。
- Harness 随模型进化 — 定期审视每个组件的必要性。
- 仓库即真相 — Agent 访问不到的等于不存在。
- 渐进式披露 — 不要一次性把所有信息塞给 Agent。
- 确定性护栏 — Hook 保障 Prompt 覆盖不到的场景。
- Git 是安全网 — 每个任务提交一次,回退永远有保障。
快速上手
前置条件
- Claude Code CLI 已安装
- Python 3.10+(无头执行器需要)
- Git
安装
Harness 不是 npm 包——它是一组你放入项目的文件:
# 克隆并复制到你的项目
git clone https://github.com/anxiong2025/harness.git /tmp/harness
cp -r /tmp/harness/.claude /tmp/harness/.harness /tmp/harness/CLAUDE.md your-project/
# 编辑配置
vim your-project/.harness/config.json
30 秒开始使用
cd your-project
# 1. 配置你的项目验证命令
# 编辑 .harness/config.json 中的 verify_cmd
# 2. 交互模式:打开 Claude Code,贴入需求
# Claude 自动进入 harness 工作流
# 3. 无头模式:批量处理
python3 .harness/runner.py --plan .harness/plans/your-plan.json --loop
这不是银弹
Harness 不会让 AI Agent 变得完美。它让 Agent 的失败变得可预测、可检测、可恢复。
- 可预测 — 知道 Agent 会在哪里出错(自我评估过高、上下文焦虑、跳过步骤)
- 可检测 — Evaluator 在独立上下文中审查,Hook 在确定性层面拦截
- 可恢复 — 每个任务一个 commit,回退成本几乎为零
这就够了。完美不是目标,可靠才是。
GitHub 仓库:harness — 记得 Star
完整中文 README:README.zh-CN.md