AI Agent写了代码就说"完成了"?一套Harness模板,把它钉死在轨道上

从失忆、假完成、越界改代码——到跨会话稳定交付的实战指南


*“代码已经写好了,功能应该可以用了。”

如果你用过 AI 编码 Agent(Claude Code、Codex、Cursor……),这句话你一定不陌生。Agent 自信满满地说"完成",你打开一看:测试没跑、功能只有一半、甚至改着改着把别的地方搞坏了。

更糟糕的是,下一轮会话开始,Agent 完全失忆——它不知道上一轮做了什么、做到哪了、哪里还是坏的。你只能从头解释一遍,然后祈祷它别又跑偏。

这不是某个 Agent 的问题,这是当前所有 AI 编码 Agent 的结构性缺陷。而今天要讲的这套 Harness 模板,就是用来解决这个问题的。


01 问题:AI编码Agent的三宗罪

在长周期、多会话的编码任务中,AI Agent 几乎都会犯同样的三类错误。不是模型不够聪明,是缺少约束机制

第一罪:跨会话失忆

每一轮会话都是独立的。Agent 不记得上一轮做了什么、做到哪了、哪些验证通过了。它会读聊天记录,但聊天记录是不可靠的——里面充斥着"我试试看""应该可以了"这种模糊表述,根本无法作为可靠的工作状态。

结果:每一轮会话都在"重新理解项目",大量时间浪费在重建上下文上。

第二罪:假完成

Agent 天然倾向于取悦用户。它写了代码,就声称"功能已完成"。但"写了代码"和"功能能用"之间,隔着一条巨大的鸿沟:

  • 验证步骤跑了吗?——没有。
  • 跑过了,结果记录了吗?——没有。
  • 重启之后还能用吗?——不确定。
  • 功能清单更新了吗?——什么功能清单?

结果:你以为做完了,实际上一堆半成品。越往后做,积攒的技术债越重,直到某天全线崩盘。

第三罪:范围越界

你让 Agent 做功能 A,它做着做着发现功能 B 也需要改,于是顺手改了。改完发现功能 C 的测试挂了,又去修 C。最后你回头一看:A 没做完,B 改了一半,C 被改出了新 bug。

结果:改动像滚雪球一样失控,每一轮会话结束时代码库都处于不确定状态。


02 什么是Harness?一句话说清

Harness 的本意是"马具"——套在马身上的缰绳和马鞍,用来控制马匹方向、让它跑在正确的道路上。

在 AI Agent 语境下,Harness 是一套围绕 Agent 的工作流约束系统。它不是代码框架,不是中间件,而是一组文件 + 规则 + 流程,把 Agent 钉在轨道上:

目标不是尽可能快地产出代码,而是让每一轮会话结束后,下一个会话仍然能无猜测地继续工作。

这句话来自这个项目的根指令文件 AGENTS.md,也是整个 Harness 哲学的核心。

打个比方:没有 Harness 的 Agent 像是一个没有项目管理的新人程序员——能力很强,但没人告诉他先做什么后做什么、做完要检查什么、怎么交接。Harness 就是那个项目管理机制。


03 Harness的六大组件

这套模板项目提供了六个核心文件,每个文件在 Agent 工作流中各有分工。它们不是"可选的文档",而是 Agent 必须读写的工作件。

AGENTS.mdinit.shfeature_list.jsonprogress.mdhandoff.mdchecklist.md

① AGENTS.md / CLAUDE.md —— 根指令文件

这是 Agent 每次开工会第一个读的文件。它定义了三件事:

  • 开工流程:确认目录 → 读进度日志 → 读功能清单 → 看最近提交 → 运行 init.sh → 跑 smoke test
  • 工作规则:一次只做一个功能、不假完成、不越界、不偷偷弱化验证
  • 完成定义:目标行为已实现 + 验证真的跑过 + 证据已记录 + 仓库可重启

AGENTS.mdCLAUDE.md 内容一致,只是格式适配不同 Agent——前者给 Codex 等通用 Agent,后者给 Claude Code。

关键设计:完成定义那一段是整个 Harness 的核心。项目文档里明确写了:“完成定义那一段别改——那是整个 harness 最关键的部分。” 四个条件缺一不可,没有讨价还价的余地。

