尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI批量重写存量代码:GitHub三周128个PR的工程实践拆解

AI批量重写存量代码:GitHub三周128个PR的工程实践拆解 1. 一个反直觉的工程选择让 AI 修改自己的源码先说一个可能和多数人直觉相悖的事实GitHub 这个承载了全球数亿个代码仓库的平台其自身的代码库也面临着所有老系统都会遇到的麻烦——技术债堆叠、依赖版本过于陈旧、核心服务之间的耦合越来越深。维护团队每天都在和这些存量代码搏斗而新功能的开发节奏一直被拖后腿。于是他们做了一个很激进的决定把自家代码库的一部分交给 AI 来重写通过大批量生成 PR 的方式在三周内合并了 128 个由 AI 辅助完成的 Pull Request累计改动约 83 万行代码。看到这个数字很多人第一反应是是不是 ChatGPT 直接吐出 83 万行代码然后一股脑贴进去。如果真这么干代码库早就炸了。实际上这 128 个 PR 背后是一套相当精细的工程流程涉及任务拆解、上下文治理、编译与测试的自动化闸门、以及人与 AI 审查协作的新模式。每一个 PR 的改动量、边界和验收标准都是事先设计好的AI 更像是流水线上一个不知疲倦但需要严格看管的操作员而非拍板的设计师。这个案例的参考价值并不限于 GitHub 一家。任何团队只要手里有一批 10 万行以上的存量代码正在为依赖升级、API 迁移、框架换代而头疼都能从中提炼出一套可复用的思路。这篇文章我会沿着这个项目的推进链条逐个环节拆开讲清楚为什么它敢让 AI 动源码拆分 PR 的逻辑是什么质量怎么兜底三周时间线是如何编排的以及这套玩法在什么条件下可以复制到你的项目里。会涉及不少具体做法和判断依据但不会把AI 生成的代码能不能用当成一个玄学问题来回答——用数据、流程和验证结果说话比情绪化争论靠谱得多。2. 从人工迁移到AI 批量改造这 83 万行代码的问题本质2.1 存量代码升级的典型困境GitHub 面对的存量代码本质上是两类问题的叠加第一类是依赖陈旧的连锁反应。代码库使用的核心框架版本停留在一个相当古老的版本上这个版本早已停止维护又因为安全公告和兼容性要求不得不升级。可一旦升级核心框架与之配合的周边库、工具链、自动构建脚本也必须一并调整。这些依赖像一张互相咬合的齿轮网络单独动某一个齿轮相邻的齿轮就会卡死。人工梳理这种依赖网络极其耗时而且常常出现昨天改好了三个文件今天发现另一个模块的调用方式又变了的情况。第二类是跨模块的 API 表面迁移。旧框架的 API 在被调用时参数结构、返回值格式、异常处理方式约定散落在几十个乃至上百个文件中。每一个调用点看似孤立改起来也不需要动太多脑子但总数庞大。让资深工程师连续三周坐在那里机械地修改这种有明确改法但没有智力挑战的代码是巨大的浪费而且人恰恰在这种重复劳动中最容易疲劳走神漏掉边界情况。对于这类问题传统做法是组织一个专项小组按照模块边界分批迁移每批走一遍梳理调用点—修改—编译—测试—人工 review的流程。整个过程通常以月为周期计算而且会造成主干分支长时间处于半迁移状态其他团队的开发工作不断被冲突打断。2.2 为什么这个场景天然适合 AIAI 代码生成模型在这个场景中的表现远好于在从零写一个分布式存储系统这类开放式需求中的表现原因是边界足够清晰、验收标准足够客观。先看任务性质API 迁移、依赖升级、废弃接口替换这类工作输入是旧调用方式输出是新的等价调用方式过程高度程序化。模型的训练数据里存在大量同类迁移的样例它在见过足够多相似改法的前提下可以直接给出符合新 API 约定的代码。你可以把这一步理解为把 80 万行代码当作训练好的翻译模型的源语言目标语言是升级后的 API 规范——比自然语言翻译更简单因为语法规则是确定的编译器和测试套件就能当翻译质量裁判。再看反馈回路。人工迁移一个文件后要手动跑编译、跑单测确认没问题再进入下一个文件。AI 迁移也一样但它的迭代速度可以被工程化地推到极致——每个 PR 生成后自动触发 CI 流水线编译错误和测试失败结果直接回传给生成模块让模型在下一次生成中规避同类问题。这种生成—验证—修正的循环正是机器学习模型最擅长的学习模式。人在这个回路里的角色被压缩到两种设计任务边界和处理机器无法通过的边缘案例。最后是规模效应的区别。人工完成的迁移经验和注意力是逐文件流失的AI 生成的迁移越到后面越能借助反馈积累避开常见错误模式。128 个 PR 能控制在三周完成与其说是模型聪明不如说是这个工作模式的迭代速度足够快。2.3 先立规矩再放开手脚边界划分原则当然AI 写代码的能力再强也不能让它自由发挥去重构整个代码库。GitHub 这边的处理原则很值得借鉴AI 的修改范围被严格限定在同构迁移范围内即只改变调用的方式不改变业务逻辑。换句话说凡是需要理解业务意图的改动——比如这个功能在旧框架里依赖回调新框架里要改成事件驱动那业务行为要不要变——都不在 AI 的决策范围内必须由人工先给出标准改法。AI 只能在这种预先定义好的改法框架内执行大规模复制和替换。这个边界看起来保守实际上非常聪明。业务逻辑的改动需要人的判断争议大、责任重而迁移类改动是确定性工程适合机器批量执行。两者一旦混在一起review 的人就永远分不清改坏了是 AI 的锅还是当初业务设计就有问题。保持同构迁移审查边界就非常清楚新增代码和删除代码是不是一一对应逻辑有没有多出来或者少掉一目了然。3. 128 个 PR 的拆解策略怎么把一个庞然大物切得不重不漏3.1 按依赖层级排序而非按代码行数83 万行代码分布在大量仓库和服务中如果第一反应是按文件数量均匀切 128 份后患无穷。GitHub 团队采用的是依赖层级优先的拆解策略先列出一张依赖关系拓扑图找出那些被最多模块引用的底层库从最底层开始迁移。这个顺序很关键。在软件工程里底层依赖是牵一发动全身的它出问题所有上级模块全都跟着报错。先把底层迁移完成并且保证它稳定通过全部既有测试之后上层模块的迁移就有了一份可信赖的新地基。反过来做的话上层模块改好了下一周底层一换上层又要重新返工。拆解出的每个 PR 也严格限制改动面积。128 个 PR 平均每个约 6 千行左右代码改动但这不是指一次性生成 6 千行新代码而是修改涉及 6 千行——很多情况下其中一半是机械性的接口替换、签名变更另一半是为了配合变更而微调的外部调用点。PR 保持小粒度一是有利于 review二是出问题时定位成本低三是可以更快地暴露系统性错误避免错误模式被复制到几十个 PR 里才发现。3.2 把先导 PR作为样板书项目启动阶段团队并没有让 AI 同时开跑各种任务而是先人工完成了一个小规模的先导 PR覆盖典型的迁移路径。这个 PR 的规格是这样的选择底层依赖中的一个中等规模模块包含约 20 个调用点覆盖了三种最常见的 API 使用方式人工完成迁移后配上详细的 PR 描述重点写明三类信息旧 API 到新 API 的映射规则、特殊场景的处理约定比如回调改事件后的时序问题、以及编译和测试的验证结果把这个 PR 作为后续 AI 生成的风格参考。之所以要这个先导过程是因为模型提示词写得再详细也不如一个真实可运行的成品样例更有约束力。AI 在生成本文后续的 PR 时参考的就是这个样板书中的映射规则和代码风格。如果有多种 API 使用方式样例里没有覆盖到AI 生成的代码很可能跑偏——所以先导 PR 选择的模块要足够典型覆盖尽可能多的调用变体。后来据团队复盘这个先导过程大约占用了整个项目初期一周中的三分之二时间但极大降低了后续批量生成阶段的纠错成本。这属于典型的慢就是快前期规则不清楚就匆忙让 AI 大规模产出后面付出的返工代价会高出一个数量级。3.3 上下文治理如何避免 AI 迷失在代码海洋市面上大多数 AI 代码工具直接面对单文件或单个仓库干活改动范围相对可控。但当目标任务变成跨 20 个仓库、修改 83 万行时最棘手的不是生成而是上下文。模型的上下文窗口装不下整个代码库强行把相关代码全部塞进去既浪费 token又会让模型在无关细节中迷失重点。GitHub 的做法是给每个 PR 任务配一个上下文包。这个上下文包不是随机挑选的代码文件而是根据依赖关系精确计算出的最小集合本 PR 任务涉及的所有源文件这些文件直接调用的依赖接口定义不需要完整实现体只需要签名和类型声明本任务需要迁移到的目标 API 的参考文档和样例片段以及与本次迁移相关的测试文件确保生成的代码在逻辑上空跑时能配对测试用例。这个最小集合的构建有点类似编译器里的按需引入。上下文包里的代码量控制在模型可接受的范围同时保证生成结果所需要的全部约束都在场。整个过程中最考验功力的地方就在于识别哪些文件可以放心地从上下文包里剔除——这需要在基于依赖关系做可达性分析的基础上再结合对目标框架的理解来判断。依赖分析工具能算出相关文件的完整列表但最终删掉哪些巨量的顺带引用还是得人工拍板。3.4 大量生成后的人工分组 review128 个 PR 三周内完成平均每天约 6 个 PR 产出这个频率放到一个正常开发团队里已经相当高了。但如果牵头人每天都要逐个打开 PR 检查每一行代码人力完全跟不上。所以 review 也做了分层次设计第一层是机器把关。编译检查和全套测试是硬门槛这个没过的话 PR 根本无法合入。第二层是抽样人工 review。每个批次 PR 中人工会挑若干有代表性的做全量代码审查重点看那些涉及特殊边界处理的文件而不是均匀撒网。第三层是模式验收。项目负责人每天会进行一次错误聚类——把当天产生的所有 review 意见按错误类型归类如果发现某一类错误频繁出现就回到提示词或者先导样例中补充对应规则下一批量生成时就能系统性地规避。这种人抽查 机器全量 错误聚类反馈的组合让质量保障真正做到了越到后期越稳定。4. 质量怎么守编译、测试、人工三重闸门4.1 把AI 生成的代码能不能用变成一道计算题圈里对 AI 写代码的质疑大多集中在AI 生成代码可能逻辑正确但语义偏颇这个点上。这个担忧在从零开发场景下是成立的但在同构迁移场景下其实可以被大幅消解——因为存在客观的判定基准迁移前后功能等价。GitHub 的做法是把等价性测试做成自动化流水线的核心部分。每个 PR 生成后第一关是编译能否通过。编译器对语法、类型、接口签名进行严格校验AI 如果犯了低级错误在这个环节就直接打回压根不浪费人类审查者的时间。第二关是现有的全部单元测试和集成测试。这部分测试是在迁移发生之前就已经存在的它们代表了系统当前的既定义务。迁移后的代码改动只是替换接口调用不改业务逻辑那么这些测试一个都不应该失败——凡是失败的必须给出合理解释否则 PR 不能合入。这个方法听起来简单但它有一个隐藏前提存量测试套件必须足够健康。如果一个代码库本身测试覆盖率低下或者现有测试里已经有一堆长期处于失败状态的用例这套闸门就毫无意义。GitHub 的代码库在这点上基础相对扎实这也反过来解释了为什么他们有底气推进这种大规模的 AI 改造——自动化验证基础强的系统才敢让机器动手。4.2 特殊边界情况的处理规则迁移过程中总有一部分测试用例在改动后必然会失败——因为旧测试本来就是针对旧 API 行为设计的新 API 语法变了部分用例需要同步更新。这里如果处理不当会出现一个经典陷阱AI 为了图省事直接改测试断言去适应新实现相当于改答案去凑题目这是绝对不可接受的。GitHub 团队的策略是测试文件的更新也必须走人工明确的规则指引。AI 只被允许修改调用方式和构造参数的方式测试断言中期望的结果值不被允许改动。如果新 API 放返回值的语义发生了变化导致既有断言必然失败那就需要人工介入判断——到底是迁移逻辑有问题还是新 API 打破了兼容语义。这个判断已经超出模型能力必须交给熟悉业务的工程师完成。整个过程里我最认同的是他们对模棱两可的零容忍态度。一次 review 中如果出现 AI 某个改动行为原因不明的状况工程师必须追查到底不允许出现这边看起来差不多就行的情况。因为模型生成代码的潜在缺陷往往是系统性的放掉一个模糊点可能意味着同一模式已经在几十个文件中潜伏着。4.3 PR 描述与变更记录的隐性价值128 个 PR 的合入不只是代码层面的变更它还制造了一份极其完整的迁移文档。每个 PR 的描述里记录了改动背景、涉及的服务、测试验证方式甚至包括迁移过程中哪些规则被更新过、为什么更新。这份记录的价值在项目结束后才慢慢显现——后续任何人遇到类似迁移问题直接搜 PR 记录就能复现完整的决策链路。另一个容易被忽略的隐性价值是 review 效率的持续优化。项目团队把 review 历史积累产生的常见错误清单整理成了结构化提示词模板越到后面生成的 PR 初始质量越高。从数据上看后期的 PR 平均 review 轮次比初期显著减少一次通过的占比也大幅提升。这充分说明这套生成—反馈—规则更新—再生成的闭环真的在工作而不是靠运气一个个改对的。5. 三周时间线编排快节奏下的节奏感与回撤机制5.1 第一周铺地基跑流程整个项目的第一周并不是大规模产出的时候。公开的一些过程资料显示这一周的核心在于把先导 PR 打磨到可以当范例的程度并把 CI 流水线中新引入的 AI 生成校验步骤全部跑通。同时团队会完成一个关键分工——决定哪些仓库先做、哪些后做并和各个下游业务的 owner 确认迁移顺序。这一步如果省了后面很容易出现PR 合并完某个隐藏下游模块编译失败还要紧急回滚的被动局面。第一周接近结束时项目组通常只合并了少量先导 PR数量可能只有个位数。但所有参与者的信心已经建立起来人力、流程、验证手段全部就绪剩下的事情就是顺着流水线往下推。5.2 第二周批量产出的加速期进入第二周批量生成才真正开启。基于第一周打磨好的样例和规则库AI 开始在多个仓库并行生成 PR。此时每天的产出从个位数迅速跃升到两位数。团队节奏也调整为上午查看机器筛选后失败的任务并快速修复下午集中 review 通过编译与测试的 PR傍晚汇总当天的错误聚类和规则更新清单。这个环节出现最多的并不是代码生成问题而是跨仓库协调。上游仓库的 PR 合入后下游仓库的依赖同步需要时间部分并联任务可能因为等待上游而阻塞。解决方案是把依赖链条长的任务尽量安排在线性通道上串行推进而把相互独立的仓库拆到不同通道并行——调度算法不复杂但需要有人在第一天就把这个依赖矩阵画明白。5.3 第三周收尾与顽固问题攻坚最后一周剩余的工作量逐渐收窄但剩下的任务往往不是之前流水线能轻松处理的部分。这些顽固问题大概有三类第一类老代码中存在大量重复逻辑和死代码AI 在迁移时不知道是应该一并清理还是保持原样。统一约定是不夹带无关重构把清理留到后续专项处理。这个约定避免了很多让 review 争论不休的情况。第二类某些模块的测试覆盖率本身极低AI 改完之后没有足够的测试来验证语义是否真的没变。这种模块只能靠额外的人工审查兜底。每一个这样的模块都需要领域工程师仔细检查 diff 里的逻辑对应关系才能确认迁移安全。第三类三方依赖升级引起的编译链变化超过了 AI 能消化吸收的范围。这种情况下最稳妥的办法不是逼 AI 硬扛而是把这类情况单独拎出来走传统的人工升级路径留到项目之后另行解决。这个收尾阶段让我最感慨的一点是项目方没有为了追求100%由 AI 完成这个 KPI 而死撑。能由 AI 批量处理的部分大规模自动化不能的则坦率地交给人工。三周完成 128 个 PR 固然亮眼但真正健康的度量指标是在当前约束条件下系统达到了最优的自动化覆盖率而不是所有改动都必须由 AI 生成。5.4 进度度量的三个关键信号整个项目周期的进度不是靠PR 合入数量单指标推动的团队还同时盯着另外两个信号信号一编译失败率的变化趋势。如果随着规则库越来越完善、参考样例越来越丰富编译失败率应该持续下降。如果某天失败率反而反弹通常意味着新接触了一个之前没见过的 API 变体需要专门补规则。信号二人工 review 的非机械性意见占比。机械意见比如格式、命名、基本接口签名错误占比越高说明规则还应该继续沉淀机械意见减少、非机械性意见增多说明 AI 已经把能学的都学到了剩下只剩真正需要人判断的部分。信号三延期任务的 reason 分布。每周任务没能按时合入的原因如果是上游依赖未就绪这类协调问题说明调度策略还有优化空间如果集中出现在测试断言语义冲突则说明业务逻辑的迁移路径本身没设计好。这三个信号组合起来可以清晰判断项目进行到哪了、接下来重点是哪里。单纯盯着 PR 数量只会让人在顺境中盲目乐观逆境中慌忙救火。6. 这套玩法能复制到哪一步规模、条件与分批推进的思路6.1 不是所有代码库都适合 AI 批量重写写到这里必须给跃跃欲试的读者浇一盆客观的冷水GitHub 的成功建立在几个相对苛刻的前提之上。复制这套方案前建议先对着这个清单自查代码库的依赖关系是否清晰可解析模块边界含糊、大量循环依赖的代码库AI 生成的迁移很容易让问题雪上加霜。测试套件覆盖率是否足够至少核心路径要有较高覆盖。没有自动化验证兜底AI 的大规模产出就约等于往生产环境扔炸弹。存量代码是否已经在稳定运行如果代码库本身处于频繁的业务迭代之中迁移过程中不断有新改动汇入会让 AI 的上下文包迅速过期生成的 PR 大量作废。团队是否有足够的 review 人力储备128 个 PR 背后的 review CPU 消耗是巨大的小团队如果一边做业务一边处理这堆 PR大概率会被拖垮。6.2 小规模团队的简化版复刻规模小一点的团队未必用得上 128 个 PR 这种量级但完全可以借鉴其核心思路做一个简化版把目标从一个庞大的代码库收缩到一个具体的服务模块或一类有明确图纸的 API 接口迁移。先人工做一个标准样例 PR让 AI 照猫画虎批量生成后续改动。每一批生成结果都走同一套编译校验 测试验证 人工抽查的闸门。不需要严格的 83 万行目标哪怕只是把几千行四处散落的废弃调用点改干净也能体会到这套流程和几个工程师没日没夜手动改之间的效率差异。技术选型上GitHub 官方文档和技术博客里提到他们主要使用了内部的代码生成基础设施配合自家 Copilot 的能力。中小团队没有这种基础设施也不影响主流的几个 AI 编程工具都支持多文件编辑、批量提交可以在有限上下文的约束下完成类似的任务编排。核心还在于流程设计——怎么拆任务怎么定规则怎么验证结果。工具永远是辅助流程才是保障。6.3 与现有研发流程的融合方式最后一点想单独展开因为它被很多人忽视了AI 重写代码这事不是开一个三周临时项目干完拉倒这么简单。它最好能嵌入到团队常态化维护工作的节奏里。比如依赖升级这类反复出现的任务可以在每次升级时都跑一遍样例 PR AI 批量生成 CI 验证的流程而不用每次都当做大项目来立项又比如AI 生成过程中的规则库和错误清单可以沉淀为团队内部的知识库无论哪一轮迭代都能复用。GitHub 这次项目最深远的意义恰恰在于它验证了这种模式的稳定性真正让AI 不是一次性帮手而是持续参与代码维护协作的环节从口号变成了被验证过的实践。从这个角度回看整个项目衡量它的标准不应该只是 128 个 PR 或 83 万行代码而是一整套可被移植、可被迭代、可被复用的工程方法论。
返回列表