给评审 Agent 划权限:审查者不应该大于被审查者
一个人带一个 Agent 干活的时候,权限这件事基本不用想。你在旁边看着,它做完一步你看一眼,不对就让它退回去。权限边界其实是你的注意力划出来的。
真正开始需要单独设计权限,是在我给流水线加了第二个角色之后。我这条批量出内容的线上,每一篇稿子由一个实现者 Agent 写,写完之后由另一个独立的评审 Agent 检查——两个 Agent 互不通气,评审员拿不到实现者的推理过程,只拿到落盘的文件和那份规格。人退到了流程的两端:开工前定规格和事实源,收工后抽查验收。中间这一段,人不在。
这个结构一搭起来,一个问题立刻浮上来:评审员到底能干什么。它显然得能改文件——不然它发现问题只能写在报告里,等着人来处理,那批量就没意义了。可它一旦能改文件,它离「能提交」「能构建」「能顺手动一动隔壁那篇」也就一步之遥。而这一步跨过去之后,整条线的性质就变了。
判断权限边界的三个问法
我给自己定的不是一条抽象标准,是三个当场能问出答案的问题。给流水线上任何一个角色配能力的时候,我按顺序问一遍。
第一问:这个角色做错了这个动作,谁会发现?
如果答案是「下一个环节会发现」,这个能力可以给。如果答案是「没人会发现,除非事后翻记录」,那就不给,或者换个形式给。评审员改一段正文,实现者的原稿还在版本控制里躺着,人抽查的时候能对出来——这是可发现的。评审员把改完的东西提交了,历史被它自己写进去了,人再看到的就只有结果——这是不可发现的。
第二问:这个动作之后,人还有没有机会看到改动前的样子?
这一问是上一问的具体化。审查者的价值来自「它和被审查者是两个独立判断」,而两个独立判断必须都能被人看到,人才有得选。审查者一旦能把自己的判断固化成既成事实,两个判断就塌缩成一个了,而且塌缩成的还是后手那个。人名义上还在环路上,实际上只能看到一份已经被审查者改造过的结果。
第三问:这个能力是它完成本职工作必需的,还是「顺手有了会方便些」?
我这条线上评审员的本职是:确认这一篇写出来了,并且符合规格。改文件是必需的。构建整个仓库不是必需的——构建期的问题有专门的脚本去查。碰别的文件更不是,它的任务边界就是这一篇。凡是落在「顺手方便」这一栏的,我一律不给。
三个问题里有任何一个答不上来,我就默认不给。少给一个能力最坏的结果是评审员做不动、返回一个 FAIL,我会看到;多给一个能力最坏的结果是它悄悄替我做了决定,我看不到。这两种失败的代价完全不对等。
我实际写在评审员任务书里的那几条
判据落到动作上,就是评审员那份任务书末尾的一段。我把权限收窄写成了三个并列的否定句,逐字是:
不许 commit,不许跑 build,不许动其它文件。
同一份任务书里,评审员被允许的动作只有一个:
发现问题就用 Edit 直接改掉,不要重写全文。
这两句放在一起看才完整。前一句划的是外沿——它的手伸不出这一篇文件之外。后一句划的是内部形态——它在这一篇里也不是想怎么改就怎么改。
「不要重写全文」这一条,表面上像是在嫌重写慢,但它真正挡住的是另一件事:一个能重写全文的审查者,事实上已经不是审查者了,它是第二个作者。它交回来的东西没法和原稿逐处对照,人抽查的时候只能整体重读一遍——那评审这一层就白加了,因为它没有把「哪里有问题」这个信息留下来,只留下了一份不知道改了什么的新稿。改而不是重写,本质上是逼审查者把它的判断以「差异」的形式表达出来,而差异是人能快速验的。
任务书里还有两条同源的约束,也是把审查者的权限往回收:
一条是数字必须自己用 Python 按 Unicode 区间数,别用命令行的文本工具凑合——那类工具按字节算,中日韩字符会虚高约三倍半,字数门直接形同虚设。这里收的不是「能不能做」,是「用哪种方式做」,因为审查者用错方式得出的结论,比不检查更有害:它会盖一个「通过」的章。
另一条是绝对不许联网。这不是防它作恶,是因为我这条线上出现过子代理调联网工具之后不报错、不返回、一直挂着的情况,而挂死的代理还会把已经写好的成品覆盖掉。核实这件事我留在自己手里,评审员只面对落盘的文件和事实卡。
还有一条顺序上的约束值得单独说:评审员被要求先查文件存在或为空,是则直接判 FAIL,然后才进入质量检查。我把「有没有做」和「做得好不好」拆成了先后两道。原因是这两类失败在流水线上的表现是一模一样的——都是「返回了一个看起来正常的结果」。不先把前一类挑出来,后一类的检查就会在一个不存在的文件上跑,然后给出一个不存在的评价。
这条不适用的地方
只有一个角色的时候不适用。 如果你的流程里没有独立的审查环节,人自己就是那个审查者,那本文整套判据都是空转的。人当然可以既改又提交——人本来就是最终的责任方。这条约束的适用前提是「审查动作被交给了另一个 Agent」。
审查者需要观察运行时行为的时候,得另想办法。 我这里能把构建能力从评审员手上拿掉,是因为我这条线检查的是文本稿件,构建期的问题另有脚本层兜着。如果审查的对象本身就是「跑起来对不对」,审查者不能执行就根本没法判断,这时候要收的不是执行权限,而是执行的环境——让它在一个隔离的地方跑,跑完的产物不进主干。约束的形式变了,第二问那个「人还能不能看到改动前的样子」没变。
权限收窄不能代替权限之外的检查。 这一点我踩过。脚本能查字数、能查死链、能查格式和孤儿页,唯独查不出事实层面的错误;反过来,把审查者的手脚捆好了,也不代表它的判断就是对的——我这条线上就发生过评审阶段反查出事实卡本身有一处错、连累已写的几篇同时出错的情况,最后是我自己实测修正、再全批回查。所以我给评审员留了一条向上的通道:它有权质疑事实卡本身,但只能写进返回里交给我,不许自行「修正」后写进文章。这仍然是同一条原则——它可以提出,不可以坐实。
说到底,我把审查者的权限压到比被审查者还窄,不是因为不信任它,而是因为我承认这条线上任何一个 Agent 的成功率都明显低于 1。承认了这一点,编排、回查、独立评审这些东西才有意义;不承认,就会把「偶尔失败」当成「基本不会失败」来设计,而一个权限比被审查者还大的审查者,正好会在你最看不见的地方失败。
这篇的判据来自我自己带 Agent 干活的实践,样本有限。它更像一份可以拿去验证的假设,而不是一份可以照抄的规范。
延伸阅读
- 上一篇(接手脚):排查 Agent 接不上消息:身份授权和消息通道是两件事
- 下一篇(接手脚):自用 Agent 走向可移交:硬编码路径是第一批要拆的
- 专题导读与七个阶段的地图:把 Agent 当成一个要上岗的员工来带:这个专题讲什么