遗留系统代码重构指南:如何用AI大模型快速梳理复杂老代码并完成重构

接入与开发

给维护老系统的工程师一套 AI 辅助重构流程:怎么分块喂老代码、怎么让模型讲清依赖、怎么控制改错风险,每步都有验收判据。

老项目最难受的不是看不懂,是不敢动:一个函数牵出十几个调用方,改完自己都不敢提交。这篇不给「AI 一键重构」的幻想,而是把梳理、切片、验证、回滚拆成可执行步骤,告诉你每一步模型能帮到哪、哪一步必须人来拍板,以及什么情况下这套流程不适用。

老项目最难受的不是看不懂,是不敢动。一个函数牵出十几个调用方,改一行心里打鼓,改完自己都不敢提交。这篇给维护老系统的工程师一套能落地的 AI 辅助重构流程:怎么分块喂老代码、怎么让模型讲清依赖、怎么控制改错风险,每一步都配验收判据。

先说清楚这篇不承诺什么。没有「一键重构」这回事,模型在这条链路上只做三件事:解释代码、找依赖、生成候选实现。拆解范围、判断行为是否等价、决定提交还是回滚,都是人来拍板。下面按梳理、切片、验证、回滚的顺序拆,每一步都告诉你模型能帮到哪、哪一步必须自己上。

先搞清楚:哪些老代码适合交给 AI,哪些别碰

不是所有老代码都值得进入这套流程。判断的第一道门槛很朴素:你能否为这段代码写出一条可重复执行的验证命令——能自动跑、能对比前后输出。写得出来,说明它的输入输出边界是清楚的,AI 参与重构才有意义;写不出来,先别重构。

代码特征能不能交给 AI原因
输入输出明确、可单独跑起来的函数或模块可以主导模型看得全上下文,验证也简单
强依赖运行时环境、靠全局状态和时序耦合只读不写模型看不全上下文,容易编出不存在的行为
涉及资金、权限、合规、并发安全只用来读懂和写注释改动的正确性靠推理保证不了,必须人工评审
没有版本控制、没有测试、没有可回放样本先别碰重构出问题不知道退到哪,等于蒙眼走钢丝

第一步不是改代码,是把地图画出来

很多人的第一反应是让模型直接改写。正确做法是这一轮只做只读的事:让模型解释模块职责、列出对外暴露的接口、标注可疑的隐式依赖——全局变量、单例、静态缓存、写在类初始化里的副作用。产出物是一份模块地图加一份待确认清单,不是任何一行代码改动。

  1. 让模型讲模块职责贴入模块代码,要求它用一段话说清这个模块对外提供什么能力、对内依赖什么。讲不圆的地方,通常就是你也没搞清楚的地方。
  2. 列出对外接口要求模型输出公开函数和字段的清单,每条注明被谁调用。它会漏,但比人工翻快很多。
  3. 标注隐式依赖专门问全局变量、单例、静态缓存、环境变量、配置文件这几类。老代码翻车大多栽在这。
  4. 人工核对猜的部分模型给的每条依赖都要求指出代码位置。指不出位置的当幻觉处理,重点标记,后面验证时优先覆盖。

这份地图的价值不在于多准确,而在于把「你不知道自己不知道」的部分暴露出来。模型猜错的地方,往往正是团队里只有一两个人清楚的历史包袱,趁这个机会把它们问清楚写下来。

怎么把几万行老代码切给模型看

按文件切是最省事也最容易出错的做法。老代码最常见形态就是一个文件里塞了三个模块、互相引用还有循环。切片要按调用边界切,不按文件切。一个文件里职责混杂的,先按职责拆开再分别喂。

  • 一次只处理一个可独立验证的单元,别贪多
  • 上下文里固定放三样:目标模块、它的直接调用方、相关数据结构的定义
  • 调用链太长时先让模型做摘要压缩,把压缩结果而不是原始代码放进上下文
  • 注意上下文预算,硬塞的结果是关键信息被截断,模型拿半截代码给你编一个完整答案
  • 切片完成后回看一下:每个单元都能单独写出一条验证命令吗,不能就切错了

