☰
AI重构83万行代码:GitHub三周128个PR的工程化实践
2026/9/28 21:51:34 网站建设 项目流程

最近技术圈被一个数字刷屏:GitHub 让 AI 重写了自己的代码库,三周时间,128个PR,83万行代码。消息传出来时,很多人第一反应是“又是 AI 吹牛”,但仔细扒完技术细节后我发现,这恰恰是 AI 编程落地最该有的样子:不是让 AI 自由发挥,而是把它塞进一套严格的重构流水线里,让机器做体力活,人做决策。这套打法非常适合那些被历史代码拖住、想做大规模迁移却没胆量动手的团队。

80万行这个量级,放在任何一家公司都不是小工程。如果让开发团队人肉去改,光是评审和冲突处理就可能拖上两三个月。GitHub 这个案例的价值不在于“AI 写得快”,而在于它展示了一套从任务拆分、代码索引、自动生成 PR 到质量闸门、人工审查的完整闭环。这篇文章我把这套闭环拆开来讲,重点说不清不楚的部分其实是哪里、128个PR怎么设计、哪些步骤可以直接抄到自己的仓库里。

1. 三周83万行,本质上不是“AI写代码”而是“AI做存量替换”

1.1 重写的对象:不是新功能,而是“历史包袱”

很多人看到“AI重写”就会以为是大模型凭空生成了83万行新代码,这其实是一个误区。真实的大规模重构项目,目标几乎都是同一个:把已经存在的、能跑但不好维护的代码,迁移到约定的目标状态。写新代码是创造性工作,AI现在最多帮你打个底;但替换旧调用、统一工具函数、迁移 API、调整目录结构,这些是重体力劳动,规则明确、重复度高,恰恰是大模型最擅长的事。

举个例子就明白了。假设你的旧代码库里到处是old_send_email()这个函数,新代码库统一改成了notifier.send(),参数顺序还变了。人工操作时要做的是:先全局搜出所有调用点,逐个判断上下文,再按新签名改写,然后跑测试看有没有漏网之鱼。这个过程枯燥、易错、耗时间,而且数量一旦上到几千处,人脑就会开始疲劳漏改。LLM不会疲劳,你给它明确的映射规则,它就能照着清单批量执行,给它的上下文越大、规则越清楚,输出越稳定。

所以这个项目的本质,是把“语义等价但不符合当前规范”的老代码,用 AI 批量替换成“语义等价且符合新规范”的新代码。行为不变,表达变清晰。这个目标决定了后面所有流程设计:每一处改动都必须能被验证,必须能回滚,绝不能出现“AI顺手改了业务逻辑”这种事。

1.2 128个PR的拆分逻辑,为什么不是1个巨型PR

83万行如果堆在一个PR里,哪怕是AI写的,也没有任何人敢点Merge。代码评审、CI验证、回滚定位全部会瘫痪。GitHub 的做法是把它拆成128个可独立合入的PR,这背后不是拍脑袋,而是有一套拆分原则。

拆分的核心不是按“行数”,而是按“风险边界”。一类典型的拆法是按目录拆,比如src/billing/作为一组、src/auth/作为一组;另一类拆法是按“迁移模式”拆,比如“所有旧邮箱服务的调用”归成一个PR,“所有缓存客户端切换”归成另一个。这样做有四个直接好处:

第一,错误能快速定位。某个PR合并后线上出问题,回滚这个PR就行,不会波及83万行。第二,CI压力可控。128个PR同时跑测试和128万个文件同时跑测试完全是两码事,小批量能让失败集中在局部,排查成本低。第三,评审可以并行。每个模块的负责人只要看自己负责的那几个PR,不用理解整个代码库。第四,适合渐进式验证。先合入低风险的PR,观察监控指标,确认安全后再合下一批,三周不是一口气冲完,而是每天推进若干个“小确信”。

128个PR听上去很多,但平均下来每天也就是8个左右,周末可能不跑,每个PR大概覆盖几千行改动,是一组人类Reviewer能在一小时内看完的体量。这个节奏既压不死人,又能保持每周可见的推进速度。

1.3 人机分工:AI负责执行,人负责定规矩

这次重构最打动我的一句话是“AI提议,人决策,机器验证”。AI在整个流程里干的活是扫描、初稿、替换、自我检查;人干的活是定义目标规则、划定改哪些文件、审查高风险diff、处理语义冲突。两者之间没有模糊地带。

人不能在一开始就“让AI随便看看仓库哪里可以优化”。那会产生大量无法归类的变更,Reviewer根本无从下手。正确的姿势是:人先把迁移规则写死,比如“所有old_api调用都换成new_api,参数顺序按照映射表转换,不允许动其他代码”,然后AI只在这个框架内执行。等于说人先画好施工图纸,AI是拿着图纸的施工队。这也是很多团队用AI做重构失败的原因——他们把AI当成了“建筑师”,结果AI交还给你一堆风格混乱、超出预期的东西。