② init.sh —— 统一启动入口

一条命令完成三件事:安装依赖 → 跑验证 → 打印启动命令。

#!/usr/bin/env bash
set -euo pipefail

# 按你的项目实际情况替换这些命令
INSTALL_CMD=(npm install)
VERIFY_CMD=(npm test)
START_CMD=(npm run dev)

echo "==> 当前目录: $PWD"
echo "==> 同步依赖"
"${INSTALL_CMD[@]}"

echo "==> 运行基础验证"
"${VERIFY_CMD[@]}"

echo "==> 启动命令"
printf '    %q' "${START_CMD[@]}"

这个文件的设计哲学是:如果基础验证一开始就失败,先修基础状态,不要在坏的起点上继续叠新功能。

这个原则极其重要。很多开发者拿到 Agent 后让它直接写新功能,完全不管现有测试是不是绿的。结果新功能写在一个已经损坏的基础上,越写越乱。init.sh 强制每一轮会话都从验证通过的状态开始。

③ feature_list.json —— 功能状态的唯一事实来源

这是一个机器可读的 JSON 文件,列出项目的所有功能,每个功能包含:

字段 说明
id 短唯一标识,如 chat-001
priority 整数,越小越优先
area 功能所属区域,如 chatimport
user_visible_behavior 功能正常时用户能看到什么
status 四种状态之一(见下文)
verification 逐步验证步骤
evidence 验证通过的记录

四种状态是 Harness 最精妙的设计之一:

状态 含义
not_started 还没碰
in_progress 当前唯一正在做的(同一时间只能有一个)
blocked 有记录的阻塞问题,推不动
passing 验证通过,证据已记录

铁律:Agent 任何时候只能有一个功能处于 in_progress 这条规则直接消灭了"范围越界"的问题——你想做别的?先把当前的做完或标记为 blocked。

④ claude-progress.md —— 进度日志

每轮会话往里写,每轮新会话先读它。它记录的不是流水账,而是结构化的状态快照

  • 当前已验证状态:仓库根目录、标准启动路径、标准验证路径、当前最高优先级未完成功能、当前 blocker
  • 会话记录:每轮一条,包含目标、完成内容、验证结果、证据、提交记录、已知风险、下一步

这个文件解决的是"失忆"问题。Agent 不需要读聊天记录猜上次做了什么——进度日志就是唯一真相。

⑤ session-handoff.md —— 交接摘要

比进度日志更简短的交接文档。适用于会话较长或项目有多个并行区域时,让接手的人或 Agent 快速了解现状:

  • 哪些是确认能用的
  • 本轮改了什么
  • 仍损坏或未验证的部分
  • 下一步该做什么、哪些不要动
  • 启动、验证、调试命令速查

⑥ clean-state-checklist.md —— 收尾检查清单

每次会话结束前逐项检查,确保仓库处于下一轮可直接开工的状态:

[ ] 标准启动路径仍然可用
[ ] 标准验证路径仍然可运行
[ ] 当前进度已经记录到进度日志
[ ] 功能状态真实反映了 passing 和未验证的边界
[ ] 没有任何半成品步骤处于未记录状态
[ ] 下一轮会话无需人工修复即可继续

最后一条尤其关键:没有假 passing。功能清单里的状态必须真实反映实际情况——通过了就是通过了,没验证就是没验证,不存在"应该可以了吧"这种灰色地带。


04 四条铁律:Harness的约束引擎

六大组件是"硬件",四条铁律是驱动它们的"软件"。这些规则被写进了 AGENTS.md,Agent 每次开工都会读到:

铁律一:一次只做一个功能

功能清单里同一时间只能有一个 in_progress。想做别的?先把当前的推到 passing,或者明确标记为 blocked 并记录原因。

这条规则看起来简单,但它从根源上消灭了"范围越界"。Agent 不能再以"我顺手改一下"为借口扩散改动范围。

铁律二:没有证据不算完成

不要因为"代码已经写了"就把功能标记为完成。

完成定义有四个条件,缺一个都不行:

1. 目标行为已经实现
2. 要求的验证真的跑过
3. 证据记录在 feature_list.json 或 claude-progress.md
4. 仓库仍然能按标准启动路径重新开始工作

