AI 写代码越来越强,但它不知道我们上周修了什么 bug,把 Bug 重新引入生产环境了

14 小时 18 分钟前
 huoru

三个月前,我们花了两周时间修了一个 bug 。

用户账单偶尔会出现 ¥0.01 的误差。复现不稳定,线上偶发,客服一直在手动补差价。翻遍了日志,最后定位到一个经典问题:浮点数精度。

0.1 + 0.2 在 IEEE 754 里不等于 0.3,这个大家都听说过,但真的踩到还是很痛。

修复方案是把所有金额改成以「分」为单位存整数,展示时再除以 100 。改动不复杂,但涉及的地方很多,改完之后代码里到处是 amount * 100Math.round()/ 100,看起来有点丑,但能用,bug 消失了。

然后上个月,我让 Agent 帮我重构结算模块,优化一下代码结构。

它看到那堆乘除,觉得多此一举,顺手给「简化」了,改回了直接用浮点数。逻辑更清晰,代码更短,单元测试全过。

那个 ¥0.01 的 bug 悄悄回来了。


这件事让我开始认真想一个问题:

我们有代码审查,但我们需要「意图审查」。

这不是 AI 写了烂代码

大家讨论 AI 写代码,通常聚焦在输出质量上:架构合不合理、有没有 bug 、测试过了没有。

但我说的这个问题不一样。

Agent 那次重构质量是好的。逻辑清晰,可读性提升了,测试也没挂。它只是不知道「那堆看起来多余的乘除,是两周 debug 换来的」。

从它的角度看,price * 100 然后 / 100 是纯粹的噪音——数学上等价,白白增加了阅读负担。优化掉,天经地义。

你想想一个工作了五六年的老工程师,碰到这段代码会怎么做?

大概率不会直接删。他会皱着眉头想:「这里为什么要转成整数?不可能是手滑写的,一定有原因。」然后去翻 commit ,或者去问写这段的人。

这叫对不熟悉代码的谦逊感——被坑多了,知道看起来多余的代码往往不是真的多余。

AI Agent 没有这个。它被训练成「顺着干」,而不是「先问为什么」。代码看起来可以简化?简化它。逻辑看起来绕弯子?拉直它。它只会优化表面,不会追问历史。

新项目里这没问题,在一个有历史的真实代码库里,这会出事。

现有的方案都差点意思

每次我说起这个问题,大家都会推荐一些工具。我挨个想过,说说为什么都不够用:

注释:「// 不要修改这里,浮点精度问题」写上去当然有用。但你得先意识到这里需要警告,才会去写。当时修 bug 的人在想的是「终于修完了」,不是「三个月后的 Agent 可能会把这个改回去」。漏写的注释保护不了任何人。

AGENTS.md / CLAUDE.md:同理,你想到的禁忌才能写进去。但大多数坑是事后才知道是坑的,你没法提前把所有决策都整理成文档。

ADR / RFC:门槛太高,大多数团队第一个季度之后就不维护了。就算维护着,也是给人看的文档,不是供 Agent 在改代码前按需查询的。

Wiki / Notion / Confluence:文档会和代码脱节。「金额统一用分存储」这件事,可能在某个内部文档里提了一句,但 Agent 不会在重构代码前主动去翻 Confluence ,就算翻了,也是一堆非结构化的文字,未必能命中。

PR 描述:当时修 bug 的 PR 描述里可能写了原因,但埋在 GitHub 历史里,没人去翻,Agent 更不会主动去看。

每一个工具都是对真实问题的局部回应,但没有一个能在 Agent 动手之前,把「这里曾经踩过什么坑、为什么要这么写」这件事,可靠地送到它面前。

我们缺的是「意图审查」

现有的代码审查,回答的是:「这个变更实现得好不好?」

看 diff ,查正确性、风格、测试覆盖率。这个流程很成熟,也很必要。

但代码审查解决不了另一个问题:「这个变更,在已有的历史背景下,方向对不对?」

这个问题需要审查者记住代码库的历史,记得这堆乘除是两周 debug 换来的,记得某个绕弯子的写法是填过坑之后留下的疤。大多数审查者没这个上下文,就算是原作者,三个月后也可能忘了当时为什么。

所以我觉得我们需要一层新的审查,叫意图审查,发生在代码被改之前,而不是之后。

