升级依赖总挂在同样几个地方:类型检查看不见的废弃 API、函数签名没动但行为变了、peer-dep 冲突静默解析成错误版本、单测抓不到的运行时回归。AI Agent 能搞定——前提是你给它结构:CHANGELOG、对应到你代码的破坏性变更清单、以及一个”不许漂移到重构”的修复循环。
这篇主要解决什么问题
接手项目时关键依赖已经落后 12 个 major;或者周五下午 5 点掉了安全公告,patch 隐藏在两个破坏性版本之后。CI 绿但你不信版本锁。这套流程让一个开发者加一个 AI Agent,在一次专注会话里安全完成升级——并 ship 一份 CHANGELOG 映射好的 diff,reviewer 真能核。
这篇适合谁看
面对”已经落后 12 个 major”的维护者;被 npm update 烫过、现在拒绝跑它的人;接手 4 年没动过 lockfile 的内部项目的开发者;安全驱动的一次性升级、patched 版本比你领先 2 个 major 的情况。
什么时候适合用
某个依赖落后好几个 major。CI 通过但你不信版本锁。被安全公告逼着升。接手一个废弃内部工具且 lockfile 比公司当前 ESLint 配置还老。在动其他东西之前先跑这套。
什么时候不建议用
框架级迁移(Vue 2→3、React 17→19、Angular major-major、Rails major-major)——要专门的迁移计划,含 codemod、分阶段上线、常需 feature freeze,不是简单升级。也别用在小型 prototype——按当前版本从零重建比升级还快。
开始前准备
- 确认 main 上 CI 绿。main 红就先修红,否则升级失败和既有失败混在一起没法分。
- 准备能跑的冒烟测试方案:3-4 条手工路径,覆盖你要升的依赖。类型过 / 冒烟挂——后者抓真回归。
- 定升级边界:就这一个包 + 必要的 peer-dep?还是带相邻包?默认”一次一个包”。
- 留好回滚:老 lockfile 留备份,懂自己的分支保护。
具体步骤
- 从绿 main 拉分支。 跑完整测试套件。基线确认过。基线绿不了——先停下修基线。
- 和 AI 一起读 CHANGELOG。 Prompt:“我要把
\{包\}从\{x\}升到\{y\}。读该范围的 CHANGELOG 和迁移指南。列每条可能影响 TypeScript 代码库 + [列出你用的 API] 的破坏性变更。“存清单。 - 破坏性变更映射到你代码。 每条问:“本仓库哪些文件用了受影响的 API?给 file:line。“点开核——给一堆没真匹配的文件就是幻觉。
- 升级包。
npm install package@y或等价。重新解析 lockfile。同一次 commit 别动其他依赖。 - 跑测试。归档失败。 先别修。列出每个失败:哪个测试文件、哪条 assertion、源码哪一行。
- 失败和破坏性变更清单交叉对照。 每个失败该对应清单上一条。对不上说明你漏了一条——回第 2 步,把失败当证据重 prompt。
- 逐条修。 每个修复 AI 该出最小化 diff,采用新 API,不是顺手重构周边。问:“这是最小化改动,还是在引入不匹配代码库其他风格的新模式?”
- 跑完整测试 + 跑起来手工冒烟。 类型过不够。启动 App、走冒烟路径、看 network 和 console 警告。
- 按 CHANGELOG 映射写 commit。 每个 commit 写明对应清单上哪一条。Reviewer 能拿 diff 对 CHANGELOG。
破坏性变更映射 prompt
Package: \{name\}
Upgrade: \{from-version\} -> \{to-version\}
Codebase: TypeScript 5, Node 22, [framework]
读该范围的官方 CHANGELOG 和迁移指南。
返回表格:
| 破坏性变更 | 受影响 API | 本仓库 file:line | 建议修法 |
只列影响本代码库的;我们没用的特性变更跳过。每行给出
CHANGELOG 章节引用,我要能核。
第一次实操怎么跑
- 挑一个落后 1-2 major 的依赖。不是最危险那个。
- 9 步走完。
- 给跑时计时。记下 AI 哪一步对、哪一步需要重 prompt。
- 第二次跑更危险的依赖快得多——你已经知道你 Agent 每步的可靠度。
完成后检查
- 你失败清单里每一条都对应某条 CHANGELOG 吗?对不上说明还有没发现的破坏性变更。
- 是在跑起来的 App 上冒烟过吗,不是只 CI?类型检查抓不到运行时回归,尤其是静默那种(日志变化、默认参数翻转)。
- AI 顺手加了无关重构吗?revert——属于另一个 PR。
- lockfile 解析干净,还是带了某个未授权的传递依赖 major?需要就 pin 住。
怎么复用这套流程
- 破坏性变更映射 prompt 存模板;只换包名和版本范围。
- 每个项目维护升级日志:哪些包、哪些版本、什么失败、用了多久。规律会浮现——某些包在某个版本切换上稳定地难。
- patch 级升级让 Dependabot / Renovate 自动 PR;这套手动 AI 流留给 major 和高危 minor。
建议的操作流程
React Router 5 → 6:列破坏性变更(Switch → Routes、useHistory → useNavigate 等)→ 升级 → 11 个测试挂 → 每个挂对应一条已知破坏性变更 → 上线。如果 App 部署到 Firebase Hosting,紧接着跑AI Firebase 部署检查工作流——大版本升级常常会打坏 SPA rewrite 规则和 function region,本地测试抓不到。
容易踩的坑
- 跳过 CHANGELOG。AI 会从训练数据猜——可能对你的版本不对。一定要把 Agent 锚在已发布的 CHANGELOG 上。
- 升级时让 AI 顺手做风格重构。每个重构都给本应无聊的 PR 增加风险。留给另一波。
- 同时升多个包。失败归因难。一个包一个 PR。
- 不在跑起来的 App 上冒烟。类型过,App 加载空白因为一个默认 prop 翻了。冒烟不可选。
- 信任传递依赖解析。lockfile 引入新 major 的传递包就显式 pin 直到你也读过它的 CHANGELOG。
- CI 绿就算完。生产有 CI 不复现的运行时配置——先上 staging。
进阶技巧
- 框架升级问:“
\{x\}→\{y\}的官方推荐迁移路径?维护者发布的 codemod / 迁移脚本?“用上。 - peer-dep 地狱问:“最小兼容版本集合一起升哪些?“作为协调单元升,不是零碎升。
- 反复痛的包,建一份过去修复 snippet 库。很多包跨 major 复用同样的破坏性变更模式。
- monorepo:先在最小 workspace 升一次摸形状再传播。
怎么验收输出
- 从绿 main 拉的分支,所有测试基线过。
- CHANGELOG 破坏性变更映射到具体文件。
- 所有测试挂都对应一条已知破坏性变更。
- 运行中的 App 手动冒烟过。
- 升级 commit 里没掺风格重构。
- lockfile 审过并提交。
FAQ
- 也用 Dependabot 吗?: 用——补丁版升级和 minor 让它做。AI 流程在 major 和高危 minor、已知有迁移痛点的包上发挥。
- 废弃警告怎么办?: 当作作业,不是阻塞项。2-4 周内单独排 PR 清。让 deprecation 堆积会变成下一个”落后 12 个 major”问题。
- 传递依赖怎么处理?: 升级后审 lockfile。某个传递跳了未授权的 major,显式 pin 或 override。
- AI 坚持某条破坏性变更和你无关、但其实有关怎么办?: 把失败测试输出给它,问:“把这个失败和你说不适用的 CHANGELOG 条目对齐。“Agent 在被指出矛盾时会自纠。
- 能多 Agent 并行吗?: 同一分支一次一个 Agent。同一升级里并行 Agent 会冲突且丢失 CHANGELOG-到-失败的追溯。
- npm、pip、cargo、gem 都适用吗?: 都适用。CHANGELOG 锚定步骤语言无关;只是安装命令和测试框架细节不同。