报错一出,我以前的习惯是把栈贴进会话,写一句「修一下」。小问题能过。一卡住,Agent 就在出错那一行加判断、加兜底、换调用。日志干净了,根因还在。过两天换个输入,又炸。
我现在指挥 Agent debug,先做两件事。一件是第一性原理:别从报错栈开工,先问系统为什么会进入这个状态。另一件是对抗性审查:诊断或补丁写出来之后,专门让它攻击刚才那份判断。
栈很清楚、改动就一行的,我还是直接丢过去。会留下来的、现象和栈对不上的,才走下面这套。
别从报错开始
第一性原理说白了就是:眼前的报错不当默认答案。把现象拆到不能再拆的事实。
Agent 很会修「这一行」。它不太会先问:这一行为什么会跑到这里。
普通思路
网页慢、安装版黑屏、测试偶发失败,我随口会说:
帮我看看这个报错帮我优化一下帮我修这个 bug它就开改。改的是症状所在的那一层。
先拆「系统为什么会这样」
同样是网页慢,我先让它拆原因,不让它动代码:
用户感觉慢=网络慢?+资源加载慢?+渲染慢?+JavaScript 阻塞?+设计问题?根因找错,优化就是在错的层上加补丁。Agent 特别擅长加补丁。
CaPilot 在 Linux 打包后视频壁纸零帧,也是同一类坑。开发态能播,.deb 一帧都没有。第一反应是片子没打进包,或者解码器缺了。两边排除完,才摸到 WebKitGTK 把 <video> 交给 GStreamer,GStreamer 不认自定义协议。排查过程写在 Linux 打包后视频壁纸零帧 里。当时要是一上来让 Agent「把 video 标签修好」,大概会在前端绕 blob:,还是零帧。
我给 Agent 的第一性原理提示词
我尽量不说「帮我修这个 bug」。先把它按进分析模式:
先不要改代码。
这是一次 debug,请用第一性原理分析:
1. 可观察的现象是什么?哪一步开始不对?2. 已经确认的事实有哪些?(环境、输入、能复现 / 不能复现的边界)3. 系统要正常工作,必须成立的条件是什么?4. 这些条件里,哪些已经验证过,哪些还是假设?5. 按「能最快证伪」排序,下一步该探哪一条?
不要给补丁。先输出诊断和下一条探针。它还是会想改文件。这句「不要给补丁」得写死。
「能最快证伪」比「最可能的原因」好用。后一种它会讲一个听起来完整的故事;前一种它得设计一条马上能打脸的检查。
三种我反复碰到的 debug
栈很清楚
空指针、类型不对、命令退出码非零。栈指向的位置往往就是该改的位置。这种我直接让它修,不走全套。
还是会看一眼它改的是根因还是把异常吞掉。unwrap 改成 unwrap_or_default,日志是干净了,数据是空的。
现象在,栈帮不上
「感觉慢」、偶发失败、只在某一台机器上出现。没有一张漂亮的栈。
我让它先写一张表:现象、已确认事实、未验证假设、下一条探针。没有探针之前不准动代码。
Linux 壁纸那次,探针很具体:同一套 WebKitGTK 里读 <video> 的 videoWidth。file:// 和真 HTTP 出帧,blob: 和自定义协议零帧。表出来之后,修复目标才变成「给 GStreamer 一个它能打开的 URI」,而不是继续改前端。
开发有、打包没有
pnpm tauri dev 正常,安装包不行。Agent 默认会去改业务代码。这类问题经常出在 URI、CSP、打包资源、权限,不在你正在写的那一层。
我先让它对比两条路径:开发态的输入是什么,安装版的输入是什么。差在喂给下一层的东西,就先别改产品逻辑。
诊断出来之后,让它攻击自己
模型很会顺着你说。我说「应该是缓存问题」,它很少问「你怎么知道是缓存」,直接开始清缓存、加时间戳。
所以诊断一出来,我会另开一段,专门当审查,不当修复:
现在请停止改代码。
你是在审查刚才的诊断,不是在帮忙圆场。
请攻击它:
1. 这条诊断依赖了哪些还没验证的假设?2. 有哪个事实和它矛盾?3. 如果补丁打上去,哪个症状会消失、根因却还在?4. 有没有更便宜的探针,能在改代码之前把这条诊断证伪?5. 假如修完一周后又炸,最可能炸在哪?
不要为了认可诊断而分析。优先寻找它错的方式。同一条会话里,它刚写完诊断,立刻攻击,有时会护短。护得厉害我就换一个窗口,或者丢给另一个模型。后来用 Paseo 的 advisor,就是把这步从「我记得要问」变成固定动作。
我自己查的时候也会走这一圈:
现象 ↓拆条件 / 写假设 ↓探针证伪 ↓诊断 ↓攻击诊断 ↓再改代码Agent 默认从「改代码」开始。前面几步得我手动接上。
我现在指挥 debug 的五步
会留下来的问题,我大致按这个顺序。栈已经指到那一行的,跳过前四步,不装。
1. 固定现象
先不要修。
写下:- 期望行为- 实际行为- 复现步骤- 只在什么环境出现「修一下」三个字,Agent 会自己编一个现象。现象写不准,后面全是空忙。
2. 拆条件
系统要正常,必须成立哪些条件?哪些已经验证?哪些还是假设?按能最快证伪的顺序排列。3. 只发探针,不发补丁
针对排序最高的那条假设,给出一条最小探针。不要改产品代码。告诉我运行什么、看到什么算证实、看到什么算推翻。Linux 壁纸那次,gst-play 能播、自定义协议 MEDIA_ERR_SRC_NOT_SUPPORTED,这两条就把「片子坏了」和「自己实现 Range 就行」一起关掉了。
4. 对抗性审查
假设这个补丁一周后失效。
分析失效原因。
攻击当前诊断。「一周后失效」比「请指出不足之处」好用。后一种它会客客气气列三条,前一种它会去找补丁盖住的那层。
5. 再改代码
这步我以前最想跳。跳完通常第二天用另一个输入,问题换个脸回来。
我什么时候不用这套
改个文案、修个拼写、看一眼就知道的空指针,直接让它写。这套分析加审查有成本。
判断力花在现象和栈对不上的时候:打包才坏、偶发、性能、权限、跨进程。那种时候 Agent 最快的动作,往往是最贵的弯路。
调度、交接、第二意见怎么跑,写在 我怎么使用 Paseo。这篇只到动手改代码之前:先问系统为什么会这样,再让模型拆自己的诊断。