反过来,AI也承担了大量人做不好的工作:检索全部调用点、保持风格一致、同时处理成百上千个文件而不遗漏。“人定边界、AI执行、测试兜底”这个闭环一旦跑起来,三周83万行就不再是天方夜谭。

2. 支撑128个PR的工程底座:代码索引、自动流水线与质量闸门

2.1 代码索引与上下文管理,AI必须“看得到”整个仓库

大模型不是数据库,你给它一个仓库链接,它并不会自动知道里面有什么。要让AI在83万行代码里精准干活,第一步是给AI建立“施工清单”。

我在类似项目里的做法是,先写脚本扫描整个代码库,把所有需要改动的位置提取出来。具体来说可以用 tree-sitter 解析每份代码的AST,也可以用简单的 grep/RG 正则搜索把所有old_api的调用点捞出来,然后聚合成“文件路径 + 行号 + 周围上下文”的索引条目。这个清单就是AI的任务输入,它不需要理解整个仓库,只需要针对每个清单项,读取对应的文件片段并做出替换。

在这里要注意一个关键约束:模型的上下文窗口是有限的。83万行不可能一次性喂进去,哪怕是128个文件也要分批。所以我的策略是“一次只让AI看一个文件或一组强关联文件”,把仓库的整体结构、目录说明、依赖关系用一段很短的prompt告诉它,剩下的靠代码自己说话。为了让模型不乱看,我还会把无关区域压缩成占位注释,比如// ---- 本段无需修改 ----,这样既减少token消耗,也大幅降低AI“顺手美化无关代码”的概率。这个技巧在批量重构中非常有效。

2.2 自动PR流水线:从“AI输出代码”到“合法PR”的最后一公里

AI生成完代码之后,最难的不是生成本身,而是怎么把生成结果安全地变成Pull Request。我在实践中总结下来,这一步必须有完全自动化的流水线,否则你将会成为手工搬运工,每天开分支、提交、建PR、填描述,累到怀疑人生。

GitHub生态提供的底座是 GitHub Actions + GitHub CLI(也就是gh命令)。我们可以用workflow_dispatch手动触发一个“重构批处理workflow”,这个workflow接收一个参数,比如批量大小,然后执行归档脚本。脚本流程大致如下:

name: ai-refactor-pipeline on: workflow_dispatch: inputs: batch_id: description: 'refactor batch id' required: true permissions: contents: write pull-requests: write jobs: generate-pr: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Run AI refactor batch run: | python scripts/run_ai_refactor.py \ --batch-id ${{ inputs.batch_id }} \ --config configs/email-migration.yaml - name: Commit changes run: | git config user.name "ai-refactor-bot" git config user.email "bot@example.com" git checkout -b refactor/${{ inputs.batch_id }} git add . git commit -m "refactor: migrate email sender APIs in batch ${{ inputs.batch_id }}" - name: Create Pull Request env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh pr create \ --base main \ --head refactor/${{ inputs.batch_id }} \ --title "AI refactor: batch ${{ inputs.batch_id }}" \ --body "本PR由AI重构流水线自动生成。变更范围:email sender迁移。请保持原有业务逻辑不变,只做API替换。" \ --label "ai-generated"

为什么用workflow_dispatch而不是push事件?因为重构流水线是你主动控制的批量操作,如果每推一个分支就触发一次,很可能出现“AI还在改文件,workflow又跑起来”的循环爆炸。手动触发给足控制权,随时可以暂停、调整参数、批量撤回。

同时要注意GitHub的API速率限制。并发跑几十个任务时,gh操作很容易撞上限制。我在脚本里给每个任务之间加了随机延迟,并且把并发控制在3到5路,不但稳定,CI也扛得住。

2.3 质量闸门:没有这些检查,AI写的东西不能合进去

自动生成PR只是第一步,能不能合入还得看质量闸门。这套闸门我在工程上一般设四层:第一层是格式化和lint检查;第二层是单元测试;第三层是类型检查或构建;第四层是针对核心模块的语义对比。所有检查都必须由CI跑完,任何一层红了,PR都不能动。

GitHub的CODEOWNERS文件在此时非常有用。你可以把它简单理解成“不同目录的变更由哪些人负责”,例如:

# .github/CODEOWNERS src/billing/** @billing-team-lead @billing-reviewer src/auth/** @auth-maintainer src/experimental/** @core-infra-team

这样AI创建出来的PR会自动分配到对应模块的负责人名下,不需要人工去群里喊“谁来审一下”。每批PR生成后,我还会用一个异步任务去扫描全部PR的状态,凡是CI失败的就自动重新触发一次修复流程;这样AI生成的代码首测通过率可以从60%左右拉到90%以上。

