一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

驾驭 AI Harness Engineering:用冰山假设追踪代码根因

时间:2026-09-12 17:28:01 编辑:袖梨 来源:一聚教程网

AI 生成的代码一旦出现故障,人们很容易沿着日志找到某个异常位置,随即把它认定为根因。但在复杂工程中,报错通常只是系统露出水面的部分,背后还可能存在结构缺陷、设计假设和依赖传播问题。要让 AI 真正参与可靠的软件维护,就需要建立更深入的归因与回归机制。

概述

海明威在《午后之死》里提出过一个写作者的原则,后来被称作"冰山原则":他说,"冰山运动之雄伟壮观,是因为它只有八分之一在水面上。"水面上的八分之一,是写出来的部分;水面下的七分之八,是从来不写、但读者能感受到的部分。借用海明威的冰山,是因为调试一个(AI Native 代码)的事故,和读海明威的短篇是一模一样的心智活动——水面上的东西,永远不是全部。

调试与归因层:当 AI 出错之后——冰山在水线下的部分

AI Harness Engineering 系列 · 第十篇 · 王海涛(公众号:Jia言Yi行 · GitHub:derekwang85 · 腾讯云 TVP / 架构师名人堂)

海明威在《午后之死》里提出过一个写作者的原则,后来被称作"冰山原则":他说,"冰山运动之雄伟壮观,是因为它只有八分之一在水面上。"水面上的八分之一,是写出来的部分;水面下的七分之八,是从来不写、但读者能感受到的部分。

这一篇借用海明威的冰山,不是因为要讲写作,而是因为调试一个(AI Native 代码)的事故,和读海明威的短篇是一模一样的心智活动——水面上的东西,永远不是全部。

00-intro.jpg

出错的时候,你看到的是八分之一

当一个 AI 干的活出了错,人类第一眼看到的永远是那个"现象"。

可能是提示词得到的反馈是废话,可能是生成的文件编译不过,可能是数字对不上,可能是接口超时。人打开日志,看到红色,看到报错,看到一行戳在脸上的 message,然后本能地问出那句最危险的话: "这是哪里错了?"

注意,这个问题本身就是陷阱。

因为它默认了"错"是个可以用鼠标点中的具体位置——一个函数、一行代码、一个字段。按照这个思考惯性,会顺着日志往下点,直到点到一个看起来可疑的地方,宣布"找到了"。可绝大多数时候,你能顺藤摸瓜的只是水面上的那八分之一。真正的根因,沉在水下。

三层冰山:现象、结构、设计

01-three-layers.jpg

我们后来把"水面下"分成清晰的三层,每一层都对应一种解释"为什么错"的深度:

第一层是现象层(L1) 。你直接看到的那个报错本身。它描述"发生了什么",但它几乎从不解释"为什么"。"接口超时了"是 L1。"这个文件编译失败"是 L1。它们是冰山的尖。

第二层是结构层(L2) 。在现象的后面,代码结构本身有没有问题。"接口超时"的 L2 可能是"这个服务没有设置超时配置,默认值小得离谱"。现象告诉你结果,结构告诉你布局有什么毛病。

第三层是设计层(L3) 。再往深处,是整个方案的设计有没有问题。"服务没设超时"的设计问题,可能是"当初压根没把'另一个服务会慢'设计进方案里"——它不是一个字段的事,是一个假设的事。

这三层不是学术分类,它是一条硬性的排查门禁。我们把它写进了门禁里:每个失败必须完成三层冰山分析,才能进入修复。  而且有一条写死的规定,直戳人心——

禁止把"数据问题"当成根因。

“数据问题“,这四个字是无数调试事故的藏身之所。你会看到很多团队,追了三天,最后得出结论"哦,是数据不对"。这个结论看起来无懈可击,其实它只是把 L1 的"现象"换了个说法,重新报了一遍。数据为什么不对?是上游喂错了,还是校验漏了,还是格式约定不一致?每一个"数据问题"的背后,都藏着一层结构问题和一层设计问题。允许"数据问题"当根因,等于允许自己永远停在冰山水面上的那一层。

不过,"愿意往下钻"只是第一课。真正的凶险,往往发生在你以为"根因已经找到、可以动手了"的那一秒——因为大多数涉及 AI Coding的编码问题,因为缺乏人手搓过程中的“故事性”,往往很难产生横向关联,所以,真正的不好用,不是在于没找到根因,而是把信息和耐心耗光在了"改对了这一处,却惊动了别处"。

改 A 之前,先想 BCDE

02-ripple.jpg

找到根因还不够,因为工程往往具有非孤立事件的关联关系,事故之所以是"事故",常常不是因为一处错,而是因为改了一处,引爆了别处

这是我们踩得最深的坑之一。早期我们修 bug,经常是"头疼医头,脚疼医脚"。改了字段,包了解出来了,回测也过了。结果过了几天,另一个毫不相关的模块开始报错。查了半天,发现是上次那个"修好了"的改动,悄悄影响了一个没人想到的角落。