它问的是:

对人类工程师来说,这些审查以非正式的方式发生:发条消息、瞄一眼 commit 历史、和写那段代码的人聊三十秒。

对 AI Agent 来说,这根本不会发生。没有「去问问当时踩过坑的人」的等价操作。Agent 读当前代码,看起来可以优化,就优化了,历史上踩过的坑对它来说是不可见的。

意图审查要怎么做

要真的能用起来,得满足三点:

第一,决策必须是结构化的。

「金额统一用分存储,避免浮点精度」这句话写在 Wiki 上供人阅读没问题。但 Agent 需要的是:决定了什么、为什么这么决定、涉及哪些文件、哪些操作是被明确禁止的。自由文本把这些结构藏起来了,Agent 每次都要重新解析一遍,还不一定能命中。

第二,决策必须住在代码旁边。

Wiki 会漂移,Notion 会被遗忘,Slack 消息串会被淹没。唯一能和代码永远保持连接的是 git 本身。决策活在 git 里,就能跟着代码一起被 clone 、被 fork 、被带到三个月后还没接手过这块的人面前。

第三,查询必须自动发生,在改代码之前。

如果需要提醒 Agent 「先查一下历史决策」,它就不会查。这个步骤必须内嵌在正常工作流里,就像它在重构前会先 grep 符号定义一样,查历史的摩擦要低于直接动手的摩擦。

我做了个工具

我最近在开发一个叫 Mainline 的东西,把团队决策以结构化记录的形式存进 git 本身,让 Agent 在改代码前可以查询。

每条「意图记录」长这样:

如果当时修浮点 bug 的时候封存了一条意图记录,三个月后 Agent 重构结算模块,运行 mainline context billing,就会看到:「金额统一用分存储,直接用浮点运算会导致 ¥0.01 偶发误差,已确认线上踩坑,禁止还原。」

那次「简化」大概率就不会发生了。

用了一个月,有几点出乎我意料:

摩擦不在我以为的地方。 我以为工程师会抗拒写这些记录,结果没有——因为 Agent 负责起草,工程师只是过目和调整。真正的摩擦在于:什么时候该封存一条记录?封太频繁是噪音,封太少会漏掉重要的坑。

收益来得比预期晚。 第一周感觉纯粹是额外负担。第三周开始出现「这段为什么要这么写?」的时刻,答案就在日志里。第六周,Agent 开始不用提示就把历史决策当作上下文来用。

两个人协作比一个人用难得多。 一个人用的时候,意图记录是写给自己的备忘。两个工程师同时工作时,它变成了一个协调协议——你得知道对方封存了什么,你们的方向有没有冲突。

工具是开源的( Apache 2.0 ),目前小范围私测,地址在 mainline.sh

https://github.com/mainline-org/mainline

说回这件事本身

AI Agent 现在在很多团队里写相当比例的新代码。代码审查的负担没有降低,反而在升高——因为审查 AI 写的代码认知成本更高,你没办法像问同事一样问它「你为什么这么改」。

现在的情况是,每次代码审查都得身兼两职:一边看实现,一边猜方向对不对。大多数时候,方向验证是静默失败的。审查者不知道那堆乘除是修 bug 留下来的,点了 approve ,坑就回来了。

这个问题靠更好的 prompt 解决不了,靠更大的上下文窗口解决不了,靠更强的模型也解决不了。

这是一个结构性问题:团队踩过的坑住在哪里?

现在它住在人的脑子里、Slack 里、PR 描述里——Agent 不会主动去看的地方。

要让 AI 真正能在一个有历史的代码库里可靠地工作,我们需要把这些知识搬到它会可靠地去看的地方。对大多数团队来说,那就是 git 。

我们有代码审查。我们需要意图审查。


你们有没有被 Agent 悄悄还原过某个 bug 修复?现在是怎么防的?

