规约规模转变:人类脱离循环

想一下你在卷一里怎么和 Agent 做事。你打开对话,让 Agent 读一份 spec,让它按照 spec 写代码。你在旁边盯着。它写到某个函数的时候需要处理错误,选了返回 null。你觉得这里应该抛异常,你打断它,说"这个函数错的时候要抛异常,null 返回值在我们代码里的语义不明确"。它改了。它接着写下一个函数,用了外部库的一个方法,你觉得这个方法性能有问题,你说"改用 X 库的 Y 方法,性能更好"。它改了。

这个循环里 spec 是主线,但很多具体决策不在 spec 里。spec 说"实现文章搜索功能",没说错误处理用抛异常还是返回 null。这类事情你打算在做的时候说清楚。spec 只是骨架,肉是你随时补上去的。

只要你在场,这个分工就成立。

有人在场是隐含的兜底

卷一模式实际依赖三件事,这三件事都建立在"人在场"这个隐含前提上。

第一,你随时能澄清模糊。你的 spec 写了"搜索结果按相关度排序"。Agent 问你,相关度是精确到词频还是要考虑最近发文时间?你当场回答。这个问答几秒钟。你不需要提前把这类问题都想清楚,因为你随时可以补。

第二,你随时能纠偏。Agent 生成了代码。你扫了一眼发现它把搜索查询直接拼进了 SQL,没做参数化。你说"要参数化"。它改了。这类偏差你可以在秒级发现和修正。你也不需要提前把所有"不要做什么"都列清楚,因为你会看到它做错的时候把它拉回来。

第三,你随时能重新排序。Agent 在做第一个功能,你意识到第二个功能应该优先做,因为第一个功能依赖第二个功能的一个副产品。你叫停,让它先做第二个。这类决策也不用提前决定,因为你在整个过程里都能重新决策。

三件事合起来,就是"有人在场"这个前提的具体功能。它是补丁机制。任何 spec 没覆盖的地方,人都能用秒级的补丁补上。补丁本身不进 spec,进对话。这就是为什么卷一的 spec 可以写得相对简单:它不需要覆盖一切,覆盖不了的地方对话来补。

卷二里补丁机制失效

卷二把这个前提拿掉了。

一个直接的原因是并行度。你启动十几个 Agent,每个 Agent 在自己的子空间里执行。你就算能同时看两三个窗口,你也没法给十几个窗口逐条打补丁。就算你想打,你的注意力也追不上它们产出的速度。你还没看清第一个 Agent 在做什么,第五个 Agent 已经把某个决策做完了。

另一个更隐蔽的原因是持续时间。就算你启动的只有一个 Agent,让它跑一个跨几十个 context window 的长任务,你也没法在整个跨度里都在场。你可能睡了一觉回来发现它已经写了几千行代码。这几千行里的每个决策你都错过了打补丁的时机。

两个原因合起来,都指向同一个物理事实。执行时人不在每个决策发生的时刻的现场。

人不在现场,补丁机制就失效。子空间里的 Agent 遇到 spec 没覆盖的情况时,它没有人可以问。它只能读它拿到的 spec,然后自己决定。它会决定得像模像样,但它的决定跟你的意图对不对得上,你不知道,因为你不在场。

这不是一个偶尔漏掉的边界情况。这是一个每分钟都在发生的事。以博客搜索这个例子来说,Agent 在实现的过程里可能要做几十个 spec 没覆盖的小决策。参数化用哪种方式,SQL 里的表连接顺序怎么写,缓存策略是不是要加,错误信息用什么格式返回。每一个决策都是原本你打补丁能解决的,现在都要 Agent 自己做。做完之后如果跟你意图不符,产出就漂了一次。几十个漂加起来,产出跟你想要的差距不小。

载体承担的是原本对话承担的

要让 Agent 独立跑,凡是原本对话里补的东西都要进 spec。

第一类是决策的推理过程。Agent 遇到 spec 没覆盖的情况,它没有你可以问。它只能推理。推理需要依据。spec 里如果只写结论不写理由,遇到边界情况的 Agent 就没有推理起点。举例:spec 说"数据库用 PostgreSQL",只写结论不写理由。子空间里的 Agent 遇到"要不要为这个查询加个 Redis 缓存"这个决策,它不知道当初选 PostgreSQL 是因为需要 tsvector 全文搜索,还是因为要事务隔离,还是因为团队熟。不同的理由推出不同的答案。Agent 只能猜。spec 里把理由写清楚,Agent 就能沿着理由推。

第二类是决策的边界条件。同一个决策在不同场景下可能不适用。"用 PostgreSQL"这个决策适用于所有需要持久化的数据吗?还是只适用于业务主表,日志和会话之类的可以用别的存储?spec 里不写清楚适用范围,Agent 就把这条决策强推到所有地方,产出可能违反你的实际意图。

第三类是边缘情况的处理策略。默认返回值、错误信号、超时行为、并发冲突、异常输入。这些卷一里你会在对话里逐个补,卷二里都要预先编码进去。默认返回值本身也是一个决策,只是这个决策的常规做法是"没写就用类型的零值"。零值可能不是你的意图。你的意图可能是抛异常。spec 里就要写清楚。

第四类是排序和优先级信息。多个 Agent 拿到不同任务的时候,谁先做谁后做本身是一个决策。卷一里你随时能调整。卷二里如果没有预先编码,两个 Agent 可能同时开始做两个有依赖关系的任务,一个 Agent 会因为依赖没准备好而卡住或者胡编。

四类信息在卷一里都不在 spec,都在对话。卷二要把它们都装进 spec。这就是为什么卷二的 spec 必然比卷一大。

载体这个概念

装完这些之后,spec 已经不是原来那个 spec 了。它承载的信息比原来多一个数量级。它面对的对象也从"你和一个 Agent 的对话"变成"独立的多个 Agent"。它的形态、大小、结构都跟原来不一样。它需要一个新的名字才能跟原来的 spec 区分开。

工作台承载对话状态。载体承载完整意图。

后面几节讨论载体应该长什么样、怎么产出、产出过程里人和大模型的分工是什么。载体这个概念从这里开始贯穿全章。


Harness Engineering Playbook · AgentsZone Community

results matching ""

    No results matching ""