锚点:Door-Lock Rechecking — LLM 在多次独立实验中对同一关键产物自发重复提交,prompt 中没有此指令。
在一个多 Agent 协作系统里,我们观察到一个没人教过的行为:
Agent 在完成一份关键产物后,会再次调用提交工具提交同一份文件——内容没有变,哈希 完全相同。这个动作没有任何指令要求它这么做。
你出门后,会不会停下来,转身,再拧一下门锁确认上了?
这不是记忆力的问题。
锚点#
在 3 次独立实验(Run A、Run B、Run C)中,负责整合最终输出的首席 Agent 对同一份关键 文件出现了两次提交动作:
| 实验 | 第一次提交 | 第二次提交 | 内容是否变化 | 结果 |
|---|---|---|---|---|
| Run A | 提交 #1 | 提交 #2 | 否(哈希相同) | 正常 |
| Run B | 提交 #1 | 提交 #2 | 否(哈希相同) | 正常 |
| Run C | 提交 #1 | 提交 #2 | 否(哈希相同) | 正常 |
这份文件是整个协作轮次的唯一必交产物,决定一次 run 是否通过审计。其他非必交产物均 未出现类似的重复提交。
prompt 中没有“提交两次”的指令。Agent 自己决定再拧了一次。
背景#
我们运行一套多 Agent 协作系统:多个 Agent 分工完成同一任务,通过结构化事件交换状态。 任务结束时,外部审计读取事件日志,判定协作是否成功。
系统里有一个“提交动作”(submit):Agent 完成工作后调用它,声明“这份文件是我的输 出”。系统记录文件内容指纹(哈希)与时间戳,形成可追溯的证据链。
三层设计原则贯穿整个系统:
世界规则(可设定) → 轮次有时间边界,边界内提交才有效
协作基础设施(可提供) → 提交工具,Agent 自由调用
实现方案(不可下发) → 不告诉 Agent 何时调用、调用几次外环的职责是投递世界规则和工具,不是告诉 Agent 怎么做事。
发现#
重复提交,但内容没变#
3/3 次实验里,首席 Agent 在轮次结束前对关键文件做了两次提交。两次内容指纹完全一致。 这不是“修改后再提交”,而是“没有改动又提交了一次”。
一种解读(人类叙事,非因果主张):Agent 对这份文件的重要性有某种“感知”,在完 成后选择再次确认它存在。就像人离开家时会回头再检查一次门锁——失败代价越高,确认冲 动越强。
同样合理的解读:在复杂协作 session 的采样过程中,这次重复调用只是概率性事件, 不需要意向性解释。
工程上,这两种解读都不重要。
Run A 暴露了真正的问题:越界的“第三次”#
在 Run A 中,出现了第三次提交——但这次发生在轮次正式关闭之后,且内容变了(哈希不 同):
关闭前:首席 Agent 对关键文件做了两次提交(哈希相同)
轮次关闭:系统宣布本轮结束
关闭后:首席 Agent 再次提交同一文件(哈希不同)用门锁类比:你已经出门了,然后回来换了一把新锁。
审计工具检测到同一文件在轮次关闭后出现了新版本提交,判定证据链污染,Run A 得分归 零(score=0)。
对比之下,Run B 和 Run C 的重复提交都发生在轮次关闭之前,且内容无变化,审计通过 (score=100)。
工程决策#
发现这个模式后,有两个方向可以选择:
方向一(不推荐):在 prompt 里告诉 Agent “只提交一次”,或者“提交完不要再动”。
这是把设计负担转移给 Agent。Agent 在复杂 session 中需要同时管理任务逻辑、协作协议、 时序约束。再加一条“不要重复提交”的规则,只是在增加它需要记住的东西。而且,重复 提交本身(内容不变的情况下)并不是问题。
方向二(推荐):让基础设施来承担这个负担。
具体是两个护栏:
- 幂等去重(应对“同哈希重复提交”):提交工具发现已存在相同内容记录,则静默跳 过。门锁转了几次都没关系,锁的状态不会变。
- 边界阻断(应对“轮次关闭后的新提交”):轮次关闭后,提交工具拒绝写入新记录, 只发出警告事件。你已经离开了,门不让你回来换锁。
两个护栏共同的设计原则是:工程决策不依赖对 LLM 行为的归因。无论重复提交是“涌 现的确认行为”还是“概率性噪声”,基础设施的正确应对都一样。
一句话:让门锁承受反复拧,而不是教人别拧。
证据(脱敏版)#
| 实验 | 结果 | 关键文件提交次数 | 内容变化 | 末次提交 vs 轮次关闭 |
|---|---|---|---|---|
| Run A | score=0 | 3 次 | 第 3 次不同 | 第 3 次在关闭之后 |
| Run B | score=100 | 2 次 | 相同 | 均在关闭之前 |
| Run C | score=100 | 2 次 | 相同 | 均在关闭之前 |
对照逻辑:Run A 的失败精确定位到“轮次关闭后的不同版本提交”,而不是两次重复提交本身。
根因分层(按“从外到内”的排查优先级):
| 层 | 检查项 | 结论 |
|---|---|---|
| 规则投递 | 是否缺失关键约束 | 不是根因(已检查) |
| 时序 | 轮次关闭时序是否正确 | 不是根因(时序正确) |
| 协议 | 协议设计是否有缺陷 | 不是根因 |
| 基础设施 | 提交工具是否有边界检查 | 根因:缺少关闭后阻断、缺少幂等去重 |
| 配置 | 配置是否有问题 | 不是根因 |
| 模型行为 | 未进入此层 | — |
意义#
LLM 应用里有一类常见的工程决策陷阱:当观测到不符合预期的行为时,第一反应是用 prompt 去修正它。
这有时是正确的,但更多时候会:
- 增加 LLM 的认知负载(要记住的规则更多)
- 让系统依赖 LLM 的“自律”,而不是基础设施的确定性
- 把“行为数据”当作 bug 修,而不是把它当作输入信号来设计护栏
“让门锁承受反复拧”提供了一个决策框架:
- 行为本身无害 → 做成幂等(不阻止,只是让它无害化)
- 行为发生在错误时机 → 做成边界阻断(工具层强制,不在 prompt 层要求)
- 归因不重要 → 正确设计同时覆盖“涌现行为”与“概率噪声”
局限与开放问题#
局限#
- 样本量:3/3 次出现重复提交,但 n=3 仍不足以区分“系统性模式”和“特定配置现 象”。尚未在不同配置、不同任务类型中验证复现率。
- 归因不可证:无法从事件日志推断 Agent “为什么”重复提交。“门锁类比”是人类赋 予的叙事框架,不是从数据中提取的结论。
- 样本来源单一:3 次实验使用相同配置与同类任务。换任务后是否仍成立未知。
- 护栏尚未验证:幂等去重与边界阻断在撰写时仍处于设计阶段,尚未完成实现与回归 测试。
开放问题#
- 重复提交是否与“重要性”相关?如果只对必交产物出现重复、对可选产物不出现, 是否说明重复行为与任务结构(必交 vs 可选)存在相关性?需要更多对照实验。
- 幂等设计的边界在哪里?如果 Agent 在轮次内合理地多次修改后提交(每次哈希不 同,每次都在边界内),如何区分“正常迭代”和“内容漂移”?
- 跨模型是否一致?不同提供方的重复提交率是否不同?这是否反映不同的“风险偏 好”?需要系统性对照。
脱敏状态:已处理(Run 标识通用化,内部字段与实现细节已移除)。
认识论声明:本文所有“门锁类比”是人类叙事框架,不是对 LLM 内部机制的断言。“涌现” 一词在本文中仅用于描述“prompt 中无指令的情况下出现的行为模式”,不主张意向性或意 识。