对于高风险目录,我会用规则阻止自动合并。比如billing或者账号安全这类模块,PR必须加上awaiting-human-review标签,只有人类Reviewer点了Approve并且CI通过,才允许合入。低风险的纯机械性替换则可以开启gh pr merge --auto,让测试一过就自动合并。这个分层设计非常重要:不是所有AI PR都需要人类盯着,但关键路径必须盯死。

3. 实操过程:从0到128个PR,关键环节逐段拆解

3.1 任务书模板:给AI的一次性清晰指令

很多人让我看他们用AI做批量重构,失败的原因一般不是模型太笨,而是任务书写得像个白日梦。一套可复用的任务书至少要包含角色、目标、输入、约束、输出格式、自检要求。下面这份模板我会直接抄进项目里,你可以根据自己的迁移类型微调:

【角色】你是一名资深代码重构工程师,负责将一个大型代码库中的旧API调用迁移到新API。 【任务】把输入文件中的所有旧API调用替换为映射表中对应的新API调用。 本批任务只处理文件中的函数调用和参数顺序,不改变任何业务逻辑。 【输入文件】 {file_content} 【API映射表】 - old_api(a, b) -> new_api(a, b) - old_api(a, b, c) -> new_api(a, c, b) // 注意新API把c参数提前了 【约束】 1. 只允许修改与API调用直接相关的代码行。 2. 禁止调整缩进、注释、空行和无关代码。 3. 如果某个调用在映射表中找不到,请保持原样,并整理到“未匹配列表”。 4. 所有参数必须是字面量或变量原样传参,不得做任何推导计算。 【输出格式】 1. 完整的新文件内容。 2. 一个JSON数组,列出每一处替换的位置和规则编号。 【自检】 请输出前统计:本文件中可疑的旧API调用多少次?其中已经匹配的有多少次?

每一行都是有原因的。第3条约束尤其关键,它防止模型遇到没见过的调用时“自由发挥”,而是要求它把不确定项列出来,交给人类处理。自检步骤则让模型在生成前先想一遍“我要改多少处”,能有效提高它的结构化推理能力。

同一套任务书不能用于所有场景。改日志库的任务书和改ORM迁移的任务书,约束完全不同。我的经验是每种迁移模式固化一份模板,比如email-sender-migration.txt、cache-client-migration.txt,谁用谁取,而不是每次重新写提示词。

3.2 扫描、分批、执行:调度细节与并发控制

拿到任务书之后,主流程分四步走:扫描影响面、划分批次、批量生成、自动提交PR。

扫描时我会先跑一个脚本,把所有匹配旧模式的调用点按文件聚合成清单。假设仓库里有600个文件受影响,我不会一次性生成600个PR,而是按目录或按依赖关系分到128个批次里。为什么不能一个文件一个PR?因为有可能6个文件都是被同一套重构逻辑影响,你拆成6个PR,每个PR都只改一点点,Reviewer反而要重复理解同一套背景,纯属浪费。

划分批次后,调度器从清单里依次取出文件,拼上任务书,发送给大模型。并发数我控制在3到5路,太少了赶不上三周完成,太多了AI输出质量和CI稳定性都会崩。每一路生成完,脚本先做一次“静默校验”:检查diff里是否存在任务书禁止的改动,比如无关缩进变化、注释翻译、新增空行。校验不过的自动退回重试,重试仍不过的丢进人工异常队列。

我建议所有批量生成都先开dry-run模式跑一轮。也就是说在正式建PR前,先只生成diff,输出到一个独立目录里,挑10个PR粗看一遍。这一步能尽早暴露任务书里写漏的匹配模式,否则128个PR全部生成后发现规则错了,代价非常可怕。

3.3 冲突处理和二次重试:并行BF对撞的真实较量

并行PR最大的隐患是冲突。你不可能让80个AI agent同时改代码而不碰撞。我的策略是在源头上尽可能错开:同一模块或同一文件的改动尽量放进同一个批次里,不改同一文件的PR可以大胆并行。这样真正发生的冲突大多是“两个PR合入后,在语义层面互相影响”,而不是机械的行级冲突。

机械冲突一般用GitHub的 “Update branch” 功能就能解决,点了之后自动rebase到最新main,如果是简单的增删行,Git能自动merge。麻烦的是语义冲突:PR A把函数foo()改名成了bar(),PR B又新增了20处foo()调用,两个PR各自跑测试都绿,合到一起之后直接编译失败。这种问题没有完美的自动化解法,我能做的只有两点:一是保持每个PR改动范围足够单一,二是每合入一批PR后,在聚合分支里跑一次全量测试。

