七牛云

2/3 的工程师都踩过这个坑:AI 改老代码,越改越危险!

AI Coding 正在快速进入研发流程。

对新项目来说,它可以快速生成代码、补充测试、提升开发效率。但在大量真实企业场景里,研发团队面对的并不是一个干净的新项目,而是一个运行多年、依赖复杂、文档缺失、夹杂大量历史逻辑的老系统。

每个做过老项目的工程师,都熟悉这三个瞬间:

第一个瞬间:想改一个模块,翻遍仓库找不到文档。唯一懂它的人早就离职了——或者就是半年前的你自己,你也忘了当初为什么这么写。

第二个瞬间:代码里散落着大量补丁和“看起来很奇怪”的分支。删又不敢删,留又说不清为什么要留。每次改这里都像拆弹。

第三个瞬间:上线后客户报障。排查半天发现——某个为大客户定制的特殊逻辑,在最近的重构中被“优化”掉了。没人记得它的存在,直到出事。

如果你经历过其中任何一个,恭喜你:你不是一个人。

01

2/3 的工程师,都踩过同一个坑

七牛云在内部做过一轮面向一线工程师的调研,重点了解大家使用大模型处理老代码时的真实体感。这组数据不是严格统计学意义上的行业样本,但能反映研发一线非常典型的顾虑。

三大障碍,拦在 AI 和老代码之间:

  • 输出不稳定,不敢直接用——28.6%

  • 没有测试,无法验证对错——21.4%

  • 上下文装不下,看不全代码——17.9%

这三个问题加起来,接近七成的工程师在使用 AI 处理历史代码时感到“不踏实”。

但最危险的不是这三个。

最危险的是:2/3 的工程师亲历过——大模型会“悄悄丢掉”特殊逻辑。

你让它重构一段代码,它高高兴兴地给你优化得干干净净。你看了一眼,结构清晰、命名规范,完美。提交、上线。

然后在某个你完全想不到的时刻,一个特殊条件触发了——线上炸了。

原因并不是模型故意犯错,而是它缺少历史上下文。大模型倾向于把缺少解释的特殊分支,理解成重复、冗余或可以简化的逻辑。当那些为历史兼容、客户定制、临时救火而存在的非典型代码没有被显式标注时,它很容易在优化过程中把这些逻辑一起清理掉。

损伤发生在改动当下,暴露却在很久以后。这就是旧仓库治理最危险的地方——它有潜伏期。

02

问题的本质:两条恶性循环链

把这些现象拆开看,本质上是两条恶性循环:

第一条链:理解不足 → 上下文装不下 → 越不敢用 → 理解越不足

老代码没有文档,你把整个仓库塞给大模型,上下文装不下。它只能看到局部,盲人摸象。你不敢让它改大的,只能改小的。改完也不补文档,下一次还是从零开始考古。

第二条链:缺测试 → 无法验证对错 → 不敢改 → 测试更缺

老代码先天缺测试。没有测试基线,你就不知道大模型改得对不对。越不知道对不对,越不敢让它改。越不改,测试越补不上。

两条链绞在一起,就形成了一个死局:你知道 AI 写代码很快,但在你的老项目上,它就是用不起来。

某模型大厂的分享印证了同一个结论:AI 写代码的速度至少是人的 10 倍,但人均需求吞吐率只提升了 1.6 倍。

10 倍的生产力工具,只产出了 1.6 倍的效果。中间的差距去哪了?

答案是:Vibe Coding 离可交付,还差得很远。

基础正确率可能有 80 分,但可交付性——可维护性、工程规范性、兼容性——只有 40 到 60 分。差的那几十分,需要一套“安全带”来补上。

03

四层治理框架:从“不敢改”到“可验证”

七牛云在一个有着十余年历史的视频直播核心项目上,摸索出了一套四层递进式的历史代码治理框架。

这个项目的特殊性在于:虽然经过多轮架构升级,但至今仍要兼容七年前甚至十年前的播放逻辑——是典型的“业务不能停、代码不敢动”的历史负债重灾区。

整套框架的核心逻辑是:先看懂,再锁住,再动手,最后固化成机制。

第一层:理解层——先画地图,再读代码

很多人拿到老代码的第一反应是:直接让大模型读。

正确的方式是:结构优先,先画地图。

不要一上来就扎进细节。先让大模型帮你梳理:这个系统有哪些模块?入口在哪?调用链怎么走?模块之间用什么协议通信?哪些是高风险区域?

就像你去一个陌生城市,先看地图,再逛具体的街。

