Codex 自动修 CI:接上 GitHub Actions,挂了它自己改

CI 失败是开发日常里最常见的一件事,处理起来却一点不轻松。老流程走起来是这样一串动作。先收到邮件或者消息通知,再打开 CI 日志逐行看报错。然后切到本地找到出问题的代码,修复提交再推一次。等 CI 重新跑过,确认通过,最后开 PR 等人审查合并。

整条链路全靠人在中间串起来。报错信息不明确的时候还要加一段排查时间,遇上跨时区协作,一个 CI 失败拖到第二天才处理也很正常。接入 Codex 之后,这条链路变成另一副样子。CI 一失败,工作流就自动触发 Codex。它自己读代码,定位问题,修好,开 PR。人只需要在最后审一眼,点一下 Merge。

演示里埋的是一个符号

演示用的是一个小型购物车项目,核心逻辑是计算总价,满 100 减 20。折扣函数里埋了一个 bug,减号被写成了加号。效果是原价 120 元的商品,打完折反而变成 140,越打折越贵。

代码推到 GitHub 之后,CI 自动跑测试,大约一分钟后失败。点进去看报错,测试期望拿到 100,实际拿到 140。错误直接指向折扣计算,非常明确。

让 Codex 介入靠一个工作流文件

仓库里放一个 GitHub Actions 工作流文件,CI 一失败就触发 Codex。它的骨架分四块。

部分 写什么 为什么这么写
触发 监听名为 CI 的工作流,等它跑完再判断结论 只有失败才继续,成功时整个 job 跳过,不消耗资源
权限 contents 和 pull-requests 都设成 write 少了这两条,Actions 开不出 PR
环境变量 失败的分支,提交 SHA 和日志链接,再加 OPENAI_API_KEY 这些信息会写进 PR 描述,方便追溯是哪次 CI 触发的修复
步骤 检出失败代码,装依赖,跑 Codex,验证并开 PR 每一步各管一段

有几个位置值得单独拎出来说。

检出那一步的 ref 指向失败那次的提交 SHA,让 Codex 面对真正出问题的那一版代码。

Codex 修复那一步用官方提供的 codex-action,prompt 用中文把要求写清楚。内容大意是跑一遍测试套件,找到导致失败的最小改动范围,修完即停,不碰无关代码。sandbox 设成 workspace-write,允许它写文件。

改完不能直接开 PR。工作流里再跑一次测试,配合 if 条件的 success() 判断,保证只有测试真通过才会执行开 PR 那一步,避免开出一个还是红的 PR。

开 PR 用 create-pull-request 这个动作。分支名带上这次运行的 run_id,base 指向失败的分支,标题写”Codex 自动修复 CI 失败”。描述里带上失败工作流的名字和日志链接,让人一眼看出这次修复从哪来。描述末尾还会写一句,请检查改动内容,确认无误后合并。

跑起来之后

CI 失败后,配好的工作流自动触发。Codex 做了三件事:读取仓库代码,运行测试套件,定位问题并修改。整个过程大约一分钟。

修好之后工作流变绿,Pull Requests 页面出现一条自动生成的 PR。点进去看它改了什么,就改了一个字符,其他代码一行没动。

踩过的两个坑

第一个坑在权限。代码改好了,开 PR 那一步却报错,提示 GitHub Actions 不被允许创建或批准拉取请求。这是仓库的默认设置,需要到 Settings 里手动打开,开启之后重新触发就正常了。

第二个坑是失败也计费。调试阶段反复触发了几次,最后账单是 0.40 美元。API 按 token 计费,不按成功次数,只要 AI 启动并读了代码,费用就已经产生。正常情况下一次成功的修复大约 0.05 到 0.10 美元,多出来的都是调试成本。稳妥的做法是在 OpenAI 后台设一个月度消费上限。

这条路值不值得走

跑下来验证的是,Codex 通过 GitHub Actions 自动修 CI 这条路真实可用:定位准确,只改必要的代码,修完自动开 PR。

上手之前有两件事要先办。仓库的 PR 权限得手动开,否则最后一步必然失败。API 费用要心里有数,调试阶段的失败同样烧钱。