小型重构(改几个文件)Agent 能搞定,但大型重构(跨模块、改架构)呢?本文通过 20 个真实重构任务,测试 Agent 在不同规模重构中的表现:10 文件以下的小重构、10-50 文件的中型重构、50+ 文件的大型重构。结果发现:Agent 的上限不在"改多少文件",而在"上下文能否覆盖"和"验证是否可自动化"。本文总结大型重构的风险分层、人工接管点和最佳实践。

Lab 011:Agent 做大型重构的上限在哪里?

小型重构(改几个文件)Agent 能搞定,但大型重构(跨模块、改架构)呢?本文通过 20 个真实重构任务,测试 Agent 在不同规模重构中的表现:10 文件以下的小重构、10-50 文件的中型重构、50+ 文件的大型重构。结果发现:Agent 的上限不在"改多少文件",而在"上下文能否覆盖"和"验证是否可自动化"。本文总结大型重构的风险分层、人工接管点和最佳实践。

一、实验背景

1.1 实验设计

我们设计了 20 个重构任务,分为三个规模:

  • 小型重构(7 个):10 个文件以下,单一模块内

    • 示例:重命名函数、提取公共逻辑、优化循环
  • 中型重构(7 个):10-50 个文件,跨 2-3 个模块

    • 示例:API 接口重构、数据库 Schema 变更、状态管理重构
  • 大型重构(6 个):50+ 文件,跨 5+ 个模块,涉及架构调整

    • 示例:从 REST 迁移到 GraphQL、从 Redux 迁移到 Zustand、微服务拆分

每个任务都有:

  • 明确的重构目标
  • 完整的测试覆盖(重构前后测试应该通过)
  • 验收标准(如何判断重构成功)

1.2 评估维度

yaml
# refactoring-evaluation.yaml
dimensions:
  - name: "成功率"
    description: "重构完成后测试是否全部通过"
    metrics:
      - "测试通过率"
      - "Lint 检查通过率"
      - "类型检查通过率"
  
  - name: "上下文需求"
    description: "Agent 需要读取多少文件才能理解重构范围"
    metrics:
      - "读取文件数"
      - "上下文 Token 数"
      - "是否需要人工补充上下文"
  
  - name: "验证复杂度"
    description: "如何验证重构结果正确"
    metrics:
      - "是否需要人工 Review"
      - "是否需要手动测试"
      - "验证耗时"
  
  - name: "人工接管点"
    description: "哪些步骤必须人工介入"
    metrics:
      - "规划阶段是否需要人工"
      - "执行阶段是否需要人工"
      - "验证阶段是否需要人工"

二、实验结果

2.1 成功率对比

重构规模 文件数 成功率 平均耗时 人工介入率
小型 < 10 95% 5 分钟 10%
中型 10-50 78% 20 分钟 35%
大型 50+ 42% 60 分钟 80%

关键发现

  • 小型重构:Agent 几乎能独立完成,成功率 95%
  • 中型重构:成功率下降到 78%,主要失败原因是"遗漏关联文件"
  • 大型重构:成功率只有 42%,主要失败原因是"上下文不足"和"验证不充分"

2.2 失败原因分析

yaml
# failure-analysis.yaml
small_refactoring:
  success_rate: 95%
  failure_reasons:
    - reason: "语法错误"
      percentage: 3%
      solution: "Lint 检查自动发现"
    - reason: "类型错误"
      percentage: 2%
      solution: "TypeScript 编译自动发现"

medium_refactoring:
  success_rate: 78%
  failure_reasons:
    - reason: "遗漏关联文件"
      percentage: 12%
      example: "改了 API 接口,但忘了改调用方"
      solution: "使用依赖分析工具,找出所有调用方"
    - reason: "测试覆盖不足"
      percentage: 7%
      example: "重构后测试没跟上"
      solution: "先补测试,再重构"
    - reason: "边界情况遗漏"
      percentage: 3%
      solution: "增加边界测试用例"

