1650 字
8 分钟
给子代理的 prompt 是契约,不是说明

我把自己派给子代理的任务指令导出来数了一遍,去重后 424 条。占篇幅最多的不是任务描述,是禁令:77 条以「你对这段代码的开发过程一无所知」开场,37 条写明「你看不到、也不要去读实现代码」,4 条修测试的写「只许改这些测试文件,禁止改其他任何文件」。我的判断是,把「要做什么」写得再细也约束不住它,得把「不许怎么做」写死。

每条禁令配一份补偿

它会把任务改写成自己做得到的那一个#

62 条指令逐字以同一句开场:

你是一名独立代码评审员,对这段代码的开发过程一无所知——这是有意安排的,
请只基于代码本身和仓库现状做判断,不要假设作者意图。

这句话声明的是:背景被我主动拿掉了。评审 agent 一旦知道作者想做什么,就会把实现读成意图的实现——我写「这里要做租户隔离」,它读完代码回我「隔离已经实现」。缺陷恰好藏在这两句话中间。

还有两处防的是同一件事:6 条写「不轻信注释」,2 条写「上一轮评审的意见不要照单全收,每条自己回代码验证」。代码里自己的声明不算证据,别人的结论也不算。

黑盒那类把线划得更靠前,直接禁止读实现,37 条里有 32 条把理由写进了 prompt——看了实现就只会验证「代码做了什么」,漏掉「代码本该做但没做」。有一次它比白盒先看见了问题:一个只拿到契约的 agent 问「归还沙箱时会不会解绑别人的」,顺着查下去,下游确实有一道会话核对,但它只在请求带会话标识时生效,而上游从来不传。这道防线从写下来那天起就没生效过。白盒 agent 看到的是「这里有校验」,它不会去问「它被触发过吗」。

每条禁令都得配一份补偿#

112 条带信息隔离的指令,禁令词出现次数的中位数是 2,其余 312 条是 0。这 112 条反而更长,隔离腾出来的位置被补偿填满了:

  • 切断开发过程 → 68 条给出待评审的 commit 区间或 diff 文件,61 条点名先读哪几份文档,35 条写「违反仓库明文约定按 P1 起步」
  • 禁读实现 → 契约得手写。黑盒类指令里契约部分占全文篇幅的中位数是 92%,任务描述只剩开头两三句
  • 限定可改文件 → 4 条修测试的指令全部带「修法原则(强制):修测试对齐现行实现,不是改业务代码过测试」,也全部留了出口:判断某个失败暴露的是业务真 bug,不要改业务代码,在报告里单独列出证据

这些计数都是下限。导出时每条 prompt 截断在 1200 字,424 条里有 308 条触到了这个上限,中段写了什么没被统计进去。

隔离和「偷懒少给上下文」的分界就在补偿上。少给更省事,但 agent 不会因为信息少就停下来问,它会自己构造一个意图,再照着那个意图干活,交回来的东西读起来同样完整。隔离要管用,拿掉的那部分必须用客观事实补回来——不是我想实现什么,是仓库里现在是什么。

补偿写错了,禁令会把错误原样放大#

手写契约是禁读实现的唯一补偿,它写错一处,整条链跟着错。

给一次 HTTP 框架迁移写契约文档时,我按路由注册表写了初稿,里面有两句结论:SSE 一共 7 种事件;两个长得很像的 server 有 15 条同路径路由可以共享 handler。后来派三个 agent 逐 handler 读实现提取,SSE 实际 14 种,漏掉的有工具调用待定、工具调用取消、上下文压缩、心跳这些;「同路径即可合并」在两处被证伪。

这次没出事,只是因为提取排在了派人前面。真拿初稿那份契约去派黑盒设计员,它会按 7 种事件推出一张自洽、完整、而且错的用例清单,中间没有任何一处会提示我契约有问题,因为我禁止了它去看实现。禁令把我的错误原样放大,顺手删掉了纠错的那条通道。

契约还得逐 handler 读实现提取,本身就要花掉一轮并行 agent——禁读实现省掉的是 agent 被实现带着走的那部分,我的工时一分没省。轮数也是代价:一次多租户隔离的修复,第一阶段走了 3 轮才收敛,每轮都是新开的干净会话,第 2 轮查出第 1 轮的修复自己有问题,第 3 轮查出第 2 轮只修了攻击者可控的那一侧。隔离保证每轮判断互相独立,账单记在轮数上。

出口和凑数要一起封#

禁令封的是方向,封不住交付物的水分。

一头是出口:22 条写明「没有发现就返回空」「某个维度确实没问题就明确写未发现问题」。不给出口,agent 会为了交差造一条。

另一头是凑数:12 条写「不要为了凑数量报不痛不痒的小事」,6 条给了字数上限。16 条要求区分「本次引入」和「存量」——老仓库跑一遍 lint 几百条告警,全报等于没报。

卡在中间的是输出字段。评审类指令的格式固定成这一行:

severity / file / line / problem / failure_scenario / evidence / fix

真正起作用的是 failure_scenario 和 evidence 两栏:failure_scenario 要写清输入什么、得到什么,evidence 要贴代码原文。一条凭感觉写出来的发现,填到这两栏自己就塌了,不用我再去判断它成不成立。

这套写法不是每条指令都要用。424 条里有 227 条一条禁令都没有,那些是取数、转格式、按清单提取事实的活,交付物对不对我一眼看得出来。值得写禁令的是另一类:交付物是一个判断,而我没法一眼验收这个判断。