4862 次点击
所在节点    推广
98 条回复
huoru
11 小时 14 分钟前
@SD10 感谢。是啊,最起码看看 意图。。我理解大家都越来越不能去看代码了
ovtfkw
10 小时 58 分钟前
所以其实是虚构的故事+软广?
x1aoYao
10 小时 54 分钟前
@ovtfkw 百分百编故事的,搞金融的还需要排查才知道钱不能用浮点数?大学生都没这么水吧
catoncat
10 小时 46 分钟前
@ovtfkw #62
@x1aoYao #63 是虚构的,不过 mainline 的代码确实是用 mainline “自举”开发出来的。clone 下来使用 mainline hub open 可以打开网页看到 mainline 项目自己所有的历史 intent 和详情。
这个故事确实有点太简单了。只是为了便于用户理解。包括现在的 mainline.sh 也是苦于不知道怎么设计比较好传达项目的用途。
jydeng
10 小时 40 分钟前
写的是不错,不过「金额不用浮点数」应该是个常识,人和 AI 都有问题。
402124773
10 小时 39 分钟前
你能不能正面回复下这个问题,是不是为了推广,编造的上面的故事?
loryyang
10 小时 37 分钟前
@huoru #10 那只是你没给他规定而已。如果只说一句: 开发完成写 changelog ,那当然会随便乱写。你至少要写:”什么时候,在什么地方,写入什么文件名,内容包括*****,文件长度不可超过多少行“
模型能力你说指令完全遵从确实不行,但在哪里写文档,什么时候写基本上还是做得到的
xing7673
10 小时 35 分钟前
移到推广节点
EeveeRibbon
10 小时 33 分钟前
idealhs
10 小时 32 分钟前
恶心人编故事,人和 AI 都不会写出这种 bug 现在打开 V2 全是 AI 写的 AI 推广文,真没什么好看的了
catoncat
10 小时 29 分钟前
@loryyang #67 主要是文档会腐化,有比较高的维护成本,多人协作时也会有类似代码冲突一样的决策冲突问题。这个工具主要还是参考 git 提供一个可以多人统一的工作流。
你说的正好是这个工具提供的 intent 的数据结构之一,就是记录下约束。后面 agent 有新的 intent 要开发是会根据文件自动看到这些上下文。
zhuzhibin
10 小时 29 分钟前
这不是卖广告?前面铺垫了这么多
legendBro
10 小时 26 分钟前
金融用浮点数?难道不是用精准计算的方法,比如 java 里的 BigDecimal ?
huoru
10 小时 26 分钟前
@zhuzhibin story telling 啊。
huoru
10 小时 25 分钟前
@zhuzhibin 分享事情啊。纯技术的角度,我分享过了: https://study.congcong.us/t/1210451
kamilic
10 小时 22 分钟前
你这种不就是一个变种知识库或者是记忆模块 😂
按照古法编程这种敏感数字操作就应该转用成熟且久经考验的公共库,又或者是自研经过测试的库。再进一步,围绕这种场景建立一堆规范和 lint ,以及 CI/CD 单元测试来挡着。而不是搞个东西让 ai 记得,万一你的这个坑召回不了呢,不也是照样踩进去了?
人和 AI 都会出错的,只是 AI 上下文大一点而已,但是不代表他每次都能百分百准确找出你这边角旮旯里的「意图」并识别出来。
huoru
10 小时 19 分钟前
@kamilic 是啊,就是这样子。 那现在所谓的 skill, harness engineering, compound engineering 等等词语,不就是 xxx

AI 总是要出错的,人总是会懒得读代码的,我们只是尽可能适应时代做一个能帮助大家的开源产品,哈哈
Clannad0708
10 小时 16 分钟前
那我问个问题,如果你让 ai 写一个新项目他做金额的计算的时候还是会遇到 0.1+0.2 不等于 0.3 的问题吗?
FlashEcho
10 小时 15 分钟前
我怀疑是你给了烂 prompt ,现在的 ai 大概率会建议你改用 Decimal 处理钱吧,你看到 Decimal 一下子就能意识到为啥要用,不会出现用分为单位的整数还要想的情况

要么是你的 ai 模型不行,要么是你的 prompt 太差了,这么基础的问题都处理不好,还有人愿意用你开发的新产品吗?
fennu2333
10 小时 14 分钟前
感觉有点像 Entire https://github.com/entireio ,只是 Entire 把所有的 Agent Session 都存到 git 了
git 记录这个思路不错,我之前自己做 https://github.com/Chorus-AIDLC/Chorus 的时候也想解决这个问题,但做法是把决策固化到一个单独的服务里去了方便 agent 查询

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://study.congcong.us/t/1211151

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX