跳到主要内容

AI 参与生产系统迁移:把模型能力放进可验证的交付流程

· 阅读需 9 分钟
feilx
the biulight site owner

AI 可以很快读完一个仓库、列出迁移清单、批量修改代码;但在一个缺少业务和技术文档、仍在生产运行的 系统里,“改得快”并不等于“可以上线”。这次 Vue 2 → Vue 3 迁移让我更确信:AI 最合适的位置不是 替代工程判断,而是进入一套有阶段、有证据、有回归边界的交付流程。

这篇文章不讨论 Vue API 本身,而是记录 AI 如何参与一个陌生生产系统的迁移:先收集事实、生成可审查 计划,再分批实施、手工验收,并把每次发现沉淀成下一轮可复用的规则。有关 Vue 迁移的技术细节见 keystone-web 从 Vue 2 到 Vue 3:一场两段式迁移的复盘

起点:代码很多,文档很少,不能假装自己已经理解业务

项目是一个中大型管理后台,有数百个 Vue 组件、权限路由、复杂表格、多个媒体类型的业务流程,以及 持续使用中的生产环境。接手时我并不熟悉业务,相关技术与业务文档也不完整。

在这种条件下,最危险的 AI 使用方式是把问题简化成一句“升级到 Vue 3”,然后接受一份看似完整的 改动。模型可以根据常见迁移模式给出合理建议,却不知道某个 params 是否承载业务身份、某个表格的 事件是否被下游依赖,或者一个管理员账号是否绕过了普通用户必经的权限路径。

因此先确定了一个原则:AI 不能以推断取代项目事实;每个结论都要有代码、测试、构建结果或手工观察 作为落点。

先降低未知数:不要同时替换所有基础设施

迁移被拆成两段。第一段先将 Vue CLI 迁到 Rsbuild,但仍保持 Vue 2.7 上线。随后用约半年的稳定运行期 理解系统、清理无用代码与技术债,并在新改动中优先采用 Vue 2.7 和 Vue 3 共用的能力,例如 Composition API 和新插槽语法。

这一步不是“拖慢升级”,而是在为 AI 和人都创造更好的问题边界。等正式开始 Vue 3 迁移时,构建器、 环境变量、开发与生产构建已经经过验证;排查一个问题时,不必再同时怀疑 Rsbuild、Vue 运行时和业务 逻辑。先减少变量,之后的自动化才有可信的上下文。

用 AI 写计划前,先给它经过核实的输入

计划阶段使用 Fable 5,但它不是从一句模糊需求开始猜。输入先由全仓检索和依赖排查组成,包括:

  • 331 个 .vue 组件的规模及业务模块分布;
  • 151 处 .sync、122 个 slot="..." 命中、全局和局部指令的实际数量;
  • Vue Router、Vuex、Element UI、VXE Table、测试工具与构建配置的现状;
  • 哪些高风险封装需要人工审查,哪些模式可以批量处理;
  • 不做 UI 重设计、不换状态管理、不换构建器等范围边界。

Fable 5 在这些事实之上生成迁移策略和 PRD:比较全量重写、长期 compat、微前端隔离三种路线;定义 基线、基础设施、第三方库、机械替换、公共组件、业务模块、测试升级和收尾验收等阶段;再为每一批 列出依赖关系和验证方式。

这里真正有价值的不是“AI 写出了一份很长的计划”,而是计划可以被审查、被纠正、被执行。比如 slot="..." 的 122 个命中并不等于 122 个模板迁移点:其中混有 JSX 中合法的属性和注释。把这个 前提写进 PRD,就能阻止后续执行模型做危险的全局替换。

实施时,把模型当作分批交付者,而不是一次性重写器

Opus 4.7 与 Sonnet 5 按 PRD 分批实施。每个批次都有清楚的范围和退出条件:例如先让基础设施能进入 登录页,再替换 Element UI 和 VXE Table,并用真实列表页验证;之后才处理 .sync、插槽、指令等 全仓变化;最后按公共组件、业务模块的依赖顺序推进。

这套节奏给 AI 加了三层约束:

  1. 改动范围小。 每一批聚焦一类依赖或一个模块,失败时能回到明确的 diff。
  2. 验证紧随改动。 构建、lint、单测、E2E 和手工页面验证按阶段执行,不等到最后才发现问题。
  3. 不夹带“顺手优化”。 迁移期间发现的无关重构只记录,不在同一批改动中扩张范围。