关于上下文预算和压缩策略的具体做法,站内已经有过专门讨论,这里不重复,只强调一句:宁可多切几刀,也不要把一个说不清的巨型模块整段塞进去。

让模型干最擅长的事:找依赖和副作用

找依赖和副作用是模型在这条链路上性价比最高的环节,因为它本质是模式匹配加梳理,不需要模型理解业务意图。但提问方式要固定,否则每次得到的答案格式都不一样,没法横向比对。

读状态
这段代码读了哪些外部状态:全局变量、配置、数据库、缓存、环境变量
写状态
这段代码写了哪些外部状态:数据库写操作、文件系统、缓存失效、消息投递
异常行为
出错时会发生什么:异常吞掉、日志级别、是否回滚、是否有重试

三类问题分开问,得到的清单分开记。特别要盯四类高危位置:数据库写操作、文件系统、网络调用、时间与时区相关逻辑。前三类涉及外部世界,改动后的差异很难靠读代码发现;第四类是老系统里最隐蔽的坑,跨时区、夏令时、本地时间与 UTC 混用的逻辑,模型经常答得头头是道但细节全错。

高危位置典型症状验证手段
数据库写操作查询条数变了但结果没变回放样本时统计 SQL 条数
文件系统路径拼接、临时文件残留改动前后比对目录快照
网络调用超时、重试、幂等性录制响应做桩,禁止打真实下游
时间时区跨时区结果漂移、夏令时错位固定时钟做注入,覆盖边界日期

小步改:一轮只做一件事的循环

一轮只干一类改动:这一轮只改名,下一轮只抽函数,再下一轮才换实现。混在一起改,出了问题说不清是哪一步引入的。至于测试怎么写、怎么补,属于另一篇文章的范畴,这里只管节奏:先固化验证手段,再改,再对比,再提交。

  1. 固化输入输出用真实流量录制或手工构造样本,先跑老代码,把输入和输出都存下来,当作这一轮的对照基线。
  2. 明确本轮改动类型本轮只做一类改动,写在提交信息开头。改动类型混了就拆成两轮。
  3. 让模型产出候选实现把目标模块、调用方、数据结构定义一起给它,要求它只改指定部分,别顺手优化别处。
  4. 对比并记录对比不只比结果,还比调用次数、查询条数、日志行数。行为等价但副作用翻倍,同样是回归。
  5. 提交或回滚对比通过就提交,把验证方式和未覆盖范围写进提交信息;不通过就走下一节的回滚判据。

这个循环跑起来之后,单轮改动的体量应该小到你敢在十分钟内手工复核完。如果某一轮你发现自己根本看不懂模型改了什么,说明上一轮切片切大了,退回去重新切。

改完怎么验收:一张对照清单

验收不是「跑一遍没问题」,而是四项比对里至少三项留下可重复的证据。证据的意思是:换个人照着记录能复现出同样的对比结果,而不是「我本地试过了」。

比对项做法证据形式
输入输出比对固定样本跑新旧代码,逐条比对输出差异报告,零差异或已解释的差异
边界值比对空值、极值、超长输入、非法输入各跑一遍边界用例清单及结果
异常路径比对构造下游失败、超时、权限不足等场景异常场景清单及结果
性能量级比对关注数量级而非精确值,避免噪声误判量级对照结论

样本来源上,用老系统真实流量录制出来的回放样本,比手工造用例可靠得多,因为真实流量会带上你没想过的畸形输入。样本量不用大,但必须覆盖主流程和上面那张表里的四类高危位置。任何一项无法解释的差异,都当作回归处理。

验收记录要落到提交信息或变更单里,写清楚本次改动验证了什么、用什么方式验证的、哪些范围没覆盖。这不是形式主义,下一个人接手时能省掉重来一遍的成本。

