你的 Agent 并不自主:你就是它的循环
它写你读,它说"搞定了"你验。这三层不是三件工具,是台阶:harness 给手脚,循环给能失败的检查,图给形状和闸门。
你并不是在"使用"你的 Agent。
你就是它的循环。
它写,你读。它说"搞定了",你验。它弄坏了什么,你解释坏在哪,然后你再敲一遍。
这三个动作一直重复,说明系统本该干的三件事没人干:
- 给模型一个能干活的地方;
- 告诉它到底对不对;
- 决定下一步发生什么。
这三件事有名字:Harness、Loop、Graph。
大多数文章把它们并排摆在架子上当三件工具,这恰好是它们看起来费解的原因。它们不是菜单,是梯子。 上面一层之所以存在,是因为下面那一层会以某种特定、可预测的方式坏掉。
下面七个等级,每一级只讲三件事:加了什么、修了什么、以及把你推到下一级的那次具体失败。一个例子贯穿全文:来了一张 bug 报告,Agent 要修好它并开 PR。
一、30 秒地图
| 层 | 回答的问题 | 落在什么上 |
|---|---|---|
| Harness | Agent 能做什么 | 环境 |
| Loop | 什么才是真的 | 证据 |
| Graph | 接下来发生什么 | 授权 |
以及你要爬的这七级:
| 层 | 名字 | 一句话 |
|---|---|---|
| 0 | 聊天 | 所有事都是你 |
| 1 | Harness:手 | 它能动手 |
| 2 | Harness:记忆 | 它能接着干 |
| 3 | 循环:检查 | 它能当着你的面错 |
| 4 | 循环:反馈 | 它能从错里爬出来 |
| 5 | 图:形状 | 工作有了对的形态 |
| 6 | 图:闸门 | 错误留在一个小格子里 |
| 7 | 学习 | 同一个错误不再回来 |
二、Level 0 聊天:系统里唯一没干脏活的部件是模型
你把 bug 报告贴进去。模型给一个修法。你复制到编辑器,跑测试,把报错贴回去,再问一遍。
看谁在干什么:
| 岗位 | 谁 | 具体在做什么 |
|---|---|---|
| Harness | 你 | 你的手替它跑代码 |
| Loop | 你 | 你的眼睛判断有没有成 |
| Graph | 你 | 你的脑子决定下一步 |
模型是这个系统里唯一不干脏活的部分——它是一个非常聪明的函数,而你是围着它的整个程序。
一次性提问,这没问题。任何要做第二次的事,这是灾难。
坏在哪:你。 三个岗位同时压在同一个人身上,你就是瓶颈。
三、Level 1 Harness:给它一双手
第一个修法太明显了:让 Agent 碰得到世界。shell、文件读写、一个测试运行器、git,任务需要时再加浏览器。
我见过最干净的 harness 定义是这个:把模型从你的架构图里删掉,图上还剩下的东西全部是 harness。
现在 Agent 自己读仓库、改文件、跑测试,不用再复制粘贴。
但注意 harness 到底是什么。它不是"更多工具"。每加一个工具,就多一个模型可以选错的空格。十个窄的、有文档的工具,胜过四十个互相重叠的。 给它能完成这件活的最小环境。
坏在哪:它动得了手,但没有记忆也没有围墙。
四十分钟后,上下文里塞满了测试日志。压缩一次,Agent 忘了哪个修法已经试过,于是又试一遍。而它对所有东西都有写权限,包括那个它绝不该碰的配置文件。
四、Level 2 Harness:记忆与围墙
缺的是两样东西:活得过上下文窗口的状态,和不依赖模型表现的界限。
记忆活在模型外面:
PROGRESS.md
goal fix #482: login redirect loop
tried reorder auth middleware -> still red
known only happens when the session cookie is expired
next inspect auth/refresh.py
never touch migrations/
再加上用 git 提交当检查点,以及产物按引用传递——而不是把整段记录再贴一遍。
上下文窗口是内存,harness 是硬盘。模型会忘,文件不会。
围墙是所有"模型错了也照样成立"的东西:最小权限、隔离的 worktree 或沙箱、命令白名单、硬性的 token 与时间预算(这条线上已经有人在生产系统里做:沙箱里根本不存凭证)。
围墙不是指令。"请不要动 migration"是一个愿望。Agent 没有那个权限,才是墙。
现在它能干一小时、崩溃之后接着干,并且弄不坏重要的东西。
坏在哪:它以"修好了!测试应该都过了"结账。
应该。
Harness 让 Agent 有能力。系统里没有任何东西让它正确。一个有本事但没检查的 Agent,只是更快地、更自信地错。
五、Level 3 循环:一个能失败的检查
循环是四个动作:产出、检查、纠正、重复。
所有人都在盯"重复"。唯一重要的是"检查"。没有一个真能失败的检查,"重复"就只是"重复同一个错误"。
证据不是等价的,按伪造难度排:
| 强度 | 类型 | 例子 |
|---|---|---|
| 最强 | 确定性 | 测试 exit 0、schema 通过、构建编译过 |
| 次之 | 可观测 | trace:它到底是真跑了测试,还是只说跑了 |
| 再之 | 独立 | 另一个上下文、另一份提示词里的评审者 |
| 最弱 | 自述 | "我有信心""看起来没问题""没有报错" |
规则是:一个检查只和它接受的最弱那种证据一样强。 如果你的循环接受"模型说完成了",那这个循环就是自述,堆多少步都一样——这条已经被单独量过一次,同一句"搞定了"在终态和重复 20 次面前站不住。
现在,在 Agent 写第一行代码之前,先把这张单子的检查写出来:
GREEN when
a new test reproduces #482 and FAILS on the current code
the same test PASSES after the fix
the full suite is green
the diff touches only auth/
看第一行。一个在修复前就已经通过的测试,什么都证明不了。 检查必须有可能失败,而且你得亲眼看到它失败一次。
这里有个隐藏的好处:如果你写不出这个检查,说明你还没想清这个任务。 写检查就是在写规格。
坏在哪:Agent 失败、重试,然后用同样的方式失败六次。
因为"红"不是反馈,是判决。
六、Level 4 循环:能收敛的反馈
判决说的是"错了"。反馈说的是"错在这里、错成这样、而且这条路你已经走过"。
最简单的形状,是"它预期的"和"世界实际给的"之间的那个差:
FAILED test_expired_session_redirect
EXPECTED 302 -> /login
SAW 302 -> /dashboard (auth/refresh.py:61)
FENCE auth/refresh.py only
DEAD ENDS middleware reorder
EXPECTED 和 SAW 把一盏红灯变成方向。FENCE 把下一次尝试关进一个文件里。DEAD ENDS 是这个循环自己的记忆,这样第三次尝试不会悄悄变回第一次。
然后是出口。没有出口的循环不是坚持,是持续漏钱:
EXIT when
green -> done
the same SAW comes back twice -> stop and escalate
budget spent -> stop and escalate
中间那条最重要。当 Agent 拿到完全相同的结果两次,它已经不在从循环里学了。更多尝试帮不上忙,因为缺的不是努力——是它看不见的某个东西,或者一个本来就被问错的问题。
循环能修工作。循环修不了问题本身。
坏在哪:一件一件地看,工作质量变得极好。
但真实工单上写的是:修登录循环,顺便查另外两个服务是不是用了同一个刷新 helper,然后更新文档。
于是 Agent 一行一件、在一个上下文里全做完:先修,再审计 billing,再审计 admin,最后写文档。admin 的审计读到 billing 的结论,于是把那些结论重复一遍。
每一步都对。整体慢、串行,而且只有一个观点。调循环怎么调都没用,因为问题不在任何一步里面,在它们之间。
七、Level 5 图:工作的形状
一个图是三样东西:
NODE one bounded job: one input in, one output out
EDGE a real dependency: this output feeds that input
STATE what survives between nodes
工作流里大多数箭头不是依赖,是习惯——某个人当初想到这些步骤的先后顺序。
所以每条箭头都过一遍"早开始测试":如果 B 在 A 完成之前就开始,什么会坏?
答案如果是"什么都不会坏",这条箭头就是习惯,为它等的每一秒都是浪费。
修复还没落地就开始 billing 的审计——会坏吗?不会。
修复还没落地就开 PR——会坏吗?会。那条箭头是真的。
这张工单重画之后:
-> FIX auth/refresh.py ------\
ISSUE #482 -> SCOPE -> -> AUDIT billing -------------> MERGE -> GATE -> PR
-> AUDIT admin --------------/
-> UPDATE docs --------------/
几个选择决定这张图是真帮忙,还是只是看起来厉害:
- 在会分开失败的地方切。 两件事如果会因为不同原因坏,就是两个节点;如果总是一起坏,就是一个。
- 给每个 worker 自己的房间。 四个 agent 共享一个上下文不是团队,是一个 agent 戴四顶帽子——第一份写下来的意见会变成所有人的意见。
- 问"同一个答案"的问题。 这一步如果同样输入永远给同样输出,就写成代码:合并、排序、去重、计数。模型留给那些"换个答案也可能对"的步骤。
- 闸门放在工作离开一个节点的地方,不要放在最末端——末端每个错误都已经和别的东西混在一起了。
两层怎么咬合:循环问"这一块对不对",图问"这几块是不是对的那几块"。两个都要。 上图每个 FIX 和 AUDIT 节点内部,都在跑自己的 Level 4 循环。
坏在哪:两件新事,都很难看。
一个审计失败,整批重跑。三个好结果回来时变了——不是更好,只是不同,于是现在全都要重新检查一遍。
以及,所有过闸的东西以同样的速度移动:文档里一个错别字和认证流程的一次改动,得到完全一样的对待。
八、Level 6 图:闸门与回流
冻结已经通过的东西。
一个节点的输出过了闸就变成只读,下游任何人都不许把它重新打开。有东西失败时,只重跑失败的那个节点——带着它的反馈——冻结的结果原样不动。
每一次重跑好工作,都是又一次弄坏它的机会,而你要拿回的什么都没有。
闸门看撤销的价钱。 信心是模型给自己判卷。更好的问题是:如果这是错的,把它收回来要花多少?
| 档 | 撤销是什么 | 例子 | 怎么放行 |
|---|---|---|---|
| 一键撤销 | 回滚一个提交 | 文档、测试、一个函数 | 绿了就发 |
| 要清理 | 修它碰过的地方 | 共享 helper、schema、认证流程 | 绿 + trace + 第二意见 |
| 撤不回来 | 已经发生了 | migration、删除、已经发出的邮件、花钱 | 人来签 |
最后一档身上一个分数都不挂。不是 0.95,不是 0.99。没有数字可以让模型去够,也就没有什么可争的。
前两档里,读证据要按阶梯顺序:先测试,再看 trace,再看第二意见,模型的自信排在最后。
模型给改动贴标签,代码决定这个标签解锁什么。 模型可以说"这碰到认证了";"认证"意味着一次审批还是两次,是运行之前就写在代码里的。已经有产品把这一档做成了默认行为:不可逆的动作仍然停下来等人点头。
只在撤销不存在的地方花你的注意力。你是这张图里最贵、最慢的节点。 把自己放在错误收不回来的位置,别的地方都不用放。在我们的例子里:文档改动自己上线,认证修复等一次 PR 审批,审计只要不打架你就不用读。
坏在哪:它跑通了。
然后下一周,同一类 bug 来了。Agent 做出同样的第一次错误尝试,烧掉同样的两次重试,落在同一个修复上。系统很快,但跨运行没有记忆。你在付钱让它把同一课学两遍。
九、Level 7 系统逐层学习
走到这一步的人,大多加一条回到规划器的反馈边就停了。
但每一次失败都归属于某一层,而一个教训只有落在拥有它的那一层上才留得住:
| 失败 | 教训变成 | 层 |
|---|---|---|
| Agent 看不到生产日志 | 一个只读的日志工具 | HARNESS |
| 把上周试死的路子又试一次 | never 清单里的一条 | HARNESS(记忆) |
| 没有复现测试就说"修好了" | 一条新增的必过检查 | LOOP |
| billing 和 admin 的审计撞在一起 | 一条新的拆分规则 | GRAPH |
教训放错层,就变成建议。"注意不要重复劳动"写在提示词里是一个希望;写在拆图规则里才是结构。
而且教训是约束,不是记录。你不把上周的日志喂进下周的运行,你喂那些日志教会你的那一条规则。
Level 7 的测试很简单:同一类失败,不会让你付两次钱。
十、你在第几层
从上往下找第一个对得上的症状,那就是你的下一层。不是再下一层。
| 症状 | 缺的层 |
|---|---|
| 你在聊天窗口和终端之间复制粘贴 | 1 Harness:手 |
| Agent 反复试它已经试过的路子 | 2 Harness:记忆 |
| "完成了"这句话不作数,你得自己看 | 3 循环:检查 |
| 重试在同一个错误上烧预算 | 4 循环:反馈 |
| 每一步都对,整体却慢 | 5 图:形状 |
| 一处失败就全体返工,事事都要你 | 6 图:闸门 |
| 同样的错误每周都出现一次 | 7 学习 |
十一、怎么往上爬
不能跳级。 十个没有检查的 agent 不是十倍产出,是十倍清理。一个完美的循环如果没有 harness,就没有地方跑它的测试。
但设计要从中间开始。 动手之前,先在纸上写 Level 3 的那个检查。如果你说得出"绿"是什么意思,你就知道 harness 需要哪些工具来证明它,也就知道图该把闸门放在哪里。
如果你说不出"绿"是什么意思,哪一层都救不了你。
你也不需要爬到顶。 大多数任务在 Level 4 就结束了。只有当这一层的失败比你建下一层更贵的时候,才继续往上。
十二、简短版
Harness 让 agent 有能力,循环让它诚实,图让它有条理,学习让它比昨天好。
少一层,那个缺口就由你来补。
目标从来不是一个不需要你的 agent。而是一个只在正确的位置需要你一次的系统。
十三、我们的整理:明天就能改的三件事
原文的框架好用,但它是一张地图,不是一份施工图。把它的判据落回我们自己的工单,其实只剩三样东西——而且都在 bug 发生之前。
第一,三个岗位各留一件物证。
| 岗位 | 该有的东西 | 大多数团队现在有什么 | 判据 |
|---|---|---|---|
| Harness | 一份进度文件(目标/试过/已知/下一步/绝不碰)+ 只读日志入口 | 一段塞满日志的对话 | 崩溃之后能接着干,不用重读历史 |
| Loop | 一条能红、而且你亲眼见过它红的检查 | "跑一下看看" | 修复前红,修复后绿 |
| Graph | 一张冻结清单 + 三档闸门 | 全靠最后那一次总评审 | 单点失败只重跑那一点 |
第二,把"反馈"翻译成四个字段。 这四个字段可以直接抄进任务卡,不依赖任何框架:
EXPECTED:我以为会发生什么(具体到状态码、行号、字段值)。SAW:实际发生了什么(贴原文,不要总结)。FENCE:这一轮只许动哪个文件。DEAD ENDS:这轮之后,哪条路不要再走。
第三,三条比原文更硬的判据。
- 写不出"绿"的定义,就别开工。 这是唯一一条能挡住后面所有层的规则。
- 同一个
SAW回来两次就停手。 第二次相同结果是"模型看不见某个信息"的信号,不是"再努力一点"的信号。 - 人只在不可撤销的地方出现。 其余位置放人,等于把最贵的节点浪费在最便宜的判断上。
四条边界,我们替原文打折的地方。
- 这篇文章没有任何样本、基准或现场数据。七个层级是一个人的经验框架,不是测量结果。它的价值在"症状 → 缺哪层"那张对照表,不在"7"这个数字。
- 作者在文末给自建频道导流。框架本身不受影响,但别把文中的判据当成行业标准——它是设计意见,不是规范。
- "不能跳级"当经验法则用没问题。工程上更准确的说法是:可以少建一层,不能少理解一层。两个人的团队在 Level 1 上直接加闸门,比按顺序补齐三层更现实。
- 原文的层级图和几张对照表都是纯文本画的,我们按语义重画成中文表,没有增删条目;ASCII 工单图原样保留。
相关阅读
- 代码能跑 ≠ 系统能用:好开发者为什么对 Agent 开发更谨慎——"构建一直是红的"那一段,就是 Level 3 缺检查的现场记录。
- Agent 写完的代码没人读过:出事时你该潜多深——Level 6 里"你是最贵的节点"的另一面:你不读代码,代价会以什么形式回来。
- Claude Code 团队怎么做代码评审:7 层防线,把人工时间压到最低——把 Level 3 的证据阶梯真的排成一条流水线。
来源:@m4lkxx《Harness, Loops, Graphs: What Each Layer Fixes and What It Breaks》,2026-10-25,原文(X 长文,需登录)。图由我们按原文语义重画为中文表格,ASCII 图保留原样。
本文由汇智网 · Software 2.0 编译整理,转载请注明出处。
这是「Agent / MCP」专题的一部分。完整地图见:Agent / MCP / 自动化完全指南