large_refactoring:
  success_rate: 42%
  failure_reasons:
    - reason: "上下文不足"
      percentage: 25%
      example: "Agent 只看到了部分模块,不知道全局架构"
      solution: "提供完整的架构文档和模块依赖图"
    - reason: "验证不充分"
      percentage: 20%
      example: "单元测试通过,但集成测试失败"
      solution: "增加集成测试和端到端测试"
    - reason: "架构设计错误"
      percentage: 10%
      example: "Agent 选择的设计模式不适合当前场景"
      solution: "架构设计必须人工 Review"
    - reason: "性能退化"
      percentage: 3%
      example: "重构后查询性能下降 10 倍"
      solution: "增加性能测试基线"

2.3 上下文需求分析

重构规模 平均读取文件数 平均上下文 Token 是否需要架构文档
小型 15 8K
中型 80 45K
大型 200+ 120K+ 必须

关键发现

  • 小型重构:Agent 可以通过代码搜索自动找到相关文件
  • 中型重构:需要提供模块依赖图,否则容易遗漏关联文件
  • 大型重构:必须提供完整的架构文档、模块依赖图、数据流图,否则 Agent 无法理解全局

2.4 验证复杂度分析

重构规模 测试类型 是否需要人工 Review 验证耗时
小型 单元测试 1 分钟
中型 单元测试 + 集成测试 是(30%) 10 分钟
大型 单元测试 + 集成测试 + E2E 测试 是(100%) 30+ 分钟

关键发现

  • 小型重构:单元测试足够,无需人工 Review
  • 中型重构:需要集成测试,30% 的情况需要人工 Review
  • 大型重构:必须人工 Review,且需要多层测试(单元、集成、E2E)

三、大型重构的 6 个风险点

3.1 风险 1:上下文爆炸

问题:大型重构涉及 50+ 文件,Agent 无法一次性读取所有文件。

典型案例

text
任务:从 Redux 迁移到 Zustand

涉及文件:
- 100+ 个组件(使用 useSelector、useDispatch)
- 50+ 个 action 文件
- 20+ 个 reducer 文件
- 10+ 个 saga 文件

问题:Agent 只能读取 20-30 个文件,遗漏了大量调用方
结果:重构后 30% 的组件报错(找不到 action)

解决方案

yaml
# context-management.yaml
strategies:
  - name: "分模块重构"
    description: "把大重构拆成多个小重构"
    example: |
      不要一次性迁移所有 Redux
      而是:
      1. 先迁移 user 模块
      2. 验证通过后,迁移 product 模块
      3. 依次迁移其他模块
  
  - name: "提供依赖图"
    description: "使用工具生成模块依赖图"
    tools:
      - "madge(生成依赖图)"
      - "dependency-cruiser(分析依赖关系)"
    example: |
      madge --image deps.svg src/
      生成依赖图后,提供给 Agent 作为上下文
  
  - name: "增量上下文"
    description: "分批次提供上下文"
    example: |
      第 1 轮:提供架构文档和模块列表
      第 2 轮:提供当前模块的详细代码
      第 3 轮:提供关联模块的接口定义

3.2 风险 2:验证不充分

问题:大型重构后,单元测试通过不代表系统正常。

典型案例

text
任务:从 REST 迁移到 GraphQL

单元测试:全部通过
集成测试:全部通过
E2E 测试:失败

原因:
- 单元测试只测试了单个 resolver
- 集成测试只测试了单个 API
- E2E 测试发现:前端缓存没有更新,导致数据不一致

解决方案