第4条最容易被忽略:你改完代码,仓库还能正常启动吗?如果不能,功能就不算完成——哪怕代码本身是对的。

铁律三:文件是唯一事实来源

优先依赖仓库里的持久化文件,而不是聊天记录。

聊天记录是易失的、模糊的、不可验证的。仓库里的文件(进度日志、功能清单、交接摘要)是持久的、结构化的、可验证的。Harness 把所有状态都写到文件里,让 Agent 的每一轮会话都从一个确定的起点出发。

铁律四:每轮必须干净收尾

收尾流程是固定的:

1. 更新 claude-progress.md
2. 更新 feature_list.json
3. 记录仍未解决的风险或 blocker
4. 在工作处于安全状态后,用清晰的提交信息提交
5. 保证下一轮会话可以直接运行 ./init.sh

第5条意味着:你关掉终端后,另一个人(或另一个 Agent)打开仓库,运行 ./init.sh,就能直接继续工作。不需要人工修复,不需要解释上下文,不需要"你先跑一下xxx"。


05 质量闭环:评审与质量快照

六大组件 + 四条铁律解决了"工作流"问题。但还有两个问题没回答:

  • 这轮 Agent 做得好不好?
  • 这个项目是在变强还是变弱?

Harness 用两个文件回答这两个不同的问题。

evaluator-rubric.md —— 评单次输出质量

六个维度,每个 0-2 分:

维度 核心问题
正确性 实现出来的行为是否符合目标功能?
验证 要求的检查是否真的跑过,并留下证据?
范围纪律 这一轮是否基本保持在选定功能范围内?
可靠性 结果是否能在重启或重跑后继续工作?
可维护性 代码和文档是否清楚到足以交给下一轮会话?
交接准备度 新会话是否能只靠仓库内工件继续推进?

结论三选一:Accept(达标)/ Revise(需修补)/ Block(有根本性问题)。

⚠️ 重要提醒:Evaluator 需要校准

项目文档里有一段非常清醒的警告:“开箱即用的 agent 做评审很弱——它会发现问题,然后把自己说服到通过。” 你需要用 evaluator 给已完成的 sprint 打分,和人工判断对比,把分歧写进 rubric,重新跑,反复 3-5 轮直到对齐。这不是可选步骤——不做校准的 evaluator 会变成橡皮图章。

quality-document.md —— 评代码库本身质量

给项目的每个产品领域和架构层打 A-D 的等级,跟踪代码库随时间是变强了还是变弱了:

  • 产品领域(如文档导入、问答流程):按验证状态、Agent 可读性、测试稳定性、关键缺口打分
  • 架构层(如 Main Process、Renderer、Services):按边界执行和 Agent 可读性打分

这两个文件回答的是不同的问题——一个是"这轮做得好不好",一个是"项目整体健不健康"。两者配合,构成了 Harness 的质量闭环


06 实战流程:一轮完整会话长什么样

把所有组件串起来,一轮标准会话的流程是这样的:

开工阶段(读)

# 1. 确认位置
$ pwd
/home/project/my-app

# 2. 读进度日志 → 知道上次做到哪了
# 3. 读功能清单 → 知道该做什么
# 4. 看最近提交 → 知道最新改动
$ git log --oneline -5

# 5. 运行 init.sh → 安装依赖 + 跑验证
$ ./init.sh
==> 当前目录: /home/project/my-app
==> 同步依赖
==> 运行基础验证
==> 启动命令: npm run dev

# 6. 基础验证通过?→ 选一个功能开干
# 基础验证失败?→ 先修基础状态,不叠新功能

工作阶段(做)

只围绕一个功能工作。实现 → 验证 → 记录证据。不碰别的功能,不弱化验证规则,不偷偷改功能清单的状态。

收尾阶段(写)

# 1. 更新进度日志
# 2. 更新功能清单状态
# 3. 记录未解决的风险
# 4. 过一遍收尾检查清单

# clean-state-checklist.md
[x] 标准启动路径仍然可用
[x] 标准验证路径仍然可运行
[x] 当前进度已经记录到进度日志
[x] 功能状态真实反映了 passing 和未验证的边界
[x] 没有任何半成品步骤处于未记录状态
[x] 下一轮会话无需人工修复即可继续

