最近看到不少关于 harness engineering 的文章,中文圈和英文圈都有。

但大多数只是在讲概念,细节很少。而且说实话,有些系统描述得太复杂了,很难相信它们真的能稳定跑起来。

于是周末我自己动手试了试。


说来有点好笑,我做过很多个人项目,但大部分撑不过 10 次迭代。所谓"撑不住",就是进入了一种死循环:加一个功能引入了 bug,修这个 bug 又带来新的 bug。

harness engineering 要解决的,正是这种螺旋式崩塌。

很多人把它讲得很复杂。但我自己尝试下来,核心思路其实挺朴素的。原文 中其实有两点,我觉得非常关键。


第一条:让 worktree 能直接启动。

这是让多个 agent 并行工作的前提。

前端包管理器用 bun(或者 pnpm),不要把时间浪费在装依赖上。数据 pipeline 的环境依赖用 uv 管理。每一个 worktree 都能快速启动。


第二条:定好标准。

把每个需求当成一张完整的 ticket 来处理。Lint、单元测试、构建通过——这些是基础。但如果是有 UI 的应用,UI 测试是比较关键的一环。

这里我用的是 agent browser Playwright CLI 。它们和传统 e2e 测试不同,不会因为 selector 变了就挂掉。你只需要配合它们跑一两轮,描述你的应用长什么样,然后把结果写进一个 markdown 文件。

之后你只需要说:“当我点击 X Button 时,Y 应该出现。”

验证规则用纯自然语言描述就行了。


定下这两条规则花了我最多的时间。剩下的——技术栈和基础设施——我自己来决定。代码交给 agent 写,架构还是得自己拿主意。

然后,构建过程就开始自己运转起来了。


我创建了一个叫 decision-plan 的 skill。

给它一个最小需求描述(需要包含P0 用例),它会:

  • 探索代码库
  • 基于需求生成一份 ADR(架构决策记录)
  • 生成一份 execution plan(执行计划)

ADR 负责高层设计、背景和"为什么";execution plan 负责"怎么做"——具体到哪些文件要改。execution plan 里有指向 ADR 的反向链接。两者都以代码形式存在于代码库中。

我还创建了一个 index.md,作为轻量级的索引,让 agent 能快速找到对应的 ADR,而不用把所有文件都扫一遍。随着 ADR 不断积累,它们自然形成了一个知识库——每次调用 skill,新的 ADR 都会尝试自动引用已有的。


然后是构建阶段。

我创建了另一个 skill:build-and-ship。它的执行流程是:

  1. 创建一个 worktree,确保它能启动
  2. 读取 execution plan
  3. 执行计划
  4. Lint / 单元测试 / 构建
  5. 启动一个开发服务器(随机端口),跑 smoke test(Playwright)
  6. agent browserPlaywright CLI 做视觉验证,保存截图和录屏
  7. 全部通过就合并回 main,有任何失败就修复

我的完整工作流:开 4 个终端,用 decision-plan 并行生成 ADR 和 execution plan,完成后清空上下文。然后执行 /build-and-ship ADR-0012。就这样,我跑了48 个 ADR,完成了基本上所有的需求。

代码库中不断积累的 execution plan

我也试过用 Ralph loop 做更自动化的尝试——把 4 个 ADR 合并成一个 PRD 喂给它,让它自主运行。loop 本身没问题,但任务拆分不够理想,导致一些验证点被遗漏,bug 也随之增多。

不过我觉得,现有的 ADR / 工作流组织方式,离真正支持全自动化并不远。


那我用这套东西究竟做了什么?InvestBuddy ——导入你的券商数据,查看持仓表现,导出税务报表。所有数据都留在浏览器里,没有任何服务端存储。


我学到了什么?

1. 好的需求 + 清晰的验证点,是给 agent 最好的资源。

2. 我不再扮演 engineer 的角色,深入代码细节,而更像是一个 PM。

其实刚开始会有点失控的感觉,但慢慢习惯了。看着自己搭的东西真正解决了自己的问题,反而更有满足感。

3. 简单永远优于复杂。

这套 ADR 方案大概不会扩展到几百个 ADR——上下文限制会来,agent 的记忆会衰减。但它在这个小项目里能用,就够了。

Build it simple. Make it work. When it breaks, fix it.