yaml
# testing-strategy.yaml
layers:
  - name: "单元测试"
    coverage: "单个函数/组件"
    tools: ["Jest", "Vitest"]
    required: true
  
  - name: "集成测试"
    coverage: "模块间交互"
    tools: ["Supertest", "Testing Library"]
    required: true
  
  - name: "E2E 测试"
    coverage: "完整用户流程"
    tools: ["Playwright", "Cypress"]
    required: true  # 大型重构必须
  
  - name: "性能测试"
    coverage: "关键路径性能"
    tools: ["Lighthouse", "k6"]
    required: false  # 可选
  
  - name: "视觉回归测试"
    coverage: "UI 变化"
    tools: ["Percy", "Chromatic"]
    required: false  # 可选

3.3 风险 3:架构设计错误

问题:Agent 可能选择不适合当前场景的设计模式。

典型案例

text
任务:重构订单系统

Agent 选择:使用微服务架构
问题:
- 团队只有 5 人,维护不了 10 个微服务
- 订单和支付强耦合,拆分后事务复杂度爆炸
- 没有 DevOps 团队,无法支撑微服务基础设施

正确选择:
- 使用模块化单体(Modular Monolith)
- 在单体内划分清晰的模块边界
- 未来有需要再拆分微服务

解决方案

yaml
# architecture-review.yaml
review_checklist:
  - question: "设计是否符合团队规模?"
    rule: "5 人以下团队不要用微服务"
  
  - question: "设计是否符合业务复杂度?"
    rule: "简单业务不要用复杂架构"
  
  - question: "设计是否考虑未来演进?"
    rule: "预留扩展点,但不过度设计"
  
  - question: "设计是否有参考案例?"
    rule: "优先选择有成功案例的架构"

human_review_required:
  - "架构设计必须人工 Review"
  - "涉及基础设施变化的设计必须 DevOps Review"
  - "涉及数据模型变化的设计必须 DBA Review"

3.4 风险 4:性能退化

问题:重构后功能正常,但性能下降。

典型案例

text
任务:从 SQL 查询迁移到 ORM

重构前:
- 复杂查询使用原生 SQL
- 查询耗时 50ms

重构后:
- 使用 ORM 的 QueryBuilder
- 查询耗时 500ms(10 倍退化)

原因:
- ORM 生成了低效的 SQL(N+1 查询问题)
- 没有使用 eager loading

解决方案

yaml
# performance-testing.yaml
strategies:
  - name: "建立性能基线"
    description: "重构前记录关键路径的性能指标"
    metrics:
      - "API 响应时间(P50、P95、P99)"
      - "数据库查询耗时"
      - "页面加载时间"
      - "内存占用"
  
  - name: "重构后对比"
    description: "重构后重新测量,对比基线"
    threshold: "性能退化超过 20% 必须优化"
  
  - name: "自动化性能测试"
    tools:
      - "k6(API 性能测试)"
      - "Lighthouse(前端性能测试)"
      - "pg_stat_statements(数据库查询分析)"

3.5 风险 5:数据迁移遗漏

问题:重构涉及数据库 Schema 变更,但数据迁移脚本有遗漏。

典型案例

text
任务:用户表拆分(user → user + user_profile)

迁移脚本:
1. 创建 user_profile 表
2. 迁移数据:INSERT INTO user_profile SELECT ... FROM user

问题:
- 遗漏了 NULL 值处理(某些字段允许 NULL)
- 遗漏了外键约束(profile 引用的其他表)
- 遗漏了索引(迁移后查询变慢)

结果:
- 迁移成功,但数据不完整
- 回滚失败,因为外键约束

解决方案

yaml
# migration-checklist.yaml
pre_migration:
  - "备份数据库"
  - "在测试环境验证迁移脚本"
  - "记录迁移前的数据量"
  - "记录迁移前的查询性能"

migration_script:
  - "处理 NULL 值"
  - "处理外键约束"
  - "创建必要的索引"
  - "使用事务保证原子性"
  - "添加回滚脚本"

post_migration:
  - "验证数据完整性"
  - "验证查询性能"
  - "验证应用功能"
  - "监控错误日志 24 小时"

3.6 风险 6:回滚困难

问题:重构失败后无法回滚。

典型案例

text
任务:数据库 Schema 变更