什么时候该回滚,什么时候该放弃重构

回滚的判据要提前定好,不能等到出问题再临时商量,那时候情绪会盖过判断。三条触发线,任意一条满足就回滚:出现无法解释的行为差异;验证耗时已经超过改动本身的价值;同一处反复改了三轮还没稳定下来。

  • 出现无法解释的行为差异——不是「可能没关系」,是解释不了,就回滚
  • 验证耗时超过改动本身——说明验证手段没建好,先补工具再动代码
  • 同一处反复改三轮还不稳——通常意味着切片或地图阶段出了问题,退回去重做
  • 重构范围在评估后持续扩大——前期地图没画准,先停下来补地图,不要硬推
  • 回滚后别急着再试同一刀,先问清上一轮到底漏了什么信息

有一些项目在这套流程下根本不该启动:没有测试、没有版本控制、没有可回放样本。这三样是前置条件,缺哪样就先补哪样,补完再谈 AI 辅助重构。硬上不是勇敢,是给自己挖坑。

模型和工具怎么选,以及成本怎么估

读懂类任务,比如解释模块职责、列接口清单,用便宜档模型就够,输出内容以梳理为主,不需要太强的推理。复杂推理和跨文件改动,比如换实现、重构调用链,才需要高配档。按任务切模型比笼统比较模型更实际,具体哪档模型什么价,到站内价格页核对当时的数字,别拿别人截图里的价格做预算。

成本估算可以按输入构成来算:一个可改动单元的分析输入,大致包含模块代码、直接调用方、相关数据结构定义三部分,再乘上你可能要迭代的轮数。这个构成基本稳定,单价变动直接去价格页看当时的数字就行。想省 token,优先在切片和摘要压缩上做功夫,而不是砍掉调用方和数据结构定义——省下的那点钱,换来的是模型看不见全局然后瞎编。

  • 先扫一遍老代码里的硬编码凭据、内网地址、密钥,喂模型之前处理掉
  • 日志、报错信息、样本数据导出前做脱敏,脱敏清单按站内安全类文章执行
  • 区分只读任务和写入任务:只读任务可以放宽,会改代码的任务控制在受控环境里
  • 把每轮改动的输入构成和轮数记下来,几次之后你就有自己的成本基线了
下一步如果你正准备评估这套流程要用哪档模型、大概什么成本,先去站内价格页和可信度检测页核对当时的数字与检测口径,再拿本文的切片和验收清单开一轮小范围试点。

常见问题

整个老项目直接丢给 AI 让它重构,行不行?

基本不行。上下文塞不下、模型对运行时行为无从判断,产出多半是不能编译或行为悄悄变了的代码。可行的做法是按调用边界切片,一次只处理一个能独立验证的单元,改完验证再进下一片。

没有单元测试的老系统,能不能先靠 AI 补测试再重构?

可以,但顺序是先做特征测试(记录现有行为)再谈重构,而不是先写理想测试。特征测试不判断对错,只锁住当前行为,这样重构后行为变了能立刻发现。测试怎么写属于另一篇文章的范围。

模型说这段代码有某个依赖,我怎么判断是真是假?

要求它给出文件与行号,然后自己去点开核对,指不出位置的直接当幻觉。另外看这条依赖是否符合你对系统的既有认知,冲突时以代码为准。反复出现编造依赖,说明喂进去的上下文不完整。

重构到一半发现范围比想象中大得多,怎么办?

停下来,不要扩大战线。先把已改完且验证通过的部分单独提交并锁定,然后重新评估剩余部分的地图,必要时把任务拆成几个独立变更分批推进。范围失控通常是前期依赖分析没做完。

这套流程在什么情况下不适用?

没有版本控制、没有可回放样本、没有能重复执行的验证手段时都不适用,先补这三样。另外涉及强时序、强并发或依赖特定硬件行为的代码,模型判断力有限,只能用于读懂,改动仍需人工主导。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。