内容提要
工程师 Cindy Sridharan 用 Claude 修复三个生产 Bug 后总结:AI 的根因分析往往条理清晰却结论错误,原因在于人类对 AI 生成代码的理解不足。核心方法是先让 Agent 采集客观事实,再推导假设,把调试转化为约束满足问题——用对照寻找强信号,用全部事实验证假设,矛盾即剔除。读代码应是最后一步。复现与对抗评审只是排除手段,需附证据。人工干预次数是衡量 Agent 原生基础设施成熟度的最诚实指标。
延伸解读
理解力债务:AI 代码的隐性风险
当 AI 生成数千行代码时,工程师往往只能粗浅理解,这导致在 AI 给出错误根因分析时无力反驳。文中延迟 Bug 案例中,作者逐行阅读了 9000 行代码,仍被错误结论说服。这种“理解力债务”会累积,盲目信任 AI 的修复可能将错误代码合并上线,造成生产事故。
调试新范式:事实层与推导层分离
作者提出将调试拆解为事实层和推导层。事实层由工具采集日志、抓包等客观数据,不可篡改;推导层是 AI 的假设和叙事。只有满足所有事实约束的假设才能保留,矛盾即剔除。这避免了 AI 先读代码时从片面角度走偏,读代码应作为最后一步。
强信号挖掘:从弱指标到根因
弱信号如 P99 延迟可被多种假设解释,而强信号如 DNS 返回地址数从 5 激增到 400,仅少数假设能解释。通过构建“假设×事实”矩阵,可以快速识别强信号。文中延迟 Bug 正是依靠 DNS 地址数差异锁定客户端路由错误,而非最初怀疑的证书重载。
复现与对抗评审的陷阱
本地复现可能产生与生产不同的信号,必须验证复现是否产生相同强信号才能采信。对抗式评审本质是排除器,不能验证事实完整性,且同一模型评审易重复观点。要求结论附证据引用,可剔除约三分之一无引用结论,提升可靠性。
Q&A
为什么让 AI 先读代码来调试生产 Bug 是反模式?
因为代码只能展示系统“可能发生什么”,而不是生产中“实际发生了什么”。状态空间太大,Agent 会自行挑选代码片段,容易从一个看似合理的角度一路走偏。读代码应该是整个调查的最后一步。
把调试变成约束满足问题的核心框架是什么?
将调试分为两层:事实层由工具采集日志、抓包、profile 等不可篡改的数据;推导层是 Agent 的假设、推论和叙事。事实层中的每一条事实都是硬约束,只有满足全部约束的假设才能保留,矛盾一条就必须剔除该假设。
三步调试循环具体包括哪些步骤?
第一步用对照找信号:只出现在变量、不出现在对照里的数据才是高保真信号。第二步找强信号:能被很多假设同时解释的是弱信号,只有一两个假设能解释的才是强信号,可画“假设×事实”矩阵来识别。第三步用全部事实验证:候选假设必须经受事实层中每一条事实的检验,包括噪声,矛盾一条就丢弃。
当所有假设都不成立时,应该怎么办?
不要急着编新故事,先尝试五招:复核事实的采集方式是否采错机器、时间窗口或工具版本;拆分过粗的假设;合并过细的假设;组合互补的假设;以上都不行再基于现有事实提出全新假设。
Agent 的复现结果为什么不能直接信任?
复现本身属于推导层,可能只是巧合的推导产物。必须让复现产出与真实案例完全一致的强信号,才能认定它可信。例如挂起案例中,同事复现的症状与用户反馈一模一样,但抓包后半段和内核 IPC 表与真实案例不同,说明是另一个真实存在的 Bug,而非用户遇到的那个。
对抗式评审在调试中应该怎么用?
对抗式评审本质是证伪的“排除器”,而不是事实本身的验证器。它无法保证事实层完整,且同一模型、同一上下文的评审者容易“一个观点算两遍”。更好的用法是让它去找反例、做排除,并要求每条结论附上证据引用。作者发现被追问的结论中约三分之一给不出引用,可直接剔除。
在 AI 时代,软件工厂需要做哪些思维转变?
从理解代码转向设计验证回路(选对照、定约束、否决未验证的假设);从读懂代码转向采集事实(让 Agent 从正确的层、在正确的时机拿到数据);从出事再临时采集转向默认采集(强信号放在最浅的一层);人从“肉体代理”转向政策制定者,只处理有歧义、需担责的决策;从“你不会用”的技能问题转向基础设施问题,让 Agent 默认就能严谨调试。
为什么人工干预次数是衡量 Agent 原生基础设施成熟度的最诚实指标?
因为每一次人工干预都意味着流程里有一个缺口。如果基础设施足够成熟,Agent 应该能默认进行严谨调试,而不依赖个人提示词或人工临时介入。因此人工干预次数越少,说明流程越接近真正的 Agent 原生。