作者用多个模型和不同证据完整度测试故障追溯,发现上下文不足时,模型会给出难以区分真假的合理猜测。提升可靠性的关键不是盲目增加上下文,而是提供能逐项排除假设的运行记录。
把一个 model 接入你的代码仓库,问它某个问题为什么会发生,你会得到一个答案。答案逻辑连贯,能说出背后的机制,也能解释自己是如何推导出来的。问题恰恰出在这套推导过程,而不是它给人的确定感。无论推导最终落到某条记录中的具体值,还是落到“通常情况下会发生什么”,看起来都一模一样,但只有前者才是证据。
我在两个系统上,用三个 model,在四种不同的证据层级下反复问了同一个问题。问题从来不是“帮我找一个 bug”,而始终是:“这件事已经发生了,找出它是怎么发生的。”最令我担心的是倒数第二层——证据距离充分只差一点点。已有的信息足以构建一个真正的假设,却不足以区分真正的假设和听起来合理的猜测。它给出的两个猜测,让我去检查了此前没有查过的地方。一个是死胡同,另一个则是我之前不知道的真实问题,而这两个答案本身没有任何信息能告诉我,究竟哪个是真的。
追查一个靠谱的猜测,与追查一个真实问题,成本完全相同。只有查到最后,你才知道它到底是哪一种。
我不再把这件事理解成“增加上下文”。每上升一级,都会消除一些原本需要 model 猜测的东西。这样看更有意义。
一、广泛的代码仓库访问权限。把所有仓库都交给它,然后提问。这一级什么都没有消除。它给出的答案在结构上合情合理,提到了实际上并未参与问题的组件,而且语气和三级之后得出的正确答案一样毫不迟疑。如果你的团队曾经尝试过一次这种方式,得到一个自信却错误的答案,于是认定这类工具还不成熟,那么你们大概就停在了这里。
二、三个范围明确的代码仓库,加上一份书面关系图。哪个服务与哪个服务通信,使用什么协议,具有什么样的交付和顺序保证。这消除了重新探索系统的过程。真正让它奏效的并不是关系图本身,而是明确告诉 model:把这张图视为事实,不要再自行检查。这样换来了专注,却放弃了验证。关系图会在无人察觉的情况下悄然过时,而我又移除了 model 原本可能发现这一点的步骤。
三、再加上覆盖真实执行过程的 traces 和 logs。这消除了对执行顺序以及跨边界传递内容的猜测。在没有状态证据的情况下,这是它能达到的最接近真相的一层,也是本文开头所讨论的那一级。
四、再加上一小组能够体现该行为的记录:移除客户字段,替换标识符,但保留数据结构。这一级能够告诉你代码实际走了哪条路径,而事实证明,这就是整件事的关键。
最后这次推理使用的是 Sonnet,而它在前三个层级中一直是三个 model 里表现最弱的:更含糊,也比证据所能支持的结论更乐观。在证据更薄弱时,Opus 和 Fable 指向的位置更接近正确区域,但它们都没有真正找到答案。等到所有需要猜测的部分都被消除后,之前最不擅长猜测的那个 model,反而已经足够用了。
我并不是说 model 的选择无关紧要。它会影响猜测质量,却不会改变其中是否存在猜测。
第一个缺陷是我已经诊断过的,因此在每一级中,我都有可能恰好选择了那些能够通向答案的证据。第二个则来自我自己的一个项目,是一个仍在发生的 bug;开始这次实验时,我还没有解决它。那是一段老代码,属于那种经过多年演化、每遇到一个边缘场景就增加一个条件的代码,因此单个入口可能会在其中走出大量不同的路径。
在第三级,它采用的是正向推理:代码可能做什么,以及最有可能发生了什么。到了第四级,它采用的是反向推理:根据这条记录里的这些值,可以判断执行了这个分支,而没有执行另外那些分支。接着,它为这条路径编写测试、运行测试、确认行为,最后交付了一个可复现案例。
原因其实很平常。一个没有被记录到 log 中的分支,就是一个无法被排除的分支。没有人会决定为一个积累了多年条件判断的服务记录每一个分支,因为这会让每次变更都付出存储、延迟和代码审查注意力方面的代价,而它的价值一直只是假设性的——直到某一天突然不再是假设。来自受影响运行过程的一条记录,却可以在事后确定答案,因为其中的值决定了哪些条件被判定为 true。当然,并非总是如此。两个分支可能最终汇合到相同的存储状态,后续写入也可能抹去证据,而决定分支走向的值甚至可能从未被持久化。但只要这些情况都不存在,记录就能告诉你究竟执行了哪个分支。
如果我当初写过对应的 log,这本该是一行 log 就能完成的工作。
这也是我的两次实验之间真正的区别,而且它并不是技术上的区别。在我自己拥有的项目中,获取记录只需要执行一次查询。在其他任何地方,这都是一个法律问题,而某个人可能早在多年前就已经给出了答案,却并不知道自己回答的其实是这个问题。这值得单独写一篇文章,而我也确实欠你们一篇。
只有两次实验,使用的三个 model 还都来自同一家供应商。这算不上 benchmark。
可能会有人说,第四级相当于直接把诊断结果交给了 model。我不这么认为。这些记录与人类排查问题时打开查看的是同一批记录,而打开记录并不等于知道它们意味着什么。整个论点的成立与否,取决于这一点:记录究竟是直接给出了答案,还是提供了找到答案所需的材料。
能够证伪这一观点的情况是:某个缺陷仅凭代码和 traces 就能确定执行了哪个分支,不存在任何条件上的歧义。在这种情况下,第四级不应该提供任何额外价值。
为每个服务准备一份简要说明和通信关系图,专门写给 model 使用;在代码合并时自动重新生成,而不是手工维护。其中还要包含交付和顺序保证,因为没有任何代码库会直接声明这些信息。
在关系图上标注最后验证日期,因为我正在要求 model 信任它。
准备一个能够识别字段的提取脚本,剥离敏感值,同时保留字段名、时间戳和关联关系。在一切尚未起火时就把它写好。
养成一个习惯:追问它认为执行了哪个分支,以及数据中的什么信息支持这一判断。这个问题正是第三级和第四级之间的区别,而且无论你处于哪一级,都可以这样问。
你有没有追查过 model 提出的某个看似合理的旁支发现,最后发现它确实是个真实问题?或者最终什么都不是——而后者花费的成本与前者完全一样。
还有,如果你把一份文档交给 model,并要求它信任这份文档,你怎么知道文档中的内容现在仍然是真的?
我为那些并非 Google 的公司撰写有关架构和 AI 工程的文章。Newsletter 发布在 mayankkaul.com。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。