让 Codex 学会自我纠错:迭代修复循环的工程实践

一次提交就能写好代码?别做梦了#
写代码的人都知道一个朴素的道理:第一次写出来的代码几乎不可能完美。你需要运行它,看看哪里报错,修一修,再跑一遍,再修一修。这个过程循环往复,直到代码真正可用。
那 AI 编程 Agent 呢?大多数人对 Codex 的使用方式是:扔一个任务进去,拿一个结果出来,看看行不行,不行就换个说法再试一次。这种「一次性投喂」的模式,本质上是把人类的迭代思维压缩成了一次性操作。
OpenAI 开发者关系团队的 Shreekant Agrawal 最近在官方 Cookbook 上发布了一篇教程,展示了另一种思路:让 Codex 自己建立一个「审查、修复、验证」的闭环,通过结构化的反馈驱动多轮迭代,直到问题真正被解决。
这不是一个玩具 Demo。它用三个故意写坏的 Jupyter Notebook 作为测试素材,展示了从一轮修复到三轮修复的完整收敛过程。
核心架构:三个阶段,一个闭环#
整个工作流分为三个阶段,每个阶段有明确的职责边界:
审查(Review):读取当前产物,返回结构化的问题清单。这个阶段不修改任何文件,只负责发现问题。问题类型包括过时的 API 调用、缺失的环境配置说明、运行时风险等。
修复(Repair):拿到审查结果和上一轮的验证反馈后,对产物做最小化修改。注意「最小化」三个字,Agent 被要求不要大刀阔斧重写,而是针对具体问题做精准修补。
验证(Validate):执行修复后的产物,检查是否真正可用。对于 Notebook 来说,就是跑一遍所有代码单元格。验证失败的具体错误会成为下一轮修复的输入。
这三个阶段形成一个循环:审查发现问题,修复尝试解决,验证确认结果。如果验证不通过,失败原因直接进入下一轮的修复指令。
为什么「结构化输出」是关键#
很多人用 Codex 的方式是自然语言对话,输出也是自由文本。但这个工作流的精髓在于,每个阶段的输入和输出都是严格的 JSON Schema。
审查阶段返回的是一个 findings 数组,每个 finding 包含 artifact(哪个文件)、issue_type(问题类型)、severity(严重程度)、description(描述)和 suggested_fix_direction(建议修复方向)。
修复阶段返回的是一个 fix 对象,包含 changes_made(做了什么改动)、unresolved_items(没解决的问题)和 updated_artifact_path(修复后的文件路径)。
验证阶段返回的是一个 validation 对象,包含 overall_passed(是否通过)、cases(每个验证用例的结果)和 remaining_delta(剩余问题)。
这种设计的好处是显而易见的:每个阶段的输出可以直接作为下一个阶段的输入,不需要人工解读。调试时你可以打开 record.json 文件,一眼看到每轮迭代发生了什么。
实战:三个 Notebook 的修复之旅#
教程准备了三个故意写坏的 Notebook,难度逐级递增:
简单案例(Qdrant 向量搜索):API 调用过时了,需要从旧版 qdrant.search 迁移到 qdrant.query_points。这类问题通常一轮修复就能搞定。
中等案例(OpenAI Evals 入门):不仅 API 过时了,而且运行结果的处理方式也有问题。第一轮修复了明显的 API 问题,但验证发现结果日志还有脆弱性,需要第二轮修复。
困难案例(知识检索):需要同时完成 API 现代化、本地运行能力保持、教学内容完整性维护三件事。这三个目标有时会互相冲突,需要三轮迭代才能找到平衡点。
最终结果:第一个 Notebook 在第一轮通过,第二个在第二轮通过,第三个在第三轮通过。每一轮的 remaining_delta 都在缩小,这就是收敛的信号。
容易被忽略的细节#
分阶段 staging#
不是所有问题都适合一次性修复。教程中有一个巧妙的设计:通过 staged_delta 函数控制每个案例的修复深度。简单案例允许一轮完成,复杂案例则人为设定需要多轮,让 Agent 每轮只关注最重要的那个问题。
这种设计模拟了真实工程中的场景:你不会在一个 PR 里同时重构整个模块、迁移 API、还要优化性能。分而治之,每次只解决一个核心问题。
并行执行#
三个 Notebook 的审查和修复是并行执行的,使用 Python 的 ThreadPoolExecutor。这意味着整个工作流的耗时取决于最慢的那个案例,而不是三个案例的总和。
审计追踪#
每一轮迭代都会在临时目录下生成一个 record.json 文件,记录审查发现、修复内容、验证结果。这些文件是整个工作流的审计线索,让维护者可以回溯每一步的决策依据。
生产环境的四个停止条件#
教程最后给出了一个通用化的 repair_until_done 函数。在生产环境中,循环应该在以下四种情况下停止:
- 验证通过:所有验证用例都通过了,没有剩余问题。
- 达到最大迭代次数:防止无限循环,通常设为 3 到 5 轮。
- 剩余 delta 不再变化:连续两轮的 remaining_delta 相同,说明 Agent 卡住了。
- 需要人工介入:某些问题超出了 Agent 的判断能力,需要人类审核。
这四个条件中,第 3 个最容易被忽略。如果没有这个检查,Agent 可能会在同一个问题上反复尝试,浪费计算资源。
这个模式能用在哪些地方#
文章最后提到了几个应用场景,但我觉得可以更广泛地思考:
文档维护:技术文档经常因为 API 更新而过时。用这个模式可以自动检测过时的代码示例,修复它们,并验证修复后的示例能否正常运行。
测试用例生成:让 Agent 写测试,运行测试,根据失败结果修复测试用例。这个循环可以持续到所有测试通过。
配置文件迁移:比如从旧版 YAML 格式迁移到新版,验证配置是否能被目标系统正确解析。
协议和规范文档:修复过时的引用、更新术语、确保符合最新的规范要求。
核心思想是通用的:只要你的任务有可靠的验证手段,就可以用这个模式让 Agent 自主迭代。
一点思考#
这个工作流最让我印象深刻的地方,不是 Codex 的代码能力有多强,而是它展示了一种工程化的 Agent 使用方式。
大多数人在用 AI 编程工具时,还是在用「聊天」的思维模式:提一个问题,等一个回答。但真正有价值的 Agent 工作流,应该是让 Agent 像一个初级工程师一样工作:接受任务,提交初版,收到反馈,修改,再提交,直到达标。
结构化输出、验证闭环、迭代收敛,这些不是 AI 的新能力,而是软件工程的老方法论。把它们应用到 Agent 工作流中,才是这篇文章真正的价值所在。
参考来源:Shreekant Agrawal, Build iterative repair loops with Codex, OpenAI Developer Cookbook, May 11, 2026 原文链接:https://developers.openai.com/cookbook/examples/codex/build_iterative_repair_loops_with_codex