建图的正确路径:

  1. 工具提取骨架——用 rg/grep、ctags、依赖图等工具先把符号、入口和结构抽出来

  2. 按模块分批送 LLM—— 每次只喂一个模块,不要贪多

  3. 逐块沉淀地图——每个模块产出一份 md 格式的“地图”

  4. 汇总层用地图理解地图——上下文换成摘要,不再是源码

  5. CLAUDE.md 变路由表——后续会话按任务加载相关地图片段

而且文档要分层:

  • 基础层:每个模块是干什么的

  • 入门层:模块之间的交互关系

  • 进阶层:模块内部的实现细节

  • 高阶层:特殊逻辑、哪些不能动、为什么不能动

分层的好处是:以后大模型再读的时候,不用每次都把所有细节吃一遍。需要什么层级,加载什么层级。上下文装不下,靠的不是更大的窗口,而是更高的信息密度。

Image

第二层:守护层——把隐性逻辑变成显式约束

这是整个框架里最关键的一层。

如果说理解层解决的是“看不懂”的问题,守护层解决的就是“不敢改”的问题——也就是 2/3 工程师踩过的那个坑。

核心思路只有一句话:把藏在代码里的隐性逻辑,变成大模型“看得见”的显式约束。

分三步走:

第一步:识别

让大模型扫描代码,列出所有“可疑”的点:

  • 客户定制的逻辑

  • 历史兼容的分支

  • 灰度开关

  • 特殊错误码

  • fallback

要求很简单:标出位置、触发条件、影响字段。不确定的地方明确标「不确定」,不许脑补。

第二步:建清单

把扫描结果整理成一份“不可破坏清单”(也叫分支账本),然后逐条人工确认:

  • 这个是客户定制吗?哪个客户?

  • 这个是历史兼容吗?兼容谁?

  • 这个可以清理掉吗?

  • 这个必须保留,绝对不能动?

这一步必须有人工介入。大模型能帮你找,但它没法替你判断“这个客户重不重要”、“这个兼容还要不要”。

第三步:变测试

最关键的一步:把每一条“不可破坏”的行为,转成行为快照测试。

不是测“功能能不能跑”,而是测“关键输出字段和旧行为是否完全一致”。

为什么要这么做?因为 Prompt 声明是最脆弱的防线。

你在对话里跟大模型说“这个逻辑别动啊”,它当时点头了。下一次对话、下一个 PR、换一个模型——它就忘了。

口头声明只活在单次对话里。保护规则必须外化到代码注释和测试中,让大模型每次读上下文时都“看得见”,让 CI 每次提交时都“查得到”。

Image

第三层:改造层——小步、可审、可回退

理解和守护都到位了,终于可以动手改了。

但别急。改造层的核心原则是:宁可慢,不能乱。

原则一:最小改动

每次只改一个点。重构就是重构,修 bug 就是修 bug,绝对不要混在一起。

大模型特别容易做“顺便优化”。改着改着发现旁边还有可以整理的地方,就一起改了。问题一旦出现,定位成本会被显著放大。

明确禁止“顺便优化”无关代码。

原则二:diff 行为审查

改完先看 diff,但看的不是“代码优不优雅”——而是“行为变没变”。

重点检查:

  • 有没有删掉特殊分支?

  • 有没有改默认值?

  • 调用顺序变了吗?

  • 重试次数、超时时间改了吗?

  • fallback 逻辑还在吗?

把大模型从“审美模式”拉回“行为风险控制模式”。

原则三:多视角 review

不要让同一个模型既写又审。让第二个模型专门负责挑毛病——用“攻击性评审”的思路,主动找弱点,而不是期待它自我纠错。

复杂改动,用更强的模型来审。关键路径,必须人工逐行过。

原则四:灰度兜底

本地通过 ≠ 线上安全。这是我们调研中发现的一个被严重低估的盲区——89.3% 的人依赖测试,60.7% 依赖 Code Review,但只有 10.7% 会用灰度、开关、监控。

高风险路径,一定要加开关、加日志、加灰度。先放 1% 的流量跑一跑,盯着监控没问题再全量。或者新旧入口并行,先灰度回归再替换老入口。

Image

第四层:工作流层——把做法固化成机制

前三步做得再好,如果只存在于某几个人的脑子里,那就是个人经验,不是团队能力。

人一走,方法就没了。

