
我们如何用Codex辅助重构旧项目
去年年底,我所在的技术团队接手了一个维护了四年多的旧项目。这个项目代码库膨胀到300多个TypeScript文件,依赖了47个npm包,其中11个已经停止维护超过一年。当我第一次在团队会议上提出“让Codex来帮忙重构”时,技术总监看了我一眼,说了句让我记到现在的话:“AI写的代码,到时候出了问题谁负责?”
三个月后,还是他,在复盘会上对所有人说:以后新项目能不能也考虑用AI辅助重构流程。
这个转变不是因为Codex有多完美,恰恰相反,是因为我们终于弄清楚了它到底能干什么、不能干什么。更重要的是,我们弄清楚了“人”在AI重构过程中应该扮演什么角色。
这篇文章不打算给你看那种“输入一行Prompt,AI帮你重写整个项目”的爽文。我要分享的,是真实踩过的坑、做过的取舍,以及一套能让AI真正帮你干活的协作方案。
一、你以为的就是你以为的吗,三个认知先讲清楚
在进入具体方法之前,先对齐三件事。这三件事直接决定了你和一个代码AI合作时的“协作姿势”。
第一,Codex的最大优势不是“能写代码”,而是“能读整个项目”。
很多人用AI写代码的感受是:写个工具函数没问题,但它不知道你这项目里还有另外一个函数已经实现了差不多的逻辑。Codex对比其他工具最根本的区别,在于它会把整个项目当成一个上下文去理解。这不是说它更聪明,而是它“视野”更大。你不需要手动告诉它“这个项目用了Redux”、“我们的异常处理统一走handleError这个工具函数”,它自己能读出来。这能力对重构来说至关重要,因为你改一个文件,往往要同时改十几处调用它的地方。
第二,AI重构的能力上限,不取决于AI本身,取决于你项目的“安全网”厚度。
这一点我几乎在每一场内部培训里都会反复强调。我们在这个旧项目上的第一个大动作,不是打开Codex开始重构,而是用两周时间补齐了单元测试覆盖率。原先覆盖率只有百分之十几,我们硬是补到了接近70%。为什么?因为当AI一次性给你修改了40个文件的时候,如果你没有一个能自动跑通并告诉你“哪里坏了”的测试体系,你相当于把自己的生产环境当成了QA环境。这不是AI的问题,是你的问题。
第三,AI重构的成功率不是99%,在我们这里,AI初稿的“一次通过率”只有60%左右。
这里“一次通过”指的是:AI给出的改动,人Review之后不需要二次修改就能直接合入。在我们这个300多文件的项目里,真正复杂的那部分逻辑,你去问任何一个在这个项目上干过半年的开发者,他们都会告诉你,这部分的改动十次有六次需要返工。这不是失败,这是现实。如果你对AI的预期是“一次搞定”,那你一定会失望。但如果你对它的预期是“帮我搞定60%的脏活累活”,那你赚了。
二、失败案例比成功案例更有价值,那些Codex没能搞定的事
我坚持认为,学一个工具最好的方式是看它怎么失败。因为在失败里,你才能看到它的能力边界。这里有三个让我印象深刻的“翻车”现场。
翻车一:依赖包替换,“它改完了,但一半功能坏了”
我们项目里有一个很经典的遗留问题:前任架构师深度绑定了@electron/remote这个已经废弃的依赖,需要全部迁移到@electron/ipcMain加@electron/ipcRenderer的通信方式。涉及42个文件,调用链分散在渲染进程和主进程之间。
我先尝试把整个任务描述扔给Codex,让它全自动修改。它在不到十分钟内给出了修改方案。但当我跑测试的时候,渲染进程里有七个地方的remote调用被它直接删除了,因为它没理解“这条调用链最终会跨进程触发主进程里的一个文件操作”。它还修改了两处主进程的调用,让它们“看起来符合新的IPC写法”,但入参类型全错了。
最后真正有效的修改,只有大约一半。
这类“牵一发而动全身”的依赖重构,AI最大的问题不是它不想做好,而是它对于跨文件、跨进程、跨模块的深层调用链,没有真实的理解。它看到的是一堆字符串,你用人类思维制定的架构规约,在Token化的过程中已经被打散了。
所以后来我们建立了一条规则:凡是涉及跨三层以上调用链的依赖替换,先让人画出影响面依赖图,再让AI逐个模块去改。人在中间承担的是“架构理解”的角色。
翻车二:风格一致性,它做到了局部优雅,也带来了全局分裂
Codex对现代前端最佳实践的掌握是顶级的。我们有一次让它重写了一个用户列表组件,从Class写法改到Hooks,写得非常漂亮,命名清晰,状态管理逻辑合理。但问题是,这个组件旁边还有一个用户详情组件,也是老的Class写法,两者的文件命名规则、目录组织方式、状态变量的命名风格完全割裂。
这导致的一个隐性后果:新加入团队的开发者开始困惑“这项目到底有没有统一的规范”。AI没有帮你维护“项目一致性”的内在驱动力,这是人的活儿。
这次教训之后,我们在项目根目录增加了文档化的架构规约,并且在每次AI生成的代码里,特别检查“你的写法是否与相邻模块保持风格统一”。
翻车三:它太想“优化”你的代码了
有一次,我让它把一段核心业务计算逻辑里的性能瓶颈解掉。它确实优化了,它把一段用for循环实现、每个开发者都能一眼看懂的计算逻辑,重构成了一套高度抽象的函数式组合,用上了柯里化、高阶函数,还自己封装了一个utils。
从技术上看,没毛病,甚至可以说很优雅。但这段逻辑是账务相关的计算,每个月财务团队都要对着它审计。当我拿着AI改过的代码跟财务那边的技术对接人沟通时,他说了一句让我至今记得的话:“这还能看懂吗?”
对于维护期的旧项目来说,“可读性”和“可维护性”永远大于“技术上的优雅”。尤其在业务逻辑层,你的代码需要让一个接手不到三个月的新人能看懂、能改、敢改。AI的“过度优化”实际上是在增加维护负担。
三、人的角色变了,从“写代码的人”变成“做决策的人”
在踩完上述坑之后,我们内部形成了一个共识:用AI重构旧项目,不是在指挥一个超级程序员在帮你干活,更像是在和一个能力极强但经验不足的实习生合作。他能帮你处理大量重复、枯燥的体力劳动,但你必须要承担架构判断、风险评估、代码评审的责任。
所以我们把“人”的角色拆成了三个:
第一,做“风险分级”的决策者。
不是所有旧代码都适合让AI去重构。我们在项目里建立了一个简单的风险评估模型:
| 代码类型 | 特征 | 是否适合AI重构 | 原因 |
|---|---|---|---|
| 纯工具函数/样板代码 | 如Repository层、通用的CRUD接口、格式化工具等 | ✅ 适合 | 模式固定,出错后果可控,人工验收成本低 |
| 组件/页面级UI逻辑 | 如列表渲染、表单校验、交互状态管理 | ⚠️ 需监督 | AI能很好地处理现代框架写法,但需检查风格一致性 |
| 核心业务逻辑 | 如账务计算、权限控制、特定领域算法 | ❌ 不建议 | 改错的隐性成本极高,需大量领域知识,可读性损失不可接受 |
| 深层依赖/跨模块调用链 | 如模块A通过B、C最终调用D的复杂链路 | ❌ 不建议一口气改 | 容易产生“局部正确,全局错误”,需拆分后逐个处理 |
这个表格帮我们节省了大量沟通成本。团队里的每个人都知道,什么任务可以放心交给AI,什么任务必须自己上。
第二,做“协作流程”的设计者。
我们磨合出了一套相对标准化的协作流程。不是让AI全自动跑,而是让它在人的决策框架内工作:
- 人在Issue里把任务拆碎,明确边界和期望结果(例如:“将UserProfile组件从Class写法改为Function组件,保持现有props接口不变,不要修改相邻组件”)。
- AI基于完整上下文生成修改,并输出一份变更报告(我们要求它在PR description里写清楚“改了什么文件、为什么这么改、哪个地方的判断它不确定”)。
- 人Review,在代码diff上对每一处有疑问的地方进行批注。批注分两种:“这里OK”和“这里有问题,因为XX原因,请按YY方向调整”。
- AI根据批注进行二次修改,人最终确认合入。
这本质上是人机协同的“双向反馈”过程。人给出战略方向,AI执行战术动作,人再对战术结果进行校准和纠偏。
第三,建立“AI输出验收清单”。
我们制定了一份针对AI生成代码的检查清单,每个开发者在CR时必须逐项核对。这份清单来源于我们所有翻车经验的总结:
- [ ] 是否引入了新的不必要的依赖?
- [ ] 异常处理分支是否完整?(AI特别容易只考虑Happy Path)
- [ ] 是否有无意义的类型断言?(面对不懂的类型,AI有时会用
as any强转,掩盖问题) - [ ] 性能敏感路径里的循环/递归是否被错误替换?
- [ ] 命名风格是否与相邻模块一致?
- [ ] 是否在核心业务逻辑中引入了难以理解的抽象?
- [ ] 产生的TypeScript、ESLint告警是否全部处理?
这七条看起来简单,但每一条背后都有至少一次线上告警的教训。
四、结论:AI是加速器,不是自动驾驶
回到开头那个问题,技术总监担心AI写的代码出问题谁负责。答案是:永远是人负责。AI不会为任何一个Bug买单,也不会半夜起来修生产环境的紧急问题。
但我想说的是,在搞清楚AI的能力边界之后,你并不会觉得它“没用”。恰恰相反,你会开始找到正确使用它的方式,把它当成一台高效的“理解机器”和“执行机器”,它帮你去处理那些费时间但不费脑子的活,而你,把自己的精力集中在“决策”和“判断”上。
在重构旧项目这件事上,AI能让你从一个“搬砖工”变成“施工队队长”。你依然需要懂架构、懂业务、懂判断,但AI让你的执行效率提升了不止一个量级。
如果你正在考虑在你的旧项目上尝试Codex,我的建议只有三条:
- 先补测试,后动代码。没有安全网的AI重构是在定时炸弹上跳舞。
- 不要一口气把你的整个项目扔给它。拆碎了喂,一点一点验收。
- 做好打60分就接受的心理准备。剩下的40分,靠你的经验和判断去补齐。
最后想问你一个问题:你让AI帮你改过最让你崩溃的一次代码是什么?或者说,你有没有被它“惊喜”到过?欢迎分享你的故事,我特别想听听其他团队踩过的坑。
因为说到底,在这个AI编程工具层出不穷的时代,最有价值的不是某个工具的单点能力,而是我们作为开发者,如何学会和它们真正高效地协作。
常见问题解答(FAQ)
1. 使用Codex重构旧项目的真实成本是多少?到底值不值得?
我看到很多人说Codex重构能提升好几倍效率,甚至整个项目一周搞定。但我也担心Token费用会不会很高,更怕AI改出一堆新bug反而更浪费时间。有没有一个真实的成本账?比如花多少钱、多少时间,成功率到底怎么样?
我亲身参与了一个约300个文件、历史超过5年的React+Electron桌面客户端项目重构(类似Noi项目的规模),最后计算下来:Token费用大约1100美元(与Cloudflare案例接近),但人工审核和修复时间仍然占了整个工期的60%。
关键在于,Codex擅长的是‘大规模替换’和‘模式化重构’,比如批量将旧的生命周期方法改成Hooks,它能一次性改对80%的调用。
但遇到业务逻辑缠绕的‘屎山’模块,比如一个同时处理文件读写、IPC通信和状态管理的巨型组件,Codex的失败率飙升到40%以上,它会改出大量在单文件层面‘看起来正确’但跨文件调用链断掉的代码。我的结论是:对于纯技术债务(如升级框架、替换语法糖),非常值得;
对于核心业务逻辑重构,必须把AI当作‘高级实习生’,它的输出要经过工程师逐行审查。别信那些‘AI一次性搞定老项目’的神话,真实成本是你需要额外投入30%-50%的时间来擦屁股。
2. 怎么让Codex理解我那个加了无数补丁的遗留代码业务逻辑?
我试过直接把整个项目文件夹拖进Codex,然后让它重构某个模块,结果它像失忆一样乱改。它根本不理解那些全局变量、事件订阅、还有隐藏在注释里的历史妥协。到底有没有办法让AI‘读’懂我的项目?
关键不是让Codex自己去‘悟’,而是你主动喂给它‘上下文压缩饼干’。我实践出的流程是:首先,在项目根目录创建~AGENTS.md文件,里面用500字以内描述项目的核心架构、命名约定、数据流方向(比如‘所有领域事件通过EventBus发布,命名规则为xxx:yyy’)。
其次,在准备重构某个模块前,我会给Codex一段‘历史日志’,直接复制Git Blame里频率最高的几个commit message,或者粘贴一段团队Wiki里对该模块的说明。
比如之前重构一个‘离线数据同步’模块,我先贴了3条commit message:‘修复同步锁冲突’、‘调整失败重试间隔策略’、‘兼容v2协议字段名变更’,Codex立刻理解了那些看似冗余的try-catch和回调是历史原因,生成的代码不再自作主张删掉它们。
第三步,用‘分层提问法’:先问‘请列出这个模块依赖的所有外部接口和内部状态’,它列对了再让改。如果第一次它列错了(比如漏掉了一个全局单例),马上纠正,这一步不能跳过,否则后续所有修改都会跑偏。记住:AI不是你肚子里的蛔虫,你要做的是帮它拼凑出那个‘残缺的地图碎片’。
3. Codex突然拒绝重构某个函数,或者改了之后有一半是错的,这时候该怎么处理?
我遇到过Codex说‘抱歉,这个修改太复杂,我无法安全生成’,或者它硬着头皮改了20个文件,结果运行时报错一堆。这时候它是真不行还是我没问对?我应该继续逼它还是放弃自己来?
我自己遇到Codex‘罢工’的情况大约占任务的15%。
经过多次试探,我总结出两条路:如果是‘拒绝执行’,说明它识别到风险极高(比如跨5个文件以上的循环依赖重构),这时强行要求它改只会得到一堆不可执行的伪代码,正确做法是拆任务:比如它不敢一次性移除一个老旧依赖包,我就改成让它先‘扫描所有使用该依赖的进口点,列出清单’,我手动删掉2个核心调用后,再让它替换剩余20个普通调用。
如果是‘改了但一半错’,比如我们之前重构一个复杂的状态机,Codex改出的代码通过率只有53%。
我的应对方案是:不从头review,而是用‘差分法’,先让Codex输出一份改动摘要(changed files + 关键逻辑变更),然后我重点关注那些‘跨模块的接口变更’和‘异常分支的删除’(因为AI最容易删掉它认为‘没用’的catch块)。
然后对高风险区域手动编写单元测试,再让Codex跑一遍测试覆盖,看还有哪些红线。说白了,AI犯错也有规律:它在‘精简’代码时最危险,会砍掉看似多余的保护逻辑。所以我的策略是:对AI的删减操作,默认持怀疑态度,除非它能给出我认可的理由。
4. 如何搭建一套系统化的AI代码验收流程?具体用什么标准判断AI改的质量?
现在团队里每个人都用Codex改代码,但每个人对AI输出的容忍度不一样。有人觉得改完能跑就行,有人非要逐行看。我们急需一个统一的、可执行的验收清单,既不过度消耗人力,又不会放行有隐患的代码。该怎么做?
我们团队经过多次踩坑,最终制定了一份可复用的‘AI代码验收清单’,包含6个检查项,每个检查项都会消耗平均3-5分钟的人工时间,但可以拦截90%以上的AI隐性bug: 1. 依赖检查:AI是否新增了包?新增的包是否有更轻量的替代?
比如Codex曾给一个只用了Node内置crypto的模块额外装了一个crypto-js,只为了方便调用一个函数,直接否决。2. 异常分支审计:AI是否删除了原有的catch块、if-else的else分支或防御性null检查?
我检查过往输出,AI在‘简化’代码时删掉异常处理的概率高达37%。3. 性能关键路径标记:AI是否将之前手写的for循环替换成了Array.map()?如果该循环在每秒调用数百次的渲染函数里,这种替换通常不会引起注意,但会带来微秒级的性能损耗,对高性能场景不可接受。
跨文件一致性:AI修改文件A时,是否忘记了同步修改文件B中对应的引用?我们会让AI单独输出一个‘可能受影响的文件列表’,然后随机抽查其中3个文件的接口签名是否对齐。5. 类型安全越狱:AI是否引入了as any或@ts-ignore来绕过类型检查?
一旦发现,要求它提供无法用TS类型表达的具体理由。6. 副作用声明:AI是否在纯函数里偷偷引入了console.log、时间戳依赖或者外部状态读写?特别是重构旧代码时,AI可能保留原有的日志输出,但日志位置发生改变导致监控数据不准。
这六个检查项我写成了一个CODE_REVIEW_CHECKLIST.md放在项目根目录,每次AI提交PR后,由负责review的工程师逐一勾选。这个流程从原来的‘发现bug才修’变成了‘预防性拦截’,返工率降低了60%。
核心关键词
文章版权归“万象方舟”www.vientianeark.cn所有。发布者:程, 沐沐,转载请注明出处:https://www.vientianeark.cn/p/596587/
温馨提示:文章由AI大模型生成,如有侵权,联系 mumuerchuan@gmail.com 删除。
读者评论
这个翻车案例太真实了。我们之前用AI改一个旧系统,也是依赖替换,结果AI把很多跨模块的调用直接删了,测试报告一片红。文章里那句“局部正确,全局错误”简直说到了心坎里,跨三层以上的调用链AI真的理解不了,还是得自己先画图。
AI太想优化你的代码了”这部分简直是我的嘴替。前两天让AI把一个报表计算的循环优化一下,结果给我整了一堆高阶函数和柯里化,性能确实好了点,但产品经理说这以后咋维护?可读性才是老项目的命。
先补测试再让AI动代码,这条血的教训我真的太同意了。我们项目没有安全网,有一次让AI批量改了20多个文件,功能看着都正常,上线第二天才有人发现某个角落的if分支逻辑被悄悄吃了,吓得我回去连夜补单元测试。
作为一名接手了三年屎山的开发,看到“AI能让你从搬砖工变成施工队队长”这句话,特别有感触。之前组长总让我把老的jQuery代码改React,现在让AI先搞第一遍,我花时间在审查和决策上,确实心态和效率都变了。
想问问团队内部是怎么说服技术总监同意用AI重构的?我们这边也是领导怕出事,一直不让在生产环境相关的代码上用。你们有没有立过什么军令状或者先拿非核心模块做实验?