Skip to content

pstack 拆解 08 · 验证(上):真实产物与根因 ​

模型最会写"能编译、测试过了"。而这恰恰不是证明。

这一篇讲两条最基本的验证:对着真实产物检查,而不是代理或自述;调试时追到根因,而不是修症状。

prove-it-works ​

证明它能用的背后是一个认识论上的区分:一个判断要对应世界上的事实,不能只对应一个模型。agent 的自述是模型对自己输出的信念,文件修改时间是一个变更的代理,缓存截图是某一刻的代理;这些都可能在真实情况已经错了的时候,照样显得合理。所以它要求直接观察真实产物。这会带来两个很实用的推论:验证失败时,先怀疑观察方法,再怀疑系统;而当某件事过得"太容易"时,也要先怀疑观察方法,因为一次错误的观察和一次真实的成功,在你眼里是一样的。

它有一句判据:对真实产物直接检查,不要从代理、自述或"能编译"推断。

它的做法分两层。

检查真的东西,不是代理。

  • 直接检查进程是否活着,不要通过派生出来的状态。
  • 读真正的值,不要读缓存或二次表示的副本。

能脚本化就脚本化。 最强的证明是一个确定性脚本,它重复同一个比较,不是一次性的肉眼看。写脚本,跑它,把输出留成 reviewer 能重跑的产物,而不是相信你的话。

还有一条关于产物的规矩。默认把产物留给人类,但只有大而复杂、以后需要审计的工作才提交它,比如一次大的移植或迁移。日常的小改动,让它可见就好,不必入库。

fix-root-causes ​

修根因的背后是因果推理本身:症状和原因是两件事,而人天然会停在第一个说得通的地方。修症状会立竿见影,但每一次 workaround 都让系统更难推理,而真正的 bug 还在;时间一长,系统就变成一堆互相遮蔽的补丁。所以它把调试当成科学实验:先复现,形成候选假设,用运行时证据一个个排除,直到只剩那个能解释全部现象的机制。这里有一条特别实用的经验,是关于"重启类问题"的:先怀疑状态,再怀疑代码,因为持久化的脏状态,是最像随机的那类症状。

它有一句判据:调试时不要修症状,把每个问题追到根因,在那里修。

它的做法。

先复现。 没复现就不要谈修复。

一直问为什么,直到根因。 不要停在一个说得通的地方。

不要加 guard。 加一个 nil 检查让崩溃静音,就是修症状。

如果一个 workaround 需要用一段话的注释来解释,那代码是错的。 修代码,不是修注释。

检查模式,而不只是这个实例。 grep 同样的模式,把所有实例一起修掉。

卡住就插桩,别猜。 加日志,读真正的错误。

参考 ​

原文都在 pstack 上游仓库(cursor/plugins):