所以第四层要做的,是把做法固化成机制:

  1. 文档驱动:想和干分开

    先让大模型出方案文档(md),人工审核确认了,再让它动代码。

    每个模块都要有一份喂给大模型的 md 文件,写清楚约束、目标、测试流程。设计用高级模型,写代码用普通模型——没关系,文档沉淀下来了,就是资产。

  2. 人工确认闭环

    大模型只产出草稿。最终的文档和代码变更,必须经过人工确认节点,不直接落库。

    这一步确实会慢一点,但它是必须的卡点。不审阅的话,你的“理解债”会越来越高——越积越看不懂,越看不懂越积。恶性循环就是这么来的。

  3. 资产回流

    每次治理结束后,模块地图、分支账本、不可破坏清单、行为快照、灰度记录和复盘结论,都要回流到仓库或知识库里。

    否则这次改完了,下次还是从零开始考古。

  4. CI 持续守护

    把“不可破坏清单”接进 CI。变更触及已标注的特殊逻辑,自动触发相关测试,并要求人工 review,产出特殊逻辑覆盖率报告。

    可以参考 Danger 的做法——在 CI 里跑自定义规则脚本,将 invariants.yml 与git diff做交集,命中即触发对应快照测试并标记强制 review。

Image

04

风险分级:什么能让 AI 干,什么必须人来

不是所有代码都值得用同一套标准对待。我们按风险等级划了四档:

Image

这里的底线是:

没有 owner,不改。

没有验证,不改。

没有回滚,不进生产。

越接近业务契约、资金安全、权限安全、客户定制和线上副作用,越不能让模型凭“看起来等价”自行判断安全性。

05

启动指南:两周试点法

道理都懂了,从哪下手?

我们的建议是:选一个有代表性但不致命的模块,做两周试点。

不要一上来就啃最硬的骨头。先找一个有 owner、有验证入口、出问题影响可控的模块,把整套流程跑通。

第一周:完成试点启动与风险显性化

第 1 天,选模块:选择有代表性但不致命、有 owner、有验证入口的模块

第 2 天,定边界:写清本次看什么、不看什么,哪些行为绝对不能改变

第 3 天,收上下文:收集代码、文档、PR、工单、日志、配置、测试样例

第 4 天,出地图:产出入口、调用链、依赖、高风险区域、不确定点

第 5 天,列账本:记录特殊分支、触发条件、影响行为、待确认问题

第一周结束,你应该拿到:试点范围说明、模块地图、分支账本、待确认问题清单、初步的不可破坏清单。

然后问自己三个问题:范围清楚吗?owner 确认了吗?下周具备补快照的条件吗?

答案都是“是”,再进入第二周。

Image

第二周:完成清单、快照和小步改造

第二周重点不是大规模重构,而是把第一周发现的问题转化为可验证资产,并选择一个最小改造点验证流程。

第 6 天,确认不可破坏清单:逐条找 owner、历史材料或线上证据确认,不确定项继续保留

第 7 天,补行为快照:把关键输入、输出、错误码、fallback、默认值和边界条件记录下来

第 8 天,转验证项:能自动化的写成测试,不能自动化的形成验收 checklist 或灰度观察项

第 9 天,做最小改造:只选择一个目标,不混入顺手优化,不做无关格式化

第 10 天,review 与复盘:检查 diff 行为风险,确认灰度和回滚方案,把地图、账本、清单和快照回流到仓库

第二周结束,不一定要完成一个大重构,但应该证明三件事:

  1. 团队能看清这个模块的主要风险

  2. 关键历史行为已经有保护方式。

  3. 后续改造可以按小步、可审、可回退的方式继续推进。

这样,AI 不是直接“接管老系统”,而是帮助团队建立一套可以持续复用的治理机制。

06

写在最后:AI 来了,AI 看见了,AI 还没征服

JetBrains 有一句总结很精准:“AI came. AI saw. AI hasn't conquered.”

85% 的开发者已经在定期使用 AI 工具,34% 的代码来自 AI 生成,但 99% 的开发者对 AI 仍有担忧,46% 明确不信任 AI 输出的准确性。

这不是“不用”,而是“用但不放心”。

企业级落地的瓶颈,已经不只是“能不能生成代码”,而是“能不能验证生成的代码是对的、可交付的”。

历史代码的治理,就是这场验证战的最前线。

整理文档、梳理分支、补测试、加灰度——这些“笨功夫”,才能把大模型从“看起来很厉害的玩具”,变成“真正能扛事的生产力”。

毕竟,写得快不算本事,上线不出事才算。

历史代码治理的难点,不在于让 AI 写得更快,而在于让团队更快地看清系统、更稳地保护历史行为、更可控地推进改造。

所以,我们对 AI 的期待不应该是:替我们一次性重写老系统。

更现实、也更有价值的期待是:让 AI 帮我们把隐性知识变成显性资产,把不可控风险变成工程约束,把一次次个人经验沉淀成团队能力。

当做到这一点,历史代码就不再只是负债。它会逐渐变成一套可理解、可验证、可演进的工程资产。

Image

推荐阅读

Image
Image