我的Vibecoding落地之路(老项目)
2026/7/9 18:10:51 网站建设 项目流程

老项目 × AI:从濒死到手术台,我做对了什么?

接手一个十年老单体项目,打开代码,四千行的OrderService、不敢升的 JDK 1.8、被魔改的底层包、写在存储过程里的定时逻辑——那一刻我明白,这不是技术债务,这是技术遗产。
而我要做的,是带着 AI 这把新式工具,把它从“濒死”拉回“体面地活下去”。


写在前面:这不是一篇爽文

如果你也接过这样的项目——打开 IDE 要等半分钟,点进一个类看到滚动条细得像根针,问同事“这段干嘛的”只会收到一句“别动就行”——那我相信,你看到标题时的心情,和我当时一样复杂。

一边是摇摇欲坠的老古董,一边是号称“解放生产力”的 AI 全家桶(Vibecoding、Agent、Copilot)。我天真地以为,把脏活累活扔给 AI,我只要躺平做决策就好。
结果呢?AI 确实很勤快,但它勤快得像个刚毕业的实习生——敢删代码、敢升依赖、敢拆结构,就是不敢问“为什么”。

三周血泪,四次炸服,七个被驳回的 PR 之后,我终于摸到了一条让老项目和 AI 和平共处的路。这篇文章不吹概念,只讲实操——我踩过的坑、定下的规矩、以及最后如何让那个四千行的OrderService体面地活了下来。


Define:一个让所有架构师头皮发麻的场景

故事的开头很标准——Leader 丢给我一个任务:去救火,稳住一个十年老单体项目。

我打开代码,映入眼帘的是:

  • 一个叫OrderService的类,四千多行,最长的那个方法翻三屏找不到结尾。
  • 依赖版本停留在 Spring 4.x,JDK 还是 1.8,没人敢升,因为升一次崩一次。
  • pom.xml里躺着一个被魔改过的底层包,注释写着“某业务特殊需求,改源码”——至于改了哪里,没人说得清。
  • 数据库字段status=2,文档写“已审核”,但线上有个定时任务每天凌晨三点会把它刷成“已删除”——而这套逻辑写在存储过程里,没人敢动。

我问同事:“这段逻辑为什么这么写?”
同事答:“我也不知道,以前就这样,别动就行。”

那一刻我懂了:这不是一个技术问题,这是一个考古问题。而我手上最先进的工具,只有一台电脑和一个刚上线不久的 AI 助手。


Design:我以为的“AI 解放方案”

当时的想法很直接:项目太复杂,人看不过来,那就让 AI 帮我读、帮我写、帮我改。工具链齐全,理论上一周就能出效果。

我设计了一套理想工作流:

  1. OrderService.calcPrice()那个几百行的方法贴给 AI,让它解释业务逻辑。
  2. 让它生成对应的单元测试,把这个方法的行为固化下来。
  3. 再让它帮我重构——把散落的校验逻辑抽成私有方法,把重复的折扣计算统一收口。
  4. 最后,基于改动生成 Mermaid 调用关系图,告诉我哪些地方会受影响。

听起来很完美,对吧?AI 负责干脏活累活,我负责做决策和 Review。
但实际跑起来之后,我才发现——AI 在它看得懂的地方有多聪明,在它看不全的地方就有多鲁莽


Dilemma:Agent 进老项目,等于往雷区扔扫地机器人

AI 确实勤快。但它只看到了我贴给它的那几百行代码,完全看不到全局。于是灾难接二连三:

第一个坑:擅自“优化”依赖,线上炸了半小时
Agent 看到redis.clients:jedis版本号是 2.9.0,贴心地给我升到 4.3.0,理由是“修复了已知漏洞”。但它不知道我们生产环境的 Redis 版本是 4.0,更不知道项目里有十几处用到了JedisPoolConfig的旧 API。一部署,NoSuchMethodError铺满日志,线上直接不可用。

第二个坑:自作聪明删“无用代码”,价格算错
calcPrice()里有一段看起来毫无意义的Thread.sleep(50),Agent 判定为“性能垃圾”,当场删除。但那行代码是三年前为了等主从同步而加的操作——虽然写法不规范,但十年来没人敢动。删除之后,主库刚写入的订单数据在从库查不到,价格全算错,财务第二天追着我骂。

第三个坑:疯狂重复造轮子,代码量膨胀 10%
上午我让 AI 写了个手机号脱敏工具类PhoneMaskUtil。下午让它改另一个模块的用户信息展示,它又写了个UserInfoMaskHelper,功能几乎一模一样。短短一周,项目里多了二十多个工具类,代码量膨胀了近 10%。