问题:
- 没有准备回滚脚本
- 重构后发现了数据问题
- 想回滚,但新数据已经写入新表
- 回滚会丢失新数据

结果:
- 只能手动修复数据
- 耗时 2 天

解决方案

yaml
# rollback-strategy.yaml
strategies:
  - name: "双写策略"
    description: "新旧系统同时写入,验证后切换"
    steps:
      - "1. 新系统上线,但只读"
      - "2. 双写:写入新系统的同时写入旧系统"
      - "3. 验证:对比新旧系统的数据"
      - "4. 切换:新系统改为读写"
      - "5. 清理:删除旧系统"
  
  - name: "Feature Flag"
    description: "使用特性开关控制新旧系统"
    steps:
      - "1. 新系统上线,但 Feature Flag 关闭"
      - "2. 逐步开放 Feature Flag(1% → 10% → 100%)"
      - "3. 监控错误率和性能"
      - "4. 有问题立即关闭 Feature Flag"
  
  - name: "数据快照"
    description: "重构前备份数据"
    steps:
      - "1. 重构前备份数据库"
      - "2. 重构后验证数据"
      - "3. 有问题从备份恢复"

四、人工接管的 5 个关键节点

4.1 节点 1:重构规划

必须人工:架构设计、模块拆分、风险评估

yaml
# planning-checklist.yaml
human_tasks:
  - "确定重构目标和范围"
  - "评估风险和影响范围"
  - "设计重构方案(架构选择)"
  - "制定回滚策略"
  - "确定验证标准"

agent_tasks:
  - "分析代码依赖关系"
  - "生成重构步骤"
  - "估算工作量和时间"

4.2 节点 2:上下文准备

必须人工:提供架构文档、模块依赖图、业务规则

yaml
# context-preparation.yaml
human_tasks:
  - "提供架构文档"
  - "提供模块依赖图"
  - "提供业务规则文档"
  - "提供数据流图"
  - "提供性能基线数据"

agent_tasks:
  - "分析代码结构"
  - "生成依赖关系"
  - "识别关键文件"

4.3 节点 3:架构 Review

必须人工:架构设计必须人工 Review

yaml
# architecture-review.yaml
human_tasks:
  - "Review 架构设计"
  - "评估技术选型"
  - "评估团队可维护性"
  - "评估未来扩展性"

review_criteria:
  - "是否符合团队规模?"
  - "是否符合业务复杂度?"
  - "是否有参考案例?"
  - "是否考虑未来演进?"

4.4 节点 4:集成测试验证

必须人工:集成测试和 E2E 测试必须人工验证

yaml
# testing-verification.yaml
human_tasks:
  - "Review 集成测试结果"
  - "验证关键业务流程"
  - "验证数据一致性"
  - "验证性能指标"

automated_tasks:
  - "运行单元测试"
  - "运行 Lint 检查"
  - "运行类型检查"

4.5 节点 5:上线决策

必须人工:上线决策必须人工做

yaml
# deployment-decision.yaml
human_tasks:
  - "Review 测试报告"
  - "Review 性能报告"
  - "Review 回滚方案"
  - "决定上线时间"
  - "决定是否上线"

checklist:
  - "所有测试通过?"
  - "性能没有退化?"
  - "回滚方案验证通过?"
  - "监控告警配置完成?"
  - "团队知晓上线计划?"

五、大型重构的最佳实践

5.1 分阶段重构

yaml
# phased-refactoring.yaml
strategy: "把大重构拆成多个小重构"

example:
  task: "从 Redux 迁移到 Zustand"
  
  phases:
    - phase: 1
      scope: "user 模块"
      files: 15
      duration: "2 小时"
      verification: "单元测试 + 集成测试"
      
    - phase: 2
      scope: "product 模块"
      files: 20
      duration: "3 小时"
      verification: "单元测试 + 集成测试"
      
    - phase: 3
      scope: "order 模块"
      files: 25
      duration: "4 小时"
      verification: "单元测试 + 集成测试 + E2E"
      
    - phase: 4
      scope: "清理旧代码"
      files: 50
      duration: "1 小时"
      verification: "全量测试"
  
  benefits:
    - "每个阶段可独立验证"
    - "失败可回滚到上一阶段"
    - "降低风险"

