我给三个常驻 Agent 写判读规则,前后折腾了三个月。最开始我以为只要把规则写细,执行就会稳定;后来发现,规则本身也会互相冲突,判据也会把不确定性伪装成结论。下面四件事都不是模型“突然变笨”,而是我把系统设计错了。

1. 红线写着不许改,派单却要求去改

当时怎么错的: 一条长期规则明确写着“不手改 AGENTS.md”,另一条派单却要求“把新的判读规则写进 AGENTS.md”。两边都像最高优先级,Agent 执行哪个都可能违反另一个。最糟的不是它犹豫,而是我一开始还把犹豫当成执行力问题,继续催它照做。

这其实是权限边界和内容提议混在一起了。一个规则禁止直接修改配置,另一个任务把“提出修改”误写成“直接落地”。重复强调其中一条只会让冲突更响,不会让它消失。

后来怎么定的: 改成提案制。Agent 可以在独立提案里写出建议变更、依据和影响,但不能直接改那份受保护文件;由有权限的人审阅后再决定是否合并。于是“发现规则缺口”仍能推进,“写入受保护规则”仍有明确边界。规则把禁止什么和允许做什么都说清楚,比再加一句“务必遵守”有用。

2. 把稳定量和浮动量塞进同一个判据

当时怎么错的: 我把一个判读条件写成“稳定量 + 浮动量”的组合:一部分指标本来应该长期固定,另一部分会随样本、时间窗口或新证据变化。复核时,两边拿到同一份规则,却会因为浮动部分处在不同状态而每次都报分歧。报告里看起来像模型不一致,实际是判据把两个性质不同的问题绑成一个布尔结论。

当时我还试过给总分加权,希望把分歧压小。结果只是把“哪一项在变”藏进一个更难读的数字里。稳定项应该回答口径是否一致;浮动项应该回答本轮证据是什么。二者不能互相补偿。

后来怎么定的: 拆开记录。稳定量作为版本化的硬口径,变化必须有来源和生效时间;浮动量作为每次运行的观测值,附采集窗口与证据锚点。最后可以并列展示,但不揉成一个不透明分数。只要浮动量变化,报告就说明变化来自新证据还是采样差异,不再把它冒充规则分歧。

3. 三个内容根目录,只扫一个就宣布“没有产物”

当时怎么错的: 内容线的稿件分散在三个根目录。我曾经只检查其中一个目录,没有找到目标文件,就据此判断任务没有产出。后来把其余位置也纳入核对,才发现所谓“幽灵文件”只是扫描范围漏了:文件确实存在,只是检查程序根本没去那里看。

这种误判很容易被写成“文件被删了”或“Agent 没交付”,因为检查结果确实是空。但空结果只证明被扫过的范围为空,不能证明整个系统没有结果。路径清单不完整时,负面结论尤其危险。

后来怎么定的: 把内容根目录做成明确清单,检查报告列出实际扫描的每个根、文件数量和命中项;新增位置先更新清单,再运行“缺失”判定。遇到空结果时,先验证扫描覆盖率,不能把一次局部搜索包装成全局事实。这样即使目录结构改变,报告也能让人看出它究竟查过哪里。

4. stderr 里的字节数看起来精确,实际是错的

当时怎么错的: 一次工具返回的 stderr 声称输出有 59,779 字节。我一开始把这个数字当作测量值,继续用它解释文件变化;随后用独立方式实际读取并计数,结果是 49,779。差了整整 10,000 字节。错误数字带着逗号、精确到个位,外观很像可信的运行数据,却没有对应的可复现测量。

这不是“差一点”,也不能拿来推断文件里多了什么。stderr 是待核验的工具输出,不是计数器本身。尤其在多层包装、重试或拼接日志时,格式完整并不代表来源可靠。

后来怎么定的: 对影响结论的数值做独立复算:明确输入文件、编码与计数口径,再用第二条路径重新读文件。若两边不同,先把冲突作为异常保留,不挑一个顺眼的数字继续算。此例最终口径是实测 49,779 字节;59,779 只作为错误输出记录,不再引用为事实。报告也注明计数对象,避免把字符数、文件字节数和传输字节数混为一谈。

最后留下的不是更多规则,而是边界

这四次复盘把我从“再写一条规则就好了”拉回了更具体的问题:规则有没有授权冲突,判据有没有把固定口径和新证据混为一谈,扫描有没有覆盖声明的范围,数字有没有独立测量。它们分别需要提案制、分项记录、显式根目录清单和可复算的证据。

规则越多,维护成本越高。与其把每个意外都追加成一句命令,不如让每条规则说清楚谁能做什么、依赖哪份证据、结果覆盖到哪里,以及冲突时保留什么事实。三个 Agent 没有因此变得神奇;只是后来每次出错时,我更容易分清是执行偏差,还是我又把规则写成了死结。