ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI Agent实战:3周重构10万行“祖传代码”的方法与经验

AI Agent实战:3周重构10万行“祖传代码”的方法与经验 接手这套“祖传代码”的时候我心里其实挺没底的。一个跑了快十年的老系统10万行Java代码混合着XML配置、存储过程还有一堆没人能说清逻辑的历史债务。原来团队给这套系统取了个外号叫“老黄牛”因为谁也不敢动它——改个字段名都可能触发连锁故障。那段时间我一直在想用AI写代码已经不是什么新鲜事了真正让人头疼的是怎么让AI接手这种“大工程”。后来我试着把AI从“写代码的工具”升级成“能自己规划、执行、验证的Agent”用了一套人机协作的方式花了三周左右的时间把这10万行代码做了系统性重构测试通过率从62%拉到了97%线上故障率在一个月内降了40%。这篇文章不是讲PPT是把我整个过程中踩过的坑、试错的方案、最终跑通的流程完完整整地拆给你们看希望对正在跟“老天下第一”代码搏斗的人有点参考价值。先交代一下背景。这套系统是金融行业的对账平台核心业务是对接不同渠道的交易流水并做差错处理。代码是2015年左右起的项目用的技术栈在当时算主流——Spring MVC MyBatis Oracle存储过程前端是老的JSP加一点jQuery。说实话那个年代这种架构没什么问题但跑到现在痛点就很明确了一是业务逻辑大量堆在Controller层和存储过程里想加一个功能要动五六个文件二是没有任何自动化测试当年都是靠“人肉点验”上线三是数据库表结构设计存在大量冗余join超过五张表的SQL随处可见。这些问题的核心就是“不敢改”而“不敢改”又导致没人去优化形成恶性循环。我一开始也考虑过直接推倒重写但评估下来工作量太大且业务细节早已散落在历史提交和口头传承里风险完全不可控。所以最后结论是走结构化重构用Agent来做大量的重复性迁移和验证工作我负责设计边界和兜底。真正开始动手之前我先做了两件事一件是把代码库的现状量化摸清楚另一件是定义什么叫“重构完成”。代码量化这块我写了一些分析脚本统计循环依赖、重复代码块、超长方法数和存储过程的调用关系。一圈跑下来数据很有意思整套10万行代码里Controller层平均每层有1200行最夸张的类有2600行存储过程有47个其中11个超过500行重复代码片段占比大约18%。这些数据帮我确认了重构的几个重点区域也让我能向其他人解释为什么非得动这个“老黄牛”不可。至于“重构完成”的定义我定成三个可量化的标准第一所有业务逻辑从Controller层和存储过程中迁出统一收口到Service层第二识别出来的重复代码块消除80%以上第三核心交易链路的自动化测试覆盖率从0拉到70%以上编译、单测、接口测试全绿。这两步做完之后我心里其实已经有一定把握了。重构的本质不是“把代码重写一遍”而是“在保持外部行为不变的前提下调整内部结构”基于这个逻辑AI的优势其实非常大它能在短时间内读完大量文件并理解其中重复出现的模式而人类做这件事容易疲劳并且前后标准不一致。但AI写代码的问题是它只能处理“局部任务”让它改一个方法没问题让它跨二十个文件、协调上下游改动、跑完测试再自我纠错这就超出了普通补全工具的能力范围。所以我当时的核心思路很明确把AI从“编码器”变成一个“带规划能力的执行者”也就是Agent。Agent和内AI写代码的最大区别在于它具备一个闭环感知环境、规划动作、执行修改、观察结果、调整策略。正是这个闭环让它能处理重构这种多步骤、多文件、有依赖关系的复杂任务。章节内容再往深一层说。Agent的架构我没有做得特别复杂按“规划器—执行器—验证器”三个组件来设计的配合一个围绕Git和CI构建的沙箱环境。规划器负责读取我拆好的“任务卡”根据代码库分析结果输出改动方案执行器负责具体到文件级修改生成diff补丁验证器负责把改动应用后进行编译、跑测试、检查静态代码指标然后把结果反馈给规划器决定是继续还是回退。整套流程用一个Python编写的编排脚本调度核心就是控制Agent不要“瞎跑”每一个环节都设置了明确的退出条件比如编译不过就必须回退到上一版再重新生成测试覆盖率低于阈值就自动打回。这套机制跑起来之后效果比预期好因为Agent一开始也很容易出现那种“改了A就忘了B”的情况但有了自动验证和回退闭环之后大部分低级错误在Agent内部就被消化掉了不会流到我面前。做完基础架构设计接下来要考虑的就是怎么给Agent“派活”。一开始我踩了一个很典型的坑——试图把整个项目一次性丢给Agent让它自主去重构。结果当然很惨上下文窗口根本装不下这么多文件Agent到后面甚至开始“编造”接口名和类名我收到了一堆看起来合理但根本编译不过的代码。那之后我想明白了一点大型重构要让Agent做但必须把任务拆到它可以理解和执行的颗粒度。我的做法是先把系统按照业务域拆成12个模块然后每个模块再拆成若干“重构单元”最小的单元大约覆盖三到八个文件保证Agent能在上下文窗口内读完所有相关代码并给出完整方案。拆完之后每个任务卡上写明这个单元的边界、涉及文件列表、风险点、以及必须保持不变的对外接口有哪些然后才交给Agent。这里分享一个关键经验任务卡的写法直接影响Agent输出质量。第一次我写任务卡写得比较粗糙就一句话“把这个Controller的业务逻辑搬走”Agent返回的方案五花八门有的改了接口签名有的把方法直接删了却忘了处理调用方。后来我参考了给人类外包程序员写需求的做法把任务卡改成包含背景、范围、规则、验证标准四个部分每个部分尽量具体。比如规则里明确“不允许修改Controller对外暴露的URL路径”“不允许改变DTO字段名称”“数据库访问统一迁移到新Mapper接口”Agent的输出一下子就稳了很多。我实测下来同一个Agent模型在“模糊任务”和“精细任务”两种输入下的可用产出差距是巨大的前者有三成左右的代码需要返工后者返工率压到了10%以内。再说说具体实操的时候怎么跑的。整个重构过程我分成了四轮来做每一轮都聚焦一种模式而不是按模块顺序平推。这样做的好处是Agent可以在同类任务上积累经验后面的产出质量会越来越高。第一轮做的是“Controller瘦身”把所有业务逻辑从Controller层迁移到Service层迁移过程中生成新的Service接口和实现类第二轮是“存储过程替换”把47个存储过程里的核心逻辑拆解出来改写成Java代码并落到新DAO层第三轮是“重复代码消除”基于静态分析结果把重复片段提取成公共工具方法或基类第四轮是“依赖清理”把那些已经没人调用的死代码、冗余配置和无效依赖移除掉。每一轮结束之后都会跑一次完整的编译和测试确保当前状态是可部署的然后再进入下一轮。每一轮在具体执行的时候我都让Agent遵循“先分析、再生成、后自检”的工作流。以第一轮的Controller瘦身为例子说明。第一步Agent会读取任务卡里指定的Controller和Service相关文件分析出哪些方法是纯业务逻辑、哪些是参数组装、哪些是外部依赖调用然后输出一个迁移清单包括方法明细、目标类、以及需要新建的依赖接口。这个清单会先给我用人工过一遍确认方向没问题后才会进入下一步。第二步Agent开始生成目标代码但并不是一次性地把大段代码写出来而是按照文件粒度或者说方法粒度生成diff补丁每个补丁都配有commit message。第三步Agent会运行一个我预先写好的检查脚本对改动前后的方法签名进行比对、找出所有调用方、确认URL映射没有变化全部通过后才提交到特性分支。每轮跑下来大约会产生40到60个commit虽然数量多但每个commit都小而清晰出问题时回滚也非常容易。这里要特别说一下Agent生成代码时的提示词设计。我并没有用那种“帮我重构这个系统”的玄学提示词而是把提示词当成一套完整的操作手册来写。每次下发任务我先给Agent几条“黄金示例”——即三组改动前和改动后的代码对照让它明确理解我要求的迁移模式。然后给一份“负面清单”列出绝对不允许做的事比如不许给DTO加新字段、不许改动公共方法的参数列表、不许在Service层直接执行SQL。最后再给“输出要求”比如每一个迁移方法必须保留原始注释中的业务背景信息、必须补充单测用例的骨架。这些提示词看起来朴素但其实是Agent生产能力的关键因为大模型对“示例”的理解能力远强于对“抽象描述”的理解能力给三组正反例比写一千字说明都管用。存储过程替换那一轮是最让我紧张的因为这类逻辑涉及的数据库行为复杂度高Agent写Java代码替换时非常容易漏掉事务边界和并发控制。比如某个存储过程里有一段先查后写的逻辑原实现是依赖Oracle的隐式锁来保证数据一致的但Agent在改写时很可能就简单翻译成“查出来改一下写回去”根本没有考虑并发场景。这种问题靠编译和测试都很难暴露必须靠人工来review。所以我当时定了一条规则涉及事务、锁、批量数据处理三类场景的存储过程替换Agent生成的代码不直接应用而是先输出给资深开发人工评审确认无误后再合入。这确实降低了自动化程度但换来了安全边际我觉得在做金融系统重构时这个取舍是值得的。事实上最后统计下来47个存储过程里有9个因为涉及复杂事务和并发控制改由人工主导重写剩下38个完全由Agent生成并经测试验证。再有一个很有价值的判断——Agent重构过程中测试策略不是“事后补”而是“事前建”。当时系统里几乎没有自动化测试如果直接让Agent大规模改代码一旦出错根本不知道从哪里查起。因此我在重构开始的前两天做了一个什么功能开发都不做的“测试基座”把核心交易链路上20多条关键场景用接口测试和集成测试的形式固化下来覆盖了登录鉴权、渠道接入、交易对账、差错处理这几条主链路。这20多条用例就是整个重构期间的“安全网”。Agent每改动一批代码CI就跑这一套测试再加上编译检查任何行为变化都会被第一时间扑到。事实证明这套机制救了无数次最大的一次是Agent在重构对账逻辑时把时间窗口的计算方式改了测试直接标红我们才发现它在“优化”的过程中改变了业务语义——如果不是测试拦住了上线之后就会出现批量对账误差后果很严重。不过即便有这些准备实际操作中我还是遇到了不少问题。常见的几个我总结成了一个小册子给团队的其他人也做了一份。第一个高频问题就是Agent“修复式误导”。这个问题主要出现在Agent发现编译错误后自行决定修改其他相关文件比如某方法参数被改动导致调用方编译失败Agent为了“修复”调用方强行在调用前加了一个类型转换或者塞入一个默认值表面上看编译通过了但实际语义已经悄悄改变。这种问题很难通过规则描述来完全禁止因为Agent会觉得它是在帮忙。我的应对思路是给Agent设置“建议模式”和“执行模式”的切换当改动范围超出任务卡列出的白名单文件时Agent只输出建议清单不直接生成修改代码由我来决定要不要放行。相当于给Agent加了一道“刹车”把风险控制在可控范围内。第二个问题是长文件、长上下文的“记忆衰减”。当一批任务涉及的文件比较多Agent的注意力会从中间开始漂移到后面容易出现“前后矛盾”的情况比如前面说某个接口要废弃后面又在用它。这个问题我跟它斗争了很久后来找到了比较有效的方式让Agent在处理过程中持续维护一个“变更日志”每完成一步改动就在日志中追加一条包括文件、方法、改动类型、状态这些字段。这个日志不仅给人类用来追溯也会回传给Agent自己成为后续决策的参考。这招本质上是用外部记忆来弥补大模型上下文窗口的局限实测下来效果很明显前后矛盾和重复改动的问题大幅减少。第三个问题更隐蔽——测试“假绿”。重构期间有一段时间测试通过率看着挺高但我总觉得不对劲。后来排查发现Agent生成的测试里存在“断言失效”的情况也就是测试方法本身写得有问题无论代码行为变没变它都会通过。比如断言里写的是assertNotNull(response)压根没有对返回结果的具体字段做校验这种测试看起来绿了实际等于没有。这类问题是AI生成测试的通病因为它模仿了已有测试的浅层写法。我的对策是把测试模板提前固化定义好几类必须包含的断言模板比如状态码、关键字段、异常场景、边界值然后让Agent只能在这个模板的框架内补充场景不能自由发挥断言逻辑。后来我又加了一道“变异测试”的思路故意在业务代码里埋几个小错误看测试能不能跑红跑不红就说明测试有效性不足需要回炉。还有一个组织协作层面的问题——多个Agent同时开工时容易在公共文件上互相覆盖。后期为了提速我试过多Agent并行跑不同模块但很快发现两个Agent同时改了公共工具类或者共用Mapper时Git冲突就会变得极其麻烦而且冲突解决时极易丢失某一方的改动语义。后来我采用了“文件锁”方案在编排层为公共文件设置状态同一时间内只允许一个Agent持有该文件的修改权其他Agent如果在任务里需要动这些文件就进入等待队列。这其实就是分布式系统设计里的乐观锁思路只不过应用在Agent协作场景上。当然这个方案牺牲了一部分并行度但换来的是冲突问题基本归零团队的代码评审压力也小了很多。抽检和验收环节也跟大家拆一下。我自己对整个重构工作会做三层抽检第一层是“AI灰盒”抽检也就是让Agent自己扮演一个“代码评审员”对另一路Agent的产出做交叉检查——检查逻辑一致性、接口完整性、异常处理、边界条件等等把可疑点标注出来我再来复核。这个做法利用了不同模型或不同提示词下Agent关注点不同的特性往往能看出一些我自己遗漏的盲区。第二层是“核心路径人工review”对涉及金额计算、状态流转、批次处理这几类高敏逻辑我会逐行过代码亲自跑一遍本地example不让Agent代劳。第三层是“上线前全量回归”这个不用多说只是我们额外加了线上灰度观察期用来确认静态逻辑到了真实环境也是稳定可靠的。这整个流程走下来我个人最大的感受是——用Agent重构不是一个“按一下按钮就完成”的魔法过程而是一套工程管理方法。Agent是执行层真正决定成败的反而是重构之前的拆解、规则设定、任务卡编写以及重构过程中对边界的把控和对风险的持续监测。原本“10万行祖传代码”这个量级让我心里发虚总觉得靠人力一两年都难彻底扭过来但走了Agent这条路之后三周就把核心部分翻完了。当然也不能神话Agent它做得好是因为我把它的活动范围、输入输出格式、验证反馈机制全部约束住了它是在一条清晰轨道上做高速运行而不是真的在独立“思考”。后面我又把这套方法复制到了另一个老项目的接口现代化改造上流程几乎是直接复用分析现状、拆模块、写任务卡、定测试基座、Agent生成、人工兜底。虽然每个项目的具体技术栈不同但大的方法论是完全通用的。如果你手里也有一套饱受诟病的“祖传代码”我的建议是先别急着上Agent把你的边界条件想清楚把安全网搭起来再去考虑怎么让AI帮你动手。工具只是放大器你的判断和组织能力才是重构项目真正的地基。
返回列表