AI 辅助代码重构的项目实践——从代码坏味道检测到自动修复建议
一、重构的阻力不在于能力,而在于时间和风险
团队里每个有经验的工程师都知道重构的价值,但进度压力让重构永远排在"下一个迭代"。更困难的是风险问题——一段运行了三年、经过几十次修修补补的模块,谁都不敢轻易动。即使想做,第一步"理解这段代码在做什么"就要花几个小时,然后还要评估"改了会不会影响上下游"。
AI 辅助重构的价值恰好在这两个点上:降低理解成本,提供安全网的信心。LLM 在代码理解上的核心能力在于多层次抽象——从 AST 级别的语法解析到跨文件的调用链分析,模型可以同时处理方法级、类级和模块级三个粒度的信息。通过静态分析工具提取代码坏味道的位置和类型,将坏味道所在方法和上下文代码组织为结构化提示词提交给 LLM,模型可以在数秒内完成人类工程师需要数十分钟的上下文梳理。我在三个项目上做了验证,覆盖了循环复杂度超过 15 的方法、重复率超过 30% 的模块、以及单测覆盖率低于 30% 的核心服务,重构建议的可接受率达到 78%。
在实际使用中,提示词的结构直接影响 LLM 输出的质量。提示词至少包含四个部分:代码坏味道的类型和位置、受影响的方法完整代码、上下游调用关系摘要、以及重构约束(如"不改变公开 API 签名""优先使用策略模式拆分条件分支")。越清晰的约束条件,模型生成的建议越贴近团队编码规范。对于超过模型上下文窗口限制的长方法(500 行以上),采用分块策略——先将方法按语义边界切分为逻辑段落,每个段落独立分析后再由 LLM 做全局整合,效果优于直接截断。
二、重构流水线:检测 → 分析 → 建议 → 校验 → 验证 → 评审
流水线的设计哲学是"建议权归 AI,决策权归人"。LLM 生成的所有重构建议附带结构化解释——为什么要这样重构、替代方案是什么、影响范围评估——最终都需要通过代码评审才能合并。流水线分为六个阶段。
第一阶段:检测与过滤。 通过 SonarQube 和 PMD 扫描坏味道位置和类型。不是所有坏味道都值得交给 LLM——像"变量命名不符合驼峰规则"这种确定性规则能直接解决的问题,无需消耗模型调用成本。过滤条件为:循环复杂度大于 10、方法行数大于 50、嵌套层数大于 3、或重复代码超过 15 行。这样将 LLM 的注意力集中在结构性重构上。
第二阶段:上下文分析与提示词构建。 将过滤后的坏味道信息、受影响方法的完整源码、上下游依赖关系摘要、以及一份团队编码规范摘要,组织为结构化提示词。提示词中声明"仅给出建议,不直接修改代码库",并在末尾添加输出格式模板,要求 LLM 以固定结构返回:问题描述、重构方案、重构后代码、改动说明、测试建议。对于类级别的重构(如拆分上帝类),提示词还需包含类的职责分析、依赖关系图和涉及的调用方列表。
第三阶段:建议生成与安全校验。 LLM 生成的重构代码先经过 SpotBugs 和 FindSecurityBugs 扫描,拦截可能引入的 SQL 注入、硬编码凭据、路径遍历等安全风险。如果安全扫描不通过,将扫描结果作为负反馈追加到提示词中,要求 LLM 重新生成,最多重试三次。三次后仍存在安全问题的,自动转为人工审查。
第四阶段:测试生成与 CI 验证。 LLM 为重构后的代码生成单元测试和边界测试,覆盖正常路径、异常路径和并发竞争场景。在 CI 环境中编译并运行全量测试套件,对比重构前后的测试覆盖率和通过率。如果测试不通过或覆盖率下降超过五个百分点,将失败信息反馈给 LLM 进行修正。
第五阶段:行为一致性检查。 使用线上流量回放工具捕获重构前后的 API 输入输出——包括正常流量和异常流量——逐字段对比结果差异。对外部行为产生变化的变更都会被拦截。
第六阶段:人工评审与合并。 所有通过 CI 验证的重构以 Pull Request 形式提交,附带 LLM 生成的改动说明和影响评估,由团队工程师最终评审后合并。
三、重构建议的 Java 示例:从庞大的 Service 方法拆分
下面展示一个实际案例。原代码是一个 200 行的 processRefund 方法,混合了参数校验、库存扣减、金额计算和退款调用。SonarQube 将其标记为"方法行数过长"和"圈复杂度过高"。
// 重构前:203 行方法,圈复杂度 28
// SonarQube 标记: Code Smell – MethodTooLong, CyclomaticComplexity
public RefundResult processRefund(RefundRequest request) {
// 校验逻辑 40 行
// 金额计算 30 行
// 支付网关调用 50 行
// 状态同步 40 行
// 日志与监控 20 行
// 异常处理 23 行
}
将上述代码连同调用链信息和团队编码规范提交给 LLM,提示词明确要求"使用策略模式拆分退款类型差异""保持公开 API 兼容""为每个拆分出的方法生成独立单元测试"。LLM 返回的分析指出这是一个典型的"长方法"和"职责过度集中"的坏味道,并基于单一职责原则给出拆分方案。
// AI 建议重构后:四个独立组件,单一职责
public class RefundProcessor {
private final RefundValidator validator;
private final InventoryService inventoryService;
private final AmountCalculator calculator;
private final RefundGateway gateway;
private final StatusUpdater statusUpdater;
public RefundResult process(RefundRequest request) {
// 1. 校验阶段:委托给独立校验器,保持原有校验规则不变
RefundContext ctx = validator.validate(request);
if (!ctx.isValid()) {
return RefundResult.invalid(ctx.errors());
}
// 2. 恢复库存:异常时记录告警,通过异步补偿任务修复
try {
inventoryService.restore(ctx.getOrderItems());
} catch (InventoryException e) {
// 库存恢复失败时记录异常但继续退款流程
// 后续由定时补偿任务修复库存数据一致性
alarmService.sendInventoryAlarm(ctx.getOrderId(), e.getMessage());
}
// 3. 计算退款金额:独立计算组件处理分账与舍入策略
RefundAmount amount = calculator.calculate(
ctx.getOrderId(), request.getRefundItems());
// 4. 调用退款网关:隔离外部依赖,增加超时熔断保护
GatewayResult gatewayResult;
try {
gatewayResult = gateway.refund(
ctx.getOrderId(),
amount.getTotalCents(),
request.getReason());
} catch (GatewayTimeoutException e) {
// 网关超时时保留重试信息,不直接返回失败
return RefundResult.retryable(ctx.getOrderId(), amount.getTotalCents());
} catch (GatewayException e) {
return RefundResult.failure(ctx.getOrderId(), e.getMessage());
}
// 5. 更新状态:独立状态机管理退款生命周期
statusUpdater.transition(
ctx.getOrderId(), RefundStatus.from(gatewayResult));
return RefundResult.success(ctx.getOrderId(), amount.getTotalCents());
}
}
LLM 还自动生成了对应的单元测试,覆盖了正常路径、库存异常路径和网关超时路径。测试覆盖率从原来的 22% 提升到 85%。人工评审阶段只调整了两处:库存恢复异常时的补偿策略从"直接重试"改为"记录异步补偿任务";金额计算时增加了四舍五入策略的显式声明。LLM 生成的重构解释篇幅约为改动代码量的两倍,详细说明了为什么选择策略模式而非工厂模式、取舍的依据以及影响范围。
四、安全机制:LLM 生成代码的三层防护
LLM 生成的代码有三类典型风险:幻觉注入(模型凭空调用不存在的 API 或产生逻辑错误)、安全漏洞(引入 SQL 拼接或未做输入校验导致注入风险)、性能退化(拆分后的调用链路引入了不必要的序列化开销或 N+1 查询)。流水线中必须嵌入多层安全机制来逐个拦截。
第一层:静态安全扫描。 对 LLM 生成的代码运行 SpotBugs 和 FindSecurityBugs,检测 SQL 注入、XSS、路径遍历和硬编码密钥。若发现安全漏洞,将扫描结果作为负反馈追加到提示词中,要求 LLM 重新生成。安全扫描与 LLM 生成的循环最多执行三次,三次后仍存在安全问题的变更自动转为人工审查,不允许自动合并。
第二层:行为一致性检查。 将生成的代码部署到测试环境,使用线上流量回放工具捕获重构前后的 API 输入输出——包括正常流量和异常流量——逐字段对比结果差异。对外部行为产生任何变化的变更都会被拦截。例如重构后异常码从 REFUND_FAILED 变为 GATEWAY_TIMEOUT,虽然语义更精确,但会破坏调用方的异常处理逻辑,这种变更需要人工评估后才允许通过。
第三层:性能回归检测。 对涉及热点路径的修改,在压测环境跑基线对比,关注 P99 延迟、CPU 使用率和内存占用的变化。如果 P99 延迟增长超过 15% 或内存占用增加超过 20%,自动打回并附带性能分析报告。
生产环境上还控制了 LLM 的介入范围。不允许 LLM 直接修改涉及数据库 Schema 变更、缓存策略调整和分布式事务边界的代码。这些高风险变更只在分析阶段给出报告和建议,具体修改由工程师手动完成。
五、总结
AI 辅助代码重构的实践表明,LLM 在理解代码上下文和生成结构化重构建议方面有较大优势,但安全机制不能缺失。重构的决策权始终属于工程师,AI 是建议助手而非自动提交者。通过"检测→分析→建议→校验→验证→评审"的六阶段流水线,在保持质量的前提下将重构效率提升到手动方式的 2.5 到 3 倍。关键经验有三条:提示词结构决定输出质量,约束越精确效果越好;安全扫描与 LLM 的负反馈循环是拦截幻觉的有效手段;高风险代码变更始终由人做最终决策。对于长方法超过模型上下文窗口的场景,分块策略的表现优于直接截断,但有引入跨块一致性问题的新风险,需要在提示词层面显式控制。