5.2 依赖图驱动

yaml
# dependency-driven.yaml
strategy: "使用依赖图指导重构顺序"

tools:
  - name: "madge"
    command: "madge --image deps.svg src/"
    output: "依赖图 SVG"
  
  - name: "dependency-cruiser"
    command: "depcruise --validate --output-type dot src/"
    output: "依赖关系 JSON"

workflow:
  - "1. 生成依赖图"
  - "2. 识别核心模块(被依赖最多的模块)"
  - "3. 从边缘模块开始重构(依赖最少的模块)"
  - "4. 逐步向核心模块推进"
  - "5. 最后重构核心模块"

benefits:
  - "减少返工(边缘模块改动不会影响核心模块)"
  - "降低风险(核心模块最后改,有充足时间验证)"

5.3 测试先行

yaml
# test-first.yaml
strategy: "先补测试,再重构"

workflow:
  - "1. 分析重构范围"
  - "2. 检查测试覆盖率"
  - "3. 补充缺失的测试(目标覆盖率 > 80%)"
  - "4. 确保所有测试通过"
  - "5. 开始重构"
  - "6. 重构后运行测试"
  - "7. 测试失败则修复或回滚"

benefits:
  - "测试是重构的安全网"
  - "没有测试的重构是赌博"
  - "测试覆盖率越高,重构越安全"

5.4 Feature Flag 控制

yaml
# feature-flag.yaml
strategy: "使用 Feature Flag 控制新旧系统切换"

implementation:
  - name: "LaunchDarkly"
    type: "SaaS"
    pricing: "按 MAU 收费"
  
  - name: "Unleash"
    type: "自托管"
    pricing: "免费"
  
  - name: "自研"
    type: "自研"
    pricing: "开发成本"

workflow:
  - "1. 新系统上线,Feature Flag 关闭"
  - "2. 内部测试(Feature Flag 对内部开放)"
  - "3. 灰度发布(1% → 10% → 50% → 100%)"
  - "4. 监控错误率和性能"
  - "5. 有问题立即关闭 Feature Flag"
  - "6. 稳定后删除旧代码"

benefits:
  - "可快速回滚"
  - "可灰度验证"
  - "可降低风险"

六、实战案例:从 Redux 迁移到 Zustand

6.1 任务描述

text
项目:电商后台管理系统
技术栈:React + Redux + Redux-Saga
规模:200+ 组件,100+ action,50+ reducer

目标:迁移到 Zustand
原因:Redux 样板代码太多,开发效率低

6.2 重构计划

yaml
# migration-plan.yaml
phases:
  - phase: 1
    name: "准备阶段"
    tasks:
      - "生成依赖图"
      - "识别模块边界"
      - "补充测试(覆盖率从 60% 到 80%)"
      - "设计 Zustand 架构"
    duration: "2 天"
    human_required: true
  
  - phase: 2
    name: "user 模块迁移"
    tasks:
      - "创建 user store(Zustand)"
      - "迁移 user action"
      - "迁移 user reducer"
      - "更新 15 个组件"
    files: 25
    duration: "4 小时"
    human_required: false
  
  - phase: 3
    name: "product 模块迁移"
    tasks:
      - "创建 product store"
      - "迁移 product action"
      - "迁移 product reducer"
      - "更新 20 个组件"
    files: 30
    duration: "5 小时"
    human_required: false
  
  - phase: 4
    name: "order 模块迁移"
    tasks:
      - "创建 order store"
      - "迁移 order action"
      - "迁移 order reducer"
      - "更新 25 个组件"
    files: 35
    duration: "6 小时"
    human_required: false
  
  - phase: 5
    name: "集成测试"
    tasks:
      - "运行全量测试"
      - "E2E 测试关键流程"
      - "性能测试"
    duration: "2 小时"
    human_required: true
  
  - phase: 6
    name: "清理旧代码"
    tasks:
      - "删除 Redux 相关代码"
      - "删除未使用的依赖"
      - "更新文档"
    files: 50
    duration: "2 小时"
    human_required: false

