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 评估维度
# 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 失败原因分析
# 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 无法一次性读取所有文件。
典型案例:
任务:从 Redux 迁移到 Zustand
涉及文件:
- 100+ 个组件(使用 useSelector、useDispatch)
- 50+ 个 action 文件
- 20+ 个 reducer 文件
- 10+ 个 saga 文件
问题:Agent 只能读取 20-30 个文件,遗漏了大量调用方
结果:重构后 30% 的组件报错(找不到 action)解决方案:
# 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:验证不充分
问题:大型重构后,单元测试通过不代表系统正常。
典型案例:
任务:从 REST 迁移到 GraphQL
单元测试:全部通过
集成测试:全部通过
E2E 测试:失败
原因:
- 单元测试只测试了单个 resolver
- 集成测试只测试了单个 API
- E2E 测试发现:前端缓存没有更新,导致数据不一致解决方案:
# 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 可能选择不适合当前场景的设计模式。
典型案例:
任务:重构订单系统
Agent 选择:使用微服务架构
问题:
- 团队只有 5 人,维护不了 10 个微服务
- 订单和支付强耦合,拆分后事务复杂度爆炸
- 没有 DevOps 团队,无法支撑微服务基础设施
正确选择:
- 使用模块化单体(Modular Monolith)
- 在单体内划分清晰的模块边界
- 未来有需要再拆分微服务解决方案:
# 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:性能退化
问题:重构后功能正常,但性能下降。
典型案例:
任务:从 SQL 查询迁移到 ORM
重构前:
- 复杂查询使用原生 SQL
- 查询耗时 50ms
重构后:
- 使用 ORM 的 QueryBuilder
- 查询耗时 500ms(10 倍退化)
原因:
- ORM 生成了低效的 SQL(N+1 查询问题)
- 没有使用 eager loading解决方案:
# 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 变更,但数据迁移脚本有遗漏。
典型案例:
任务:用户表拆分(user → user + user_profile)
迁移脚本:
1. 创建 user_profile 表
2. 迁移数据:INSERT INTO user_profile SELECT ... FROM user
问题:
- 遗漏了 NULL 值处理(某些字段允许 NULL)
- 遗漏了外键约束(profile 引用的其他表)
- 遗漏了索引(迁移后查询变慢)
结果:
- 迁移成功,但数据不完整
- 回滚失败,因为外键约束解决方案:
# migration-checklist.yaml
pre_migration:
- "备份数据库"
- "在测试环境验证迁移脚本"
- "记录迁移前的数据量"
- "记录迁移前的查询性能"
migration_script:
- "处理 NULL 值"
- "处理外键约束"
- "创建必要的索引"
- "使用事务保证原子性"
- "添加回滚脚本"
post_migration:
- "验证数据完整性"
- "验证查询性能"
- "验证应用功能"
- "监控错误日志 24 小时"3.6 风险 6:回滚困难
问题:重构失败后无法回滚。
典型案例:
任务:数据库 Schema 变更
问题:
- 没有准备回滚脚本
- 重构后发现了数据问题
- 想回滚,但新数据已经写入新表
- 回滚会丢失新数据
结果:
- 只能手动修复数据
- 耗时 2 天解决方案:
# 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:重构规划
必须人工:架构设计、模块拆分、风险评估
# planning-checklist.yaml
human_tasks:
- "确定重构目标和范围"
- "评估风险和影响范围"
- "设计重构方案(架构选择)"
- "制定回滚策略"
- "确定验证标准"
agent_tasks:
- "分析代码依赖关系"
- "生成重构步骤"
- "估算工作量和时间"4.2 节点 2:上下文准备
必须人工:提供架构文档、模块依赖图、业务规则
# context-preparation.yaml
human_tasks:
- "提供架构文档"
- "提供模块依赖图"
- "提供业务规则文档"
- "提供数据流图"
- "提供性能基线数据"
agent_tasks:
- "分析代码结构"
- "生成依赖关系"
- "识别关键文件"4.3 节点 3:架构 Review
必须人工:架构设计必须人工 Review
# architecture-review.yaml
human_tasks:
- "Review 架构设计"
- "评估技术选型"
- "评估团队可维护性"
- "评估未来扩展性"
review_criteria:
- "是否符合团队规模?"
- "是否符合业务复杂度?"
- "是否有参考案例?"
- "是否考虑未来演进?"4.4 节点 4:集成测试验证
必须人工:集成测试和 E2E 测试必须人工验证
# testing-verification.yaml
human_tasks:
- "Review 集成测试结果"
- "验证关键业务流程"
- "验证数据一致性"
- "验证性能指标"
automated_tasks:
- "运行单元测试"
- "运行 Lint 检查"
- "运行类型检查"4.5 节点 5:上线决策
必须人工:上线决策必须人工做
# deployment-decision.yaml
human_tasks:
- "Review 测试报告"
- "Review 性能报告"
- "Review 回滚方案"
- "决定上线时间"
- "决定是否上线"
checklist:
- "所有测试通过?"
- "性能没有退化?"
- "回滚方案验证通过?"
- "监控告警配置完成?"
- "团队知晓上线计划?"五、大型重构的最佳实践
5.1 分阶段重构
# 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 依赖图驱动
# 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 测试先行
# test-first.yaml
strategy: "先补测试,再重构"
workflow:
- "1. 分析重构范围"
- "2. 检查测试覆盖率"
- "3. 补充缺失的测试(目标覆盖率 > 80%)"
- "4. 确保所有测试通过"
- "5. 开始重构"
- "6. 重构后运行测试"
- "7. 测试失败则修复或回滚"
benefits:
- "测试是重构的安全网"
- "没有测试的重构是赌博"
- "测试覆盖率越高,重构越安全"5.4 Feature Flag 控制
# 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 任务描述
项目:电商后台管理系统
技术栈:React + Redux + Redux-Saga
规模:200+ 组件,100+ action,50+ reducer
目标:迁移到 Zustand
原因:Redux 样板代码太多,开发效率低6.2 重构计划
# 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 执行结果
# 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 做大型重构的上限不在"改多少文件",而在三个关键因素:
- 上下文能否覆盖:Agent 必须理解全局架构,否则会遗漏关联文件
- 验证是否可自动化:必须有完整的测试覆盖,否则无法验证重构结果
- 人工接管点是否明确:架构设计、集成测试、上线决策必须人工把关
核心经验:
- 分阶段重构:把大重构拆成多个小重构,每个阶段可独立验证
- 依赖图驱动:使用工具生成依赖图,指导重构顺序
- 测试先行:先补测试,再重构,测试是重构的安全网
- Feature Flag:使用特性开关控制新旧系统切换,可快速回滚
- 人工把关:架构设计、集成测试、上线决策必须人工 Review
最佳实践:
- 小型重构(< 10 文件):Agent 独立完成,成功率 95%
- 中型重构(10-50 文件):Agent 主导,人工 Review,成功率 78%
- 大型重构(50+ 文件):人工主导,Agent 辅助,成功率 42%
最终建议:
大型重构不是"能不能自动化"的问题,而是"如何降低风险"的问题。把 Agent 当作"高级助手",它帮你分析代码、生成重构步骤、执行重构,但架构设计、验证和上线决策必须人工把关。
九、系列导航
上一篇:Lab 010:Agent 生成前端页面,最容易在哪些细节翻车? 下一篇:MCP 组合实战:把 GitHub、Figma、数据库和知识库接进 Agent 工作流