重试逻辑也得设计好。AI生成的代码第一次不过CI,最常见是小毛病:少导入一个包、变量名拼错、忘了改调用点。我在脚本里配置了“最多重试两次”规则,每次都把CI错误信息喂回给模型,让它基于报错修正。跑完两次还失败的PR,直接标记为needs-human-fix,不再浪费计算资源。别指望AI一次成功率能到99%,真实跑下来,一次通过率在70%左右很正常,加上自动重试能到90%以上,剩下的10%才是人类的价值。

4. 避坑手册:84万行改下来,最容易踩的五个坑

4.1 AI“过度发挥”:任务书约束不住怎么办

比起漏改,更让人头疼的是AI“爱干净”。它会在你只让它改API的地方,顺手把整个文件夹的格式改成它觉得好看的样子。这直接污染diff,让审查者找不到重点。解决的办法除了任务书里写死“禁止调整格式”之外,最有效的是做“diff白名单校验”。

我习惯在生成PR前用AST做一次对比:旧代码的AST和新代码的AST,除了规则中允许的节点变化外,其余任何节点发生变化就判定这个PR不合格。比如只允许调用表达式层面的替换,那FunctionCall节点的变化在允许列表里,但ImportDeclaration的变化就必须被拦截。这个自动化检查比任何prompt都硬,直接从机器层面锁死AI的自由发挥空间。

另一个实用技巧是“隔离提示”。给模型喂文件时,把不需要改动的函数体替换成/** 不需要修改,仅供阅读上下文 */。这样模型在生成时,注意力会被引导到真正需要改动的区域。实测下来,这种方式能够明显减少“额外惊喜”。

4.2 CI集群被128个PR打爆

128个PR同时push,CI runner瞬间排队,这是工程上一定会遇到的问题。我第一次跑类似项目时,CI排队时间甚至比AI生成代码的时间还长,直接拖垮进度。

解决方案分三层。第一层是限制并发PR数量,我前面说的3到5路就包含这个意思。第二层是在workflow里配置concurrency,让同一时刻只有一个重构任务在跑CI,避免互相挤占资源。第三层是分组处理失败,如果出现“某测试文件大面积失败”,先怀疑公共依赖是不是被改了,而不是一个PR一个PR地修。

真正节奏是“推挤前进”:一批PR在跑CI,另一批PR已经推送完成等在队列里,人只处理需要决策的反馈。每天下班前清空一次失败队列,第二天早上集中看合并结果,三周时间就是这么一点一点挤出来的。

4.3 代码审查者如何“看得过来”

人类Reviewer一天看几十个PR,每个PR几千行,上线早就炸了。我的做法是强制每个AI PR自带“变更摘要”和“审查指引”。生成PR时,脚本会自动统计这份diff里有多少处替换、涉及哪些文件、有无未匹配项,然后把摘要填到PR描述里。Reviewer可以先读摘要,再决定要不要深入看diff。

GitHub的diff页面有一个非常实用但不被很多人注意的功能:URL后面加?w=1可以忽略空白字符差异。纯改API的PR,白空差异一忽略,很多“假改动”就消失了,真正要看的逻辑变化一眼就能扫完。同时,把“高风险目录”和“低风险目录”分开排队。低风险目录的PR用自动合并,只要摘要没问题,测试通过就合;高风险目录集中留给人类精力最充沛的时间审。

我在项目里还加了一个“回复超时提醒”,24小时内没有approve或comment,就自动在频道里提醒。评审不能成为瓶颈,否则前面所有自动化建设都白费了。

4.4 衡量重构成功,不要只看83万行

这个项目最容易被外行误解的地方,就是拿“83万行”作为成果。行数只是过程产物,真正应该看的是四个指标:合并效率、回归缺陷数、变更纯净度、人工审查成本。合并效率,比如平均每天合入多少个PR;回归缺陷数,指重构上线后一周内因为这次改动引入的bug数量;变更纯净度,即diff中跟任务书无关的改动行数占比,正常应该控制在5%以内;人工审查成本,即每个PR平均需要多少review时间。

用这四个指标复盘,能清楚回答一个关键问题:AI到底有没有帮团队省时间?如果合并效率上去了,回归缺陷没有增加,人工审查时间还控制在可接受范围,那这套流程就值得继续投入。反过来,如果一次重构造成大量回归,哪怕PR数量再漂亮,也只是把问题从“开发期”挪到了“线上事故期”。

我做过几次类似项目后有个很强烈的感受:AI重构项目最怕的不是“AI不行”,而是流程没有兜底。任务书不清晰、CI不严格、审查不分优先级,任何一环掉链子,AI生成得越快,团队崩得越快。

最后分享一个实操中的小经验。如果你也要在自家仓库里做这种大迁移,别一上来就想复刻128个PR。先跑一个10个PR的试点,用最小成本把任务书、白名单校验、审查节奏全部调顺,再铺开到全库。你看到的是三周奇迹,看不见的是背后每个PR都被当成一次小项目来对待的耐心。把这套耐心学到了,AI才能真正干重活。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询