一次计划执行完,结果不对。这种事在和 Agent 协作时几乎每周都会遇到。我的第一反应曾经是:找到那个不对的结果,改掉它。后来我发现,直接改结果是最省事也最没用的做法——结果只是症状,计划到代码之间的链路才是病因。真正值得养成的习惯,是在结果不对时先问一句:这个结果,是从哪一步开始走偏的?
这一次触发我思考的,是一个写作计划的执行。候选素材、写作输入、计划本身都齐了,Agent 按计划跑完,产出的东西却和我预期的不一致。如果按老习惯,我会说"这一段重写""那个结论改掉"。但那一回我停了一下,把问题换了个问法。
结果不对时,第一反应往往是改结果
人对"出错"的本能反应是修修补补。代码报错了就加个判断,文章不对了就改句子,数据歪了就调公式。修补本身没错,问题在于修补的位置——大多数时候我们在修补输出,而不是输入。
输出是链路的末端。在末端打补丁,能让这次的结果看起来对了,但下一次同样的计划跑下来,大概率还是错,因为生成它的过程一点没变。更麻烦的是,补丁会掩盖问题:当你把错误的输出改成"看起来对"的输出,你就失去了追问"它本来为什么会错"的机会。
这种习惯背后,其实是对待 Agent 的一种错位。把结果交给它改,等于把它当成一台高级打字机——你指挥,它执行,思考全在你这边。可如果目标是让它越用越靠谱,它就得更像一个能共同负责的同事,而不是一个只会照办的遥控器。同事犯了错,你不会替他把活重做一遍,你会和他一起复盘:这一步当时是怎么想的?
和 Agent 协作时这个惯性更明显。Agent 很听话,你让它改它就改,而且改得很快。这种"快速服从"很容易让人产生问题已经解决的错觉。但其实,它只是把你说的话执行了一遍,并没有理解为什么之前的结果不对。下一次你不在旁边盯着,它还是会犯同样的错。
所以我后来给自己定了一条规则:看到不对的结果,先别动手改,先问"它是怎么变成这样的"。
这个过程还有一个容易被忽略的好处:当你追问"是怎么变成这样的",你其实也在训练自己的诊断能力。每一次追溯,都是对你自己的判断链的一次锻炼——你学会了在错误结果中识别出模式:是输入问题还是处理问题?是上游依赖断裂还是下游理解偏差?时间久了,你不需要等故障发生,就能在计划阶段预判可能出问题的环节。
prewrite gate:在执行之前先过一道门
这次写作计划用的是 jianfei-plan。它的设计里有一个我后来才真正重视起来的环节:prewrite gate,执行前门控。
所谓门控,就是在计划真正开始执行之前,先做一次检查。检查什么?候选素材是不是齐全、写作输入是不是清楚、计划本身是不是完整自洽。门控不通,就不往下走;门控通了,才进入实际的写作执行。
这个设计的意义,当时我还没完全吃透。直到那次结果不对,我才反过来想明白:如果门控能在执行前拦住问题,那就根本不会有无谓的错误输出。但门控拦得住的,是"显而易见"的不完整——素材缺失、输入含糊、计划自相矛盾。它拦不住的,是计划内部依赖关系没说清导致的隐性错误。
而依赖关系这件事,恰恰是这个写作计划用 task graph 解决的问题。
task graph 把"谁知道什么"显式化
计划不是一串待办事项的清单。真正的计划是一张图:哪些任务先做,哪些后做,谁的结果喂给谁。在 jianfei-plan 的 task graph 里,每个任务都要写两样东西——read_set 和 write_set。
read_set 是"这个任务需要读取什么",write_set 是"这个任务会写入什么"。一开始我觉得这是冗余:任务的描述里不是已经写了要做什么吗?为什么还要单独声明读什么、写什么?
后来那次结果不对,让我看清了 read_set 和 write_set 的价值。它把"谁知道什么"这件事从隐式变成了显式。
平时我们写计划,依赖关系是藏在脑子和文字里的。任务 A 的输出,任务 B 要用——这句话在计划文档里可能只是一句"参考 A 的结果"。但 A 到底产出了什么、以什么形式产出、B 需要的到底是不是 A 产出的那个东西,没有人显式确认过。执行时靠 Agent 自己"理解",理解对了就对了,理解错了就悄悄错下去。
隐式依赖最危险的地方在于:它平时工作得挺好。十个任务里有九个的依赖,Agent 都能"猜"对,于是你以为计划没问题。直到那一个它猜错的地方,整个下游都被带歪,而你根本想不通为什么——因为断点藏在一句轻描淡写的"参考 A"里,谁也没把它当成一个需要确认的事实。
而 read_set 和 write_set 逼着这种依赖浮到台面上。当 B 声明"我要读 X",而没有任何任务的 write_set 里写"我会写 X",门控就能在执行前发现:有一条依赖是断的。或者,当 B 声明读 X,但写 X 的任务 C 排在 B 之后,门控能发现:依赖顺序反了。
这就是它比"直接执行"更早暴露问题的原因——它不是等结果跑出来才发现不对,而是在任务之间的数据流向层面就检查一致性。
从结果倒推:判断链是怎么形成的
回到那次不对的结果。当我把"怎么改"换成"是从哪一步开始的",Agent 的反应变了。
它不再是被动地等我给指令,而是开始自查:这个结果是从哪来的?它顺着执行链路往回走——先定位最终的产出,再找生成这个产出的任务,再看那个任务的输入是什么,最后追到最初的素材和计划。
这就是一条从结果到输入的判断链。它的方向是逆向的:结果 → 过程 → 输入,而不是我们习惯的正向:输入 → 过程 → 结果。
正向链条适合"做计划"——你有一堆素材,安排任务去消化它们。但当你已经拿到一个错误结果,正向链条帮不上忙,因为你不知道问题藏在正向的哪一段。这时候逆向链条才有效:从已知的错误出发,一步步往回逼,直到找到第一个不对劲的环节。
更重要的是,这条逆向判断链不是只用来救这一次火。它其实是一套 reusable 的心智模型:只要结果是可见的,链路是可描述的,你就能从任何一处偏差出发,反推出它真正的源头。那次之后,我再遇到别的不对劲,第一反应已经不是皱眉看输出,而是先在脑子里把这条链拉出来。
那一次,我们顺着判断链倒推,发现错误并不在写作执行本身,而在更早的一个环节——某个任务声称它会写入一个中间产物,但它的 write_set 和实际产出对不上,导致下游任务读到了一个残缺的东西。如果当时我只说"改结果",这个上游的断裂永远不会被发现,后面的每一篇都会踩同样的坑。
倒推还有一个隐藏的价值:它让你对系统的理解更加具体。以前你可能笼统地知道"某个环节不稳定",但倒推之后你能精确地说出"从任务A的产出到任务B的输入之间有一条未声明的数据依赖"。这种精度,是正向执行永远无法提供的。
问"从哪里来"比"怎么改"更有效
这件事给我最大的启发,不是 task graph 怎么设计,而是一个协作层面的道理:你问问题的方式,决定了 Agent 是"被你代劳"还是"自己长能力"。
"怎么改"是一个封闭问题。它隐含的前提是:我已经知道哪里错了,只是让你去执行修复。Agent 照做,结果是对的,但它没有学会任何东西,下一次照样不会。
"从哪里来"是一个开放问题。它把诊断的责任交还给 Agent,逼它把自己走过的路重新走一遍。在重新走的过程中,它才会真正看清自己的计划哪里有漏洞——可能是 read_set 漏写了,可能是任务顺序排反了,可能是某个依赖根本没说清。
区别就在于:前者你替它思考,后者让它替自己思考。前者的收益是一次性的,后者的收益是可复用的。一次"从哪里来"的追问,可能顺带修好了一批潜在问题,因为它针对的是产生错误的机制,不是错误本身。
当然,这不是说永远不问"怎么改"。当问题确实只是个局部笔误,直接改更快。但当你发现的是"系统性地不对"——同一类错误反复出现、结果偏离了预期的方向——那多半不是输出层的毛病,而是计划到代码这条链路上有断点。这种情况下,"从哪里来"几乎总是比"怎么改"更值当。
下次复用:先追溯判断链
现在遇到类似的情况,我的标准动作已经固定下来了:
第一步,不急着改输出。先把不对的结果放在一边,告诉自己"症状先记下,病因另查"。
第二步,从结果出发往回追。问 Agent:这个结果由哪个任务产生?它的输入来自谁?一路追到最初的素材和计划。每一跳都确认"上游写的,是不是下游要读的"。
第三步,在判断链上定位第一个断点。往往是某个 read_set 或 write_set 不一致,或者任务顺序和依赖方向对不上。
第四步,修断点,而不是修结果。断点修好了,重新执行,结果自然对。而且这一次,同样的坑不会再出现。
这个流程的核心是一个视角的转换:从"结果不对 → 改结果",变成"结果不对 → 追链路 → 修链路 → 结果自动对"。前者是在末端反复打补丁,后者是在源头一次修好。
这套标准动作还有一个额外的好处:它让经验变得可传递。以前你发现"这个计划总有问题",你会说"这里注意一下"——但注意什么、怎么注意,全靠对方自己悟。现在你可以说"追到第三步看到断点了,在 read_set 补上这个依赖就行"——每一步都有明确的位置和操作,对方不需要猜你"注意"的是哪个地方。
总结
从计划到代码,中间隔着的不只是执行,还有一层"可诊断性"。一个好的计划,不只是能跑出结果,更是在结果不对的时候,能让你顺着一条清晰的判断链,找回它走偏的那一步。
prewrite gate、task graph 的 read_set 和 write_set,这些设计的价值,表面上是让计划更严谨,深层里是让错误变得可追溯。当每个任务都声明了自己读什么、写什么,依赖关系就从隐式变成了显式,问题就能在执行前或执行后被快速定位。
而比工具更重要的,是协作中的那个习惯:结果不对时,先别问"怎么改",先问"从哪里来"。这句话把 Agent 从被动执行者变成了主动诊断者,也让每一次出错,都变成一次让流程更结实的机会。
从计划到代码,难的从来不是写计划,也不是跑代码,而是让这两者之间的每一步,都清楚地说得清:我读了什么,我写了什么,我又是怎么走到现在这一步的。