Harness Engineering实战:给 Agent 划清每次任务的边界示例
Harness Engineering实战:给 Agent 划清每次任务的边界示例
一、背景与一句话结论
你让 Agent “给项目加上用户认证”,它很可能同时改了数据库 schema、写路由、改前端组件,还顺手重构了错误处理中间件。两小时后 12 个文件被改、800 行新代码,却没有一个功能端到端跑通。
一句话结论:Agent 天生有"多做一点"的冲动,必须给它划清每次任务的边界——WIP=1(做完一个再做下一个),并用"完成证据"和"验证完成率(VCR)"强制约束。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
二、核心知识点讲解
2.1 注意力是有限的资源(数学本质)
Agent 的上下文容量为 C,同时激活 k 个任务,每个任务平均获得 C/k 的推理资源。当 C/k 低于完成单个任务所需的最小阈值时,所有任务都做不完。这正是"贪多嚼不烂"的数学表述。Anthropic 实验数据直接支持:使用"小下一步"(等价于 WIP=1)策略的 Agent,任务完成率比宽泛提示高 37%;且代码行数与功能完成率呈弱负相关——写得越多,完成得越少。
2.2 两个共生问题
- 过度延伸(Overreach):一次会话中激活的任务数超过最优值。可量化:同时做 5 个功能但 0 个跑通,就是 overreach。
- 不足完成(Under-finish):已启动任务中,通过端到端验证的比例低于阈值。写了代码但没跑通测试,就是 under-finish。
二者互相加剧:overreach → 注意力分散 → under-finish → 半成品增加复杂度 → 下一任务更易 overreach。恶性循环。用 Kanban 的 Little 法则(L = λ·W)解释:在制品 L 过大,每个任务的前置时间 W 必然拉长,失败概率被放大。
2.3 核心概念术语表
- WIP 限制(Work-in-Progress Limit):来自 Kanban,限制同时进行的任务数。对 Agent,WIP=1 是最安全的默认值。
- 完成证据(Completion Evidence):任务从"进行中"变"已通过"必须满足的可验证条件。"代码看起来没问题"不算,"curl 返回 201"才算。
- 范围表面(Scope Surface):DAG,每个节点是一个工作单元,边是依赖。状态只有四种:未开始、进行中、阻塞、已通过。
- 验证完成率(VCR):已通过验证的任务数 / 已启动的任务数。VCR < 1.0 时,阻止新任务启动。
- 完成压力(Completion Pressure):harness 通过 WIP 限制 + 完成证据要求共同产生的约束力,迫使 Agent 先完成再开始。
2.4 实施方法(四条)
- 强制 WIP=1:在 AGENTS.md / CLAUDE.md 写明——每次只做一个功能点,端到端验证通过后才能开始下一个,不要在实现 A 时"顺便"重构 B。
- 给每个任务定义显式完成证据:功能列表里每个条目都要有验证命令(如
curl ... | jq .status == 201)。 - 把范围表面外部化:用机器可读文件(JSON/Markdown)记录所有任务状态,任何新会话直接读,知道"谁在做、什么算完成、已通过什么验证"。
- 监控验证完成率:持续跟踪 VCR;VCR < 1.0 时阻止新任务启动。
2.5 实际案例(8 个功能点的 REST API)
| 维度 | 无约束模式 | WIP=1 模式 |
|---|---|---|
| 首会话同时启动功能数 | 5 | 1 |
| 首会话代码量 | ~800 行 / 12 文件 | ~200 行 / 4 文件 |
| 端到端测试通过率 | 20%(仅注册跑通) | 100% |
| 第 3~4 会话后完成功能数 | 3 / 8 | 7 / 8 |
| 完成率 | 37.5% | 87.5% |
结果:WIP=1 总代码量更少但有效代码更多。“少做但做完"永远优于"多做但做半”。
2.6 核心要点总结
- WIP=1 是 agent harness 的默认安全设置:做完一个再做下一个。
- 完成证据必须可执行:行为验证通过才算完成。
- 范围表面必须外部化为文件:不能只在对话里说。
- overreach 与 under-finish 是共生问题:解决一个就解决了另一个。
- “少做但做完"永远优于"多做但做半”:质量永远比数量重要。
三、示例代码搭建
技术栈:Spring Boot 3.2.5 + Java 17 + Maven,包名 com.badao.ai,沿用 harness/{state,gates,skills} 分层与 instructions/ 模块化指令、state/ 跨会话状态。
3.1 目录结构
spring-ai-alibaba-bailian-harness-scope/
├── pom.xml
├── state/
│ ├── SCOPE_SURFACE.md ← 范围表面(机器可读,外部化)
│ └── DECISIONS.md ← 边界事件留痕(overreach/under-finish)
└── src/
├── main/java/com/badao/ai/
│ ├── SpringAiDemoApplication.java
│ ├── config/ScopeConfig.java ← 模块化指令(按阶段组装提示词)
│ ├── controller/ScopeController.java ← /api/tasks、/api/scope/*
│ ├── model/WorkUnit.java ← 范围表面节点(含 Status 枚举)
│ ├── service/TaskScopeService.java ← 编排范围控制
│ ├── runner/ScopeDemoRunner.java ← 启动即演示 WIP=1
│ └── harness/
│ ├── state/TaskScopeManager.java ★ 核心:WIP=1 + VCR 红线 + 范围表面
│ ├── gates/WipGate.java ★ 核心:完成压力(wipOk/vcrOk 验收)
│ ├── skills/CompletionEvidenceSkill.java ★ 完成证据(可执行验证)
│ └── state/ScopeSurfaceManager.java ★ 范围表面外部化到 state/
└── test/java/com/badao/ai/
├── TaskScopeManagerTest.java ← WIP=1 / VCR 逻辑单测
├── WipGateTest.java ← 闸门判定单测
├── WipComparisonTest.java ← WIP=1 vs 无约束 对比实验
└── CompletionEvidenceTest.java ← 完成证据单测
3.2 核心类逐一讲解
(1)WorkUnit —— 范围表面的节点
public class WorkUnit {
public enum Status { NOT_STARTED, IN_PROGRESS, BLOCKED, PASSED }
private final String id;
private final String title;
private Status status; // 四种状态之一
private final String verifyCommand; // 完成证据(可执行验证命令)
private final List<String> deps; // DAG 边(依赖)
}
(2)TaskScopeManager —— WIP=1 + VCR 红线(范围表面核心)
它维护 DAG,并强制两条约束。startTask 在违反约束时抛出 IllegalStateException(即"完成压力"生效):
public void startTask(String id) {
WorkUnit unit = require(id);
if (!canStartNewTask()) { // WIP 超 || VCR<1.0
String reason = currentInProgress().isEmpty()
? "存在未完成(under-finish),VCR<1.0,必须先收尾"
: "已有任务进行中(overreach),WIP 限制禁止并行启动";
throw new IllegalStateException("无法启动任务 " + id + ":" + reason);
}
// ...依赖检查...
unit.setStatus(WorkUnit.Status.IN_PROGRESS);
}
public boolean canStartNewTask() {
if (currentInProgress().size() >= wipLimit) return false; // WIP 违规
long started = countStarted(), passed = countPassed();
return started == 0 || passed >= started; // VCR>=1.0
}
public double getVcr() { // 验证完成率
long started = countStarted();
return started == 0 ? 1.0 : (double) countPassed() / started;
}
注意 markPassed 要求任务处于 IN_PROGRESS——只有行为验证通过才允许置 passed,杜绝"代码看起来没问题"。
(3)WipGate —— 把"完成压力"变成可自动验证的硬指标
public GateReport verify() {
boolean wipOk = !scopeManager.isOverreaching();
boolean vcrOk = scopeManager.getVcr() >= 1.0 || scopeManager.countStarted() == 0;
return new GateReport(wipOk, vcrOk, inProgress, started, passed);
}
// GateReport.allGreen() = wipOk && vcrOk;overreach() = !wipOk;underFinish() = !vcrOk
(4)CompletionEvidenceSkill —— 完成必须靠证据
public WorkUnit buildWorkUnit(String id, String behavior, String verifyCommand, List<String> deps) {
return new WorkUnit(id, behavior, verifyCommand, deps);
}
public boolean verify(String expected, String actualOutput) {
return actualOutput != null && actualOutput.contains(expected);
}
(5)ScopeSurfaceManager —— 范围表面外部化
把 toReport() 写入 state/SCOPE_SURFACE.md,并把 overreach / under-finish 事件留痕到 state/DECISIONS.md,使任何新会话只看仓库即可接手。
3.3 服务、控制器、启动器、配置
TaskScopeService:编排上述组件。startTask在越界时捕获异常、记录边界事件、返回失败结果(而非静默放行);runDemo依次做完再做下一个,并展示并行启动被拒绝。ScopeController:POST /api/tasks(加任务)、POST /api/tasks/{id}/start(受闸门约束)、POST /api/tasks/{id}/complete?evidencePassed=(需证据)、GET /api/scope/report|vcr|gate、POST /api/scope/demo。ScopeDemoRunner:CommandLineRunner,应用启动即演示 WIP=1。ScopeConfig:模块化指令——规划阶段给"范围表面",实现阶段给"完成证据",并保留legacy/GIANT_AGENTS.md作反面教材。
3.4 测试即"可验证"的落地
WipComparisonTest 即课程"课后练习 2"的自动化:
@Test
void wipOneModeAchievesFullVcr() {
TaskScopeManager mgr = new TaskScopeManager(1);
// 依次 start+pass F01..F03
assertEquals(1.0, mgr.getVcr(), 0.0001);
assertTrue(new WipGate(mgr).verify().allGreen());
}
@Test
void unconstrainedModeLeavesLowVcr() {
TaskScopeManager mgr = new TaskScopeManager(5); // 无 WIP 纪律
for (int i = 1; i <= 5; i++) { mgr.addTask(...); mgr.startTask("F0"+i); }
mgr.markPassed("F01"); // 仅 1 个真正验证通过
assertEquals(0.2, mgr.getVcr(), 0.0001);
assertFalse(new WipGate(mgr).verify().allGreen());
}
四、如何运行
# 1) 编译并跑测试(无需大模型 Key,验证 WIP/VCR 逻辑)
mvn test
# 2) 触发 WIP=1 演示
mvn spring-boot:run
curl -X POST "http://localhost:887/api/scope/demo"
# 3) 体验边界约束
curl -X POST "http://localhost:887/api/tasks?id=F01&title=注册&verify=status==201"
curl -X POST "http://localhost:887/api/tasks/F01/start" # 成功
curl -X POST "http://localhost:887/api/tasks/F02/start" # 被 WIP 闸门拒绝
curl -X POST "http://localhost:887/api/tasks/F01/complete?evidencePassed=true"
curl "http://localhost:887/api/scope/gate" # 查看 wipOk/vcrOk
curl "http://localhost:887/api/scope/vcr" # 查看 VCR
运行完整 Web 应用需设置
DASHSCOPE_API_KEY;测试与范围控制逻辑不依赖它。
预期:/api/scope/demo 返回 gateAllGreen=true、VCR=1.0;并行启动第二个任务时被拒绝并记入边界事件。
五、课程课后练习(建议动手)
- 任务原子化:选一个宽泛需求(如"实现用户管理系统"),拆成 ≥5 个原子单元,每个写清(a)单一行为(b)可执行验证命令©依赖,检查是否满足 WIP=1。
- 对比实验:同一项目跑两次,一次无约束、一次强制 WIP=1,比较 VCR、总代码行数、有效代码比例(本工程
WipComparisonTest已给出自动化雏形)。 - 完成证据审计:回顾一次 Agent 运行,把每个变更分为"已完成行为 / 未完成行为 / 脚手架",给未完成行为补验证命令。
六、小结
第七讲的本质,是把"边界"从一句口头提醒提升为 harness 的一等约束:TaskScopeManager 用 WIP=1 拦住过度延伸、用 VCR 红线拦住不足完成;WipGate 把"完成压力"变成可自动验证的硬指标;CompletionEvidenceSkill 确保"完成"靠行为证据而非感觉;ScopeSurfaceManager 把范围表面外部化到仓库,让新会话无需任何口头交代即可接手。当 Agent 每次只推进一个被验证过的任务,它才真正"做完"而不是"做一半"。
更多推荐




所有评论(0)