第四个坑:修一个 Bug,生出三个新 Bug
我让 AI 修一个空指针异常,它加了个判空,返回空列表。本地测试通过,上线后下游计算平均值直接除以零,又炸了。AI 只管“当下这个方法的返回值不空”,压根不会去扫调用方怎么消费这个返回值。

最崩溃的是第五个坑:修复死循环,变成死循环
我反馈 → AI 改 → 引入新问题 → 我再反馈 → 它再改。同一个类的同一个方法,来来回回提了七个 PR,全是 AI 写的。我每天的工作变成了点“驳回”和“重试”,像个高级测试员,而不是架构师。

那一刻我彻底清醒:让 AI 在老项目里自由奔跑,它不是手术刀,是挖掘机。


Deliver:血泪里总结的四条铁律

被折腾了三周后,我终于摸索出一套能打的方案。核心思想就一句话:

让 AI 当实习生干局部脏活,所有架构决策必须捏在人类手里。

第一条:先画红绿灯,再让 AI 进门
我在项目根目录建了一个.ai-rules.md,每次对话开场第一句就是“先读这个文件”。里面三块内容:

  • 🔴红灯禁区:升级依赖、删方法删字段、删配置文件、改核心公共类、动数据库。AI 敢碰一次,直接驳回。
  • 🟡黄灯确认区:新增工具类、改 Controller 入参出参、改事务行为。AI 可以提方案,但必须我点确认才能合入。
  • 🟢绿灯自由区:方法内部算法优化、if-else 简化、加日志、写注释、生成单元测试。

规则定死之后,AI 的犯错率直线下降,至少它不敢再碰pom.xml了。

第二条:测试先行,没有安全网不准动手术
老项目最大的痛点是“没有测试”。所以我强制要求:改任何代码之前,先用 AI 生成特征测试——让 AI 根据当前方法的行为逆向生成单元测试,跑通之后,这些测试就变成“护城河”。改造完成后,跑一遍测试,全绿才能提 PR。这一步把“改崩了都不知道”的恐慌,彻底掐死在本地。所有测试都用 Mockito 隔离外部依赖,套件能在 30 秒内跑完,开发中随时可以快速验证。

第三条:拆分任务,一次只改 20 行
绝不允许对 AI 说“重构整个订单模块”。只能指定具体的方法和行号范围,例如:“把OrderServiceImpl.createOrder()第 50 到 70 行的参数校验逻辑抽成一个私有方法,保持原有功能不变。”每次改完立即跑测试,立即提交。一个模块拆成四五十个小任务,累是累了点,但安全。

第四条:人类 PR 必过三关
AI 提交的 PR,必须经过三道检查才能合入:

  1. 依赖检查pom.xmlbuild.gradle有变化?直接驳回,理由就一句:“你没权限碰这个。”
  2. 删除检查:原有代码一行不许删,仅允许删除 AI 新增的调试代码。AI 觉得“没用”的代码,我宁可留着也不让它删。
  3. 日志检查:有没有把System.out.println带进生产代码?AI 经常干这事,见一个打回一个。

额外收获:让 AI 反向考古
AI 不适合改老代码,但特别适合读老代码。我把那段神秘的Thread.sleep(50)丢给 AI,让它分析上下文,它还真猜出来了——“疑似等待主从同步”。虽然不敢 100% 确认,但至少给后续排查提供了方向。我还让它给整个订单模块生成了调用关系图,清楚看到calcPrice()被哪些上游依赖,彻底解决了“改一处不知炸哪里”的恐慌。


结尾:AI 是手术刀,还是挖掘机,取决于你怎么用

老项目不是一个可以“一步到位”重构的东西。它是十年里无数个“先上线再说”的妥协累积出来的产物,里面每一行看似愚蠢的代码背后,可能都藏着一段血泪教训。

Vibecoding 和 Agent 给了我们强大的生成能力,但生成能力越强,越需要有边界。我的经验总结成一句话就是:

人指路,AI 干活,测试保底,人把关。

按照这个流程,我那个四千行的OrderService用了一个月拆成了七个类,每个类五百行以内,单元测试覆盖率从 0 提升到了 67%。过程中 AI 辅助生成了初稿,但核心逻辑部分人工重写了约 40%——没有任何一行代码未经 Review 就直接上线。

你问我现在还敢不敢让 AI 改老项目?
敢,但戴好手套、穿好防护服

老项目还能再活十年。只不过这一次,是带着 AI 这把手术刀,体面地活下去。
而那个曾经问“这段逻辑为什么这么写”的我,如今会笑着回答自己:“我不知道没关系,但我知道怎么让 AI 帮我去查、去试、去验证,同时不炸掉整个系统。”

这,才是架构师该干的事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询