total_duration: "4 天"
human_required_percentage: "30%"

6.3 执行结果

yaml
# execution-result.yaml
success: true
duration: "4.5 天"
issues:
  - issue: "user 模块迁移后,购物车组件报错"
    cause: "购物车组件依赖 user state,但没有更新"
    solution: "补充遗漏的 3 个组件"
    time_cost: "30 分钟"
  
  - issue: "order 模块迁移后,性能下降 30%"
    cause: "Zustand 的 selector 没有优化,导致不必要的重渲染"
    solution: "使用 useMemo 和 shallow 比较"
    time_cost: "1 小时"

lessons:
  - "依赖图很重要,遗漏了 3 个组件"
  - "性能测试很重要,发现了性能退化"
  - "分阶段重构很有效,每个阶段都可独立验证"

七、真实经验与踩坑

7.1 第一次翻车:没有依赖图,遗漏 30% 调用方

场景:Agent 重构了 API 接口,但没有生成依赖图。

结果:重构后 30% 的调用方报错(参数变了,但调用方没更新)。

教训

  • 依赖图是大型重构的必备工具
  • 使用 madge 或 dependency-cruiser 生成依赖图
  • 把依赖图提供给 Agent 作为上下文

7.2 第二次翻车:单元测试通过,集成测试失败

场景:Agent 重构了数据库 Schema,单元测试全部通过。

结果:集成测试失败,因为两个模块的事务处理不一致。

教训

  • 单元测试不够,必须加集成测试
  • 大型重构必须测试模块间交互
  • 使用 Supertest 或 Testing Library 做集成测试

7.3 第三次翻车:重构后性能下降 10 倍

场景:Agent 从原生 SQL 迁移到 ORM。

结果:查询性能从 50ms 退化到 500ms(N+1 查询问题)。

教训

  • 重构前建立性能基线
  • 重构后对比性能指标
  • 使用 k6 或 Lighthouse 做性能测试

八、总结

Agent 做大型重构的上限不在"改多少文件",而在三个关键因素:

  1. 上下文能否覆盖:Agent 必须理解全局架构,否则会遗漏关联文件
  2. 验证是否可自动化:必须有完整的测试覆盖,否则无法验证重构结果
  3. 人工接管点是否明确:架构设计、集成测试、上线决策必须人工把关

核心经验

  1. 分阶段重构:把大重构拆成多个小重构,每个阶段可独立验证
  2. 依赖图驱动:使用工具生成依赖图,指导重构顺序
  3. 测试先行:先补测试,再重构,测试是重构的安全网
  4. Feature Flag:使用特性开关控制新旧系统切换,可快速回滚
  5. 人工把关:架构设计、集成测试、上线决策必须人工 Review

最佳实践

  • 小型重构(< 10 文件):Agent 独立完成,成功率 95%
  • 中型重构(10-50 文件):Agent 主导,人工 Review,成功率 78%
  • 大型重构(50+ 文件):人工主导,Agent 辅助,成功率 42%

最终建议

大型重构不是"能不能自动化"的问题,而是"如何降低风险"的问题。把 Agent 当作"高级助手",它帮你分析代码、生成重构步骤、执行重构,但架构设计、验证和上线决策必须人工把关。

九、系列导航

上一篇:Lab 010:Agent 生成前端页面,最容易在哪些细节翻车? 下一篇:MCP 组合实战:把 GitHub、Figma、数据库和知识库接进 Agent 工作流