模型很擅长重复性工作:全仓盘点、模式转换、补齐大量相似调用点、汇总失败清单。它不擅长在缺少上下文 时猜测某个行为是否是业务约定。因此,批次拆分的意义不是限制 AI 的速度,而是让每次推断都有机会被 最小范围的验证推翻。

真实反例:一个看似合理的路由规则如何造成回归

最有教育意义的不是成功案例,而是一次错误的启发式。

迁移 Vue Router 3 到 4 时,曾把“内部 router.push() 应使用 query,构造可分享链接的 router.resolve() 应使用 params”当作批量修改规则。这个规则很顺口,但它是错的。

真正决定参数位置的是目标路由的 path:未声明动态段的值使用 query;必填动态段必须使用 params;可选动态段再按约定选择。错误规则把某个内部跳转的必填 id 放进 query,结果在点击列表 行时同步抛出 Missing required param,跳转被直接阻断。

这次错误没有被隐藏。它被修复后,完整的根因、适用规则和反例被写进迁移记录,并进一步沉淀为项目 记忆。下一轮 Claude Code 会话不需要“记得上一次聊天”,只需要读取这条规则。

我认为这正是 AI 编程在生产环境里最重要的能力之一:把失败从一次对话中的偶然经验,变成仓库中可 检查、可复用、可更新的知识。

测试覆盖不是安全感:手工验收负责发现模型和用例的共同盲区

自动化用例能保证核心路径持续可跑,却不天然保证覆盖正确。一次手工回归发现,已有 Playwright 冒烟 只用管理员账号登录;管理员恰好绕开了普通角色才会走到的 Campaign 详情重定向,因此上述路由回归 没有被 E2E 捕获。

手工验收还发现过很多“构建、lint、单测都正常”的问题:动态组件在页面显示 [object Promise]、 Element Plus 日期控件因格式 token 或裸 default-time 解析失败而显示错误日期、全局 passive 事件 补丁让下拉组件的鼠标选择失效。这些问题往往需要真实数据、空状态、特定角色或连续交互才能出现。

所以手工验收不是自动化测试的低配替代,而是专门覆盖高不确定性区域的另一层测试。对管理后台而言, 至少应显式覆盖:

  • 管理员与非管理员的菜单、深链接和权限拦截;
  • 有数据、空数据、可清空字段和默认值;
  • 表格分页、筛选、滚动、弹窗、Popover、上传和动态组件;
  • 控制台中的框架、路由和组件库警告。

每个手工发现都应有去向:补成自动化用例、加入手工清单,或提炼为迁移规则。没有去向的“已修复”只是 下一次回归的候选。

AI 需要的不只是上下文窗口,而是项目记忆系统

这次实践中,迁移信息被拆成不同层次保存:

载体负责回答的问题
迁移 PRD为什么采用这条路线、阶段如何依赖、每批如何验收
迁移问题记录具体故障的现象、根因、修复方式与回归规则
项目 AGENTS.md当前技术栈、开发约束、验证命令和禁止重新引入的兼容层
项目记忆一条会在后续任务反复使用的精确规则,例如路由参数边界
Git 提交与测试改动的可审查证据、可回退边界与行为验证

这种分层比把所有信息塞进一个超长提示词更可靠。提示词会过期、上下文会被截断、不同模型的理解也会 不同;而仓库里的文档、规则和测试可以随实现变化一起维护。

我会继续坚持的边界

AI 参与生产改造时,我会把下面几条当作默认约束:

  1. 让 AI 先完成全仓盘点和证据收集,再由人工审查盘点结论、范围与风险后制定方案。
  2. 将大迁移拆成可独立验证、可回退的小批次。
  3. 对 API 行为、权限、路由和组件库差异,优先相信源码、测试和真实页面,而不是“通常如此”。
  4. 把模型造成或发现的错误写成规则和测试,而不是只留在聊天记录里。
  5. 保留人工验收,特别是角色、空状态、视觉和连续交互路径。
  6. 不把迁移、性能优化和业务重构混在同一轮交付中。

AI 没有让生产迁移变成零风险工作;它减少的是盘点、重复修改和信息整理的成本。真正让风险可控的, 仍然是清晰的范围、持续的验证、可回退的提交,以及愿意把错误沉淀下来的人。

评论