于是有了一个听上去像废话、做起来却反人性的规矩:改 A 之前,先想 BCDE。

我们把它做成了一套叫"涟漪分析"的机制。要改任何一个地方,先自动扫描它的影响面——直接依赖、间接依赖、被谁引用、谁引用它。然后按"涟漪"的远近分级级联回归:

  • 改得很浅、影响只在一个文件内的,做最内层回归;
  • 影响波及到相关模块的,次一层回归;
  • 往上传导到整条链路的,再往外一层;
  • 一旦改动动了约定、契约、接口,直接触发全量回归

这套 R0 到 R4 的四级级联,目的只有一个:让"我改的这个 A",在还没上线之前,先把可能被波及的 B、C、D、E 全部想一遍、测一遍。改一行,牵着十行,那不是效率低,那是对的。

一个修对了一半的 bug:Round 3

03-half-fixed.jpg

说一个真实的、让我印象极深的例子。有个 bug,追了三轮。

第一轮:Agent 看到报错,判断是字段解包不对,改了,回测没完全过。

第二轮:Agent 仔细看,发现字段和解包其实都对了,是另一个微服务的接口超时——它已经碰到结构层了,但还没到底。

第三轮:真正的问题浮现——超时的根因,是那个远程调用压根没配超时参数,默认值太小,慢一点就崩。到了这一步,光靠自动修复已经处理不了了,因为它牵扯到一个"要不要给依赖方加配置"的跨服务决策。于是触发了 HITL——人工介入,人类来拍板:加超时配置。

这个经历,我想分享的,不是 Agent 聪明,而是它差一点就在第一轮宣布"修好了" 。如果没有三层冰山逼它往下钻,如果没有涟漪回归逼它把影响面看清,它会在假根因上停下来,然后留下一颗定时炸弹。而绝大多数团队,恰恰停在了第一轮。

所以哪怕对AI Agent来说,调试编码问题也绝对是个技术活,这门手艺,练的不是"多快找到一个错误",而是"愿不愿意把水下的那七分之八也看完"。停在表面的诊断只是止痛,钻到根因的修复才是根治——你可以骗过同事,甚至骗过自己,但事故从不讲人情。 所以,要立规矩,要建制度。

04-traceability.jpg

历史解决方案的检索

这套"三层冰山 + 涟漪回归 + 归因沉淀"的完整循环,在 derekinside 里有一个最朴素、也最有说服力的落点:历史解决方案的检索

回想一下第 9 篇我们在讲记忆——记忆不是拿来'看起来丰富'的,记忆是为了让归因不再从零开始。当一个新的 issue 进来,Worker 第一时间不是埋头分析,而是先去 derekinside 检索:以前有没有处理过同类问题?  如果有,直接取出当年的 solution,看当年怎么定性的、怎么修的、留了什么备注。

这让"归因"从一次次重复劳动,变成了越用越快的递进。同类 bug 第一次处理要一小时,第二次十分钟,第三次可能看一眼就能定位。记忆的最终价值,不是让你记得更多,是让你归因得更快、更准

矫枉不一定过正

05-anti-pattern.jpg

"三层冰山"和"涟漪回归"的名字太好听了,好听到容易让人滥用。

不是每个 bug 都值得做完整的三层冰山分析。一个拼写错误、一个固定文案写错、一个显而易见的笔误,你要它"分析设计层根因",那不是严谨,那是折腾。过度归因的系统,会像过度招投标的公司一样,被自己的流程拖到动弹不得。

判断题只有一条:这个现象,停在这一层,会不会卷土重来?  如果改了 L1 就永不再犯,那它就是 L1 该解的问题;如果改了 L1 下个月换个姿势又来了,那它才配得上往下钻一层。冰山的价值,是提醒你别只看表面,不是逼你对每一个涟漪都做潜入深海。

第一天就能用的清单

06-checklist.jpg

  1. 把"这是哪里错了"改成"这是哪一层错了"。先问自己是现象、结构,还是设计。
  2. 禁止用"数据问题"当根因。数据不对,就去追数据为什么不对。
  3. 改任何东西之前,先问一句"改了 A,会不会影响 BCDE"。影响面不清,不动手。
  4. 给关键改动配涟漪回归:改得越深,回归范围越大,动了约定就全量回归。
  5. 让每次归因可追溯:commit 带推理链,Issue 三权分立,别让结论孤零零地躺着。

下一篇预告

归因归到了,修也修对了,可系统还是不会自动变好。真正让一个 AI 体系"越跑越强"的,不是会修 bug,而是会把修过的 bug 沉淀成下一次不再犯的能力。下一篇,我们讲系列里最硬核的一篇:测试与自成长层——一次性验证跑 10 秒,是怎么变成 6 个套件 50 条场景的自动护城河的。

热门栏目