# 5. 提交
$ git add -A && git commit -m "feat(chat): chat-001 创建新会话 - 验证通过"

下一轮会话开始时,Agent 运行 ./init.sh,读进度日志和功能清单,就知道该做什么、做到哪了。零猜测、零重复解释、零状态丢失。


07 如何落地到你的项目

四步快速上手:

第一步:复制四个核心文件

把以下文件复制到你的项目根目录:

  1. AGENTS.md(或 CLAUDE.md,取决于你用的 Agent)
  2. init.sh
  3. claude-progress.md
  4. feature_list.json

项目简单时,这四个文件就够了。等项目变复杂了,再补 session-handoff.mdclean-state-checklist.mdevaluator-rubric.mdquality-document.md

第二步:改 init.sh 的三个变量

# 你的依赖安装命令
INSTALL_CMD=(npm install)        # 或 pip install -r requirements.txt

# 你的基础验证命令
VERIFY_CMD=(npm test)            # 或 pytest

# 你的开发服务器启动命令
START_CMD=(npm run dev)          # 或 python manage.py runserver

第三步:填功能清单

feature_list.json 里的示例功能换成你自己的。每个功能填上 idpriorityuser_visible_behaviorverification 步骤。

第四步:填进度日志的初始状态

claude-progress.md 里的"当前已验证状态"填上:仓库根目录、启动路径、验证路径、最高优先级未完成功能。

给 init.sh 加执行权限:chmod +x init.sh。然后运行 ./init.sh,确认整个链路跑通。

适配指南:把 AGENTS.md 开工流程里的路径和命令换成你项目的。工作规则按团队约定调整。但完成定义那一段别改——那是整个 Harness 最关键的部分,改了就等于拆掉了刹车。


08 深层思考:Harness的本质是什么?

这套 Harness 模板里最深刻的洞察,藏在 quality-document.md 的说明里:

Harness 里的每个组件都编码了一个假设——“模型做不到这件事”。
模型变强后,这些假设就过时了。

这句话值得反复品味。来拆解一下:

每个组件都对应一个"模型做不到的事"

Harness 组件 它编码的假设
AGENTS.md(根指令) 模型不会自己建立工作流程
init.sh(启动脚本) 模型不会先验证再干活
feature_list.json(功能清单) 模型记不住所有功能的状态
claude-progress.md(进度日志) 模型跨会话会失忆
session-handoff.md(交接摘要) 模型不会主动总结交接信息
clean-state-checklist.md(检查清单) 模型收尾时不全面
evaluator-rubric.md(评审表) 模型不会自检质量
quality-document.md(质量快照) 模型不会跟踪项目健康度

模型变强后,Harness 应该变薄

Harness 不是越多越好。项目文档里给出了一个清晰的验证方法——移除实验法

  1. 拍一份 quality-document 快照
  2. 移除一个 Harness 组件
  3. 跑基准测试
  4. 再拍一份快照
  5. 对比——评级没降,说明那个组件是多余的;降了,就恢复

这是一个进化型系统的设计思路:Harness 会随着模型能力的提升而逐渐变薄。今天必须有的约束,可能在下一代模型上就变成了多余的官僚主义。

但关键是:在你还没验证模型能自己做到之前,约束就必须存在。 与其赌模型能自律,不如用 Harness 兜底。


总结:Harness 解决了什么问题

回到开头说的三宗罪:

问题 Harness 怎么解决
跨会话失忆 进度日志 + 功能清单作为持久化状态文件,替代聊天记录
假完成 完成定义四条件 + 证据记录 + 收尾检查清单
范围越界 功能清单的单一 in_progress 约束 + 范围纪律评审维度

本质上,Harness 做的事情只有一件:把 Agent 从"看起来在干活"变成"真的在交付"

它不帮你写代码,但它确保每一轮会话结束时,代码库处于一个确定的状态——下一轮可以直接接着干。这才是长周期 AI 编码的真正难题:不是写代码,是管理状态

如果你正在用 AI Agent 做多轮、多功能的编码项目,这套模板值得直接拿来用。四个文件,四条铁律,从今天开始把你的 Agent 钉在轨道上。


Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