过去五个月里,我们的团队一直在进行一项实验:构建并发布一个软件产品的内部 Beta 版,且由人工编写的代码为 0 行。
该产品拥有内部日常用户和外部 Alpha 测试人员。它正常发布、部署、崩溃并被修复。不同之处在于,每一行代码——应用逻辑、测试、CI 配置、文档、可观测性以及内部工具——都是由 Codex 编写的。我们估计,构建这个产品的时间大约是手工编写代码所需时间的十分之一。
人类掌舵。智能体执行。
我们特意选择了这个限制条件,以便我们构建能将工程速度提高几个数量级所需的东西。我们只有几周时间来发布最终达到一百万行代码的产品。为了做到这一点,我们需要理解当软件工程团队的主要工作不再是编写代码,而是设计环境、指定意图并建立反馈循环以允许 Codex 智能体可靠地工作时,会发生什么变化。
这篇文章讲述了我们通过用智能体团队构建全新产品所学到的东西——什么东西坏了,什么东西产生了复利效应,以及如何最大化利用我们唯一真正的稀缺资源:人类的时间和注意力。
我们从一个空的 git 仓库开始
第一次提交到空仓库是在 2025 年 8 月下旬。
初始脚手架——仓库结构、CI 配置、格式化规则、包管理器设置和应用程序框架——是由 Codex CLI 使用 GPT-5 生成的,并由少量现有模板指导。甚至指导智能体如何在仓库中工作的初始 AGENTS.md 文件本身也是由 Codex 编写的。
系统中没有预先存在的人工代码作为锚点。从一开始,仓库就是由智能体塑造的。
五个月后,该仓库包含大约一百万行代码,涵盖应用逻辑、基础设施、工具、文档和内部开发实用程序。在此期间,仅由三名工程师驱动 Codex,就开启并合并了大约 1,500 个拉取请求(PR)。这意味着每位工程师每天平均处理 3.5 个 PR,而且令人惊讶的是,随着团队增加到目前的 7 名工程师,吞吐量反而增加了。重要的是,这并非为了产出而产出:该产品已被数百名内部用户使用,包括日常的内部重度用户。
在整个开发过程中,人类从未直接贡献过任何代码。这成了团队的核心理念:无人工编写的代码。
重新定义工程师的角色
缺乏亲手编写代码的过程引入了一种不同类型的工程工作,专注于系统、脚手架和杠杆作用。
早期的进展比我们预期的要慢,并非因为 Codex 能力不足,而是因为环境规定不明确。智能体缺乏朝着高层目标推进所需的工具、抽象和内部结构。我们工程团队的主要工作变成了赋能智能体去做有用的工作。
在实践中,这意味着采用深度优先的工作方式:将较大的目标分解为较小的构建块(设计、编码、审查、测试等),提示智能体构建这些块,并利用它们来解锁更复杂的任务。当出现问题时,修复方法几乎从来都不是“再努力尝试一下”。因为取得进展的唯一途径是让 Codex 去做这项工作,所以人类工程师总是介入任务并问道:“缺少什么能力,我们如何使其对智能体既清晰可读又可执行?”
人类几乎完全通过提示与系统交互:工程师描述任务,运行智能体,并允许其打开拉取请求。为了推动 PR 完成,我们指示 Codex 在本地审查自己的更改,请求云端和本地的其他特定智能体进行审查,响应任何人类或智能体给出的反馈,并在循环中迭代,直到所有智能体审查者都满意为止(实际上这是一个 Ralph Wiggum 循环)。Codex 直接使用我们的标准开发工具(gh、本地脚本和仓库嵌入的技能)来收集上下文,无需人类在 CLI 中复制粘贴。
人类可以审查拉取请求,但不是必须的。随着时间的推移,我们已将几乎所有的审查工作推向由智能体对智能体(agent-to-agent)处理。
提高应用程序的可读性
随着代码吞吐量的增加,我们的瓶颈变成了人工 QA 的容量。由于固定的限制因素是人类的时间和注意力,我们致力于通过让应用程序 UI、日志和应用程序指标本身能被 Codex 直接读取,来为智能体增加更多能力。
例如,我们使应用程序可以在每个 git 工作树(worktree)中启动,因此 Codex 可以针对每个更改启动并驱动一个实例。我们还将 Chrome DevTools 协议连接到智能体运行时,并创建了处理 DOM 快照、截图和导航的技能。这使得 Codex 能够重现错误、验证修复并直接推理 UI 行为。
我们对可观测性工具也做了同样的处理。日志、指标和追踪通过一个对任何给定工作树都是临时的本地可观测性堆栈暴露给 Codex。Codex 在该应用程序的完全隔离版本上工作——包括其日志和指标,一旦任务完成,这些都会被拆除。智能体可以使用 LogQL 查询日志,使用 PromQL 查询指标。有了这些上下文,像“确保服务启动在 800 毫秒内完成”或“这四个关键用户旅程中没有任何跨度(span)超过两秒”这样的提示就变得易于处理了。
我们经常看到单个 Codex 运行在单个任务上持续工作超过六个小时(通常是在人类睡觉的时候)。
我们将仓库知识作为记录系统
上下文管理是使智能体在大型复杂任务中发挥效用的最大挑战之一。我们学到的最早的教训之一很简单:给 Codex 一张地图,而不是一本 1,000 页的说明书。
我们尝试过“一个巨大的 AGENTS.md”的方法。它以可预见的方式失败了:
- 上下文是稀缺资源。 巨大的说明文件会挤占任务、代码和相关文档的空间——因此智能体要么错过关键约束,要么开始针对错误的约束进行优化。
- 过多的指导变成了无指导。 当一切都“重要”时,就什么都不重要了。智能体最终会在局部进行模式匹配,而不是有意识地导航。
- 它会瞬间腐烂。 宏大的手册会瞬间变成陈旧规则的坟墓。智能体无法分辨什么是真的,人类停止维护它,文件悄然变成一个诱人的累赘。
- 难以验证。 单个大文件不适合机械检查(覆盖率、新鲜度、所有权、交叉链接),因此漂移是不可避免的。
因此,我们不将 AGENTS.md 视为百科全书,而是将其视为目录。
仓库的知识库位于结构化的 docs/ 目录中,被视为记录系统。注入上下文的是一个简短的 AGENTS.md(大约 100 行),主要充当通过地图,包含指向其他地方更深层真理来源的指针。
1 AGENTS.md
2 ARCHITECTURE.md
3 docs/
4 ├── design-docs/
5 │ ├── index.md
6 │ ├── core-beliefs.md
7 │ └── ...
8 ├── exec-plans/
9 │ ├── active/
10 │ ├── completed/
11 │ └── tech-debt-tracker.md
12 ├── generated/
13 │ └── db-schema.md
14 ├── product-specs/
15 │ ├── index.md
16 │ ├── new-user-onboarding.md
17 │ └── ...
18 ├── references/
19 │ ├── design-system-reference-llms.txt
20 │ ├── nixpacks-llms.txt
21 │ ├── uv-llms.txt
22 │ └── ...
23 ├── DESIGN.md
24 ├── FRONTEND.md
25 ├── PLANS.md
26 ├── PRODUCT_SENSE.md
27 ├── QUALITY_SCORE.md
28 ├── RELIABILITY.md
29 └── SECURITY.md
设计文档被编目和索引,包括验证状态和一组定义智能体优先操作原则的核心信念。架构文档提供了领域和包分层的顶层地图。质量文档对每个产品领域和架构层进行评分,跟踪随时间推移的差距。
计划被视为一等公民。临时的轻量级计划用于小的更改,而复杂的工作则记录在执行计划中,带有进度和决策日志,这些都会检入仓库。活动计划、已完成计划和已知的技术债务都进行了版本控制并放在一起,允许智能体在不依赖外部上下文的情况下进行操作。
这实现了渐进式披露:智能体从一个小的、稳定的入口点开始,并被教导下一步该看哪里,而不是一开始就被淹没。
我们通过机械方式强制执行这一点。专用的 linter 和 CI 作业验证知识库是否最新、交叉链接且结构正确。一个定期运行的“文档园艺”智能体会扫描那些不能反映真实代码行为的陈旧或过时文档,并打开修复拉取请求。
智能体可读性是目标
随着代码库的演变,Codex 的设计决策框架也需要随之演变。
因为仓库完全是由智能体生成的,所以它首先针对 Codex 的可读性进行了优化。就像团队旨在提高代码对新入职工程师的可导航性一样,我们人类工程师的目标是使智能体能够直接从仓库本身推理出完整的业务领域。
从智能体的角度来看,任何它在运行时无法在上下文中访问的东西实际上都不存在。存在于 Google Docs、聊天记录或人们头脑中的知识对系统来说是不可访问的。仓库本地的、版本化的工件(例如代码、markdown、schema、可执行计划)是它能看到的全部。
我们了解到,随着时间的推移,我们需要将越来越多的上下文推入仓库。那个在 Slack 讨论中让团队对架构模式达成一致的讨论?如果智能体无法发现它,那么就像三个月后加入的新员工不知道它一样,它是不可读的。
给 Codex 更多上下文意味着组织和暴露正确的信息,以便智能体可以对其进行推理,而不是用临时的指令淹没它。就像你会向新队友介绍产品原则、工程规范和团队文化(包括表情符号偏好)一样,给智能体提供这些信息会导致更一致的输出。
这种框架澄清了许多权衡。我们倾向于那些可以在仓库内完全内化和推理的依赖项和抽象。通常被描述为“无聊”的技术往往更容易被智能体建模,因为它们具有可组合性、API 稳定性以及在训练集中的代表性。在某些情况下,让智能体重新实现部分功能比绕过公共库中不透明的上游行为成本更低。例如,我们没有引入通用的 p-limit 风格的包,而是实现了我们自己的并发映射助手:它与我们的 OpenTelemetry 仪表紧密集成,拥有 100% 的测试覆盖率,并且行为完全符合我们运行时的预期。
将更多系统拉入智能体可以直接检查、验证和修改的形式中,增加了杠杆作用——不仅对 Codex 如此,对同样在代码库上工作的其他智能体(例如 Aardvark)也是如此。
强制执行架构和品味
仅靠文档无法保持完全由智能体生成的代码库的一致性。通过强制执行不变性,而不是微观管理实现,我们让智能体在不破坏基础的情况下快速发布。 例如,我们要求 Codex 在边界解析数据形状,但不规定具体如何发生(模型似乎喜欢 Zod,但我们没有指定该特定库)。
智能体在具有严格边界和可预测结构的环境中最为有效,因此我们围绕严格的架构模型构建了应用程序。每个业务领域都被划分为一组固定的层,具有严格验证的依赖方向和一组有限的允许边缘。这些约束通过自定义 linter(当然也是 Codex 生成的!)和结构测试以机械方式强制执行。
下图展示了规则:在每个业务领域(例如 App 设置)内,代码只能通过一组固定的层“向前”依赖(Types → Config → Repo → Service → Runtime → UI)。横切关注点(auth、连接器、遥测、功能标志)通过单一的显式接口进入:Providers。其他任何东西都是不允许的,并且会被机械强制执行。
这是通常你会推迟到拥有数百名工程师时才做的架构。对于编码智能体来说,这是一个早期的先决条件:约束是允许速度而不会导致衰退或架构漂移的原因。
在实践中,我们通过自定义 linter 和结构测试,加上一小组“品味不变量”来强制执行这些规则。例如,我们静态强制执行结构化日志记录、schema 和类型的命名约定、文件大小限制以及通过自定义 lint 强制执行特定于平台的可靠性要求。因为 lint 是自定义的,我们编写错误消息以将补救说明注入智能体上下文。
在以人为优先的工作流程中,这些规则可能会让人觉得迂腐或受限。对于智能体,它们变成了倍增器:一旦编码,它们就会同时应用于任何地方。
同时,我们明确指出了约束在哪里重要,哪里不重要。这类似于领导一个大型工程平台组织:集中强制执行边界,允许局部自治。你深切关注边界、正确性和可复现性。在这些边界内,你允许团队——或智能体——在如何表达解决方案方面有很大的自由度。
生成的代码并不总是符合人类的风格偏好,这没关系。只要输出正确、可维护且对未来的智能体运行清晰可读,它就达到了标准。
人类的品味被不断反馈到系统中。审查评论、重构拉取请求和面向用户的错误被捕获为文档更新或直接编码到工具中。当文档不足时,我们将规则提升为代码。
吞吐量改变了合并哲学
随着 Codex 的吞吐量增加,许多传统的工程规范变得适得其反。
仓库运行时具有最小的阻塞合并门槛。拉取请求的寿命很短。测试不稳定性通常通过后续运行来解决,而不是无限期地阻止进度。在一个智能体吞吐量远超人类注意力的系统中,修正很便宜,而等待很昂贵。
在低吞吐量环境中,这是不负责任的。在这里,这通常是正确的权衡。
“智能体生成”实际上意味着什么
当我们要说代码库是由 Codex 智能体生成的,我们指的是代码库中的一切。
智能体生产:
- 产品代码和测试
- CI 配置和发布工具
- 内部开发者工具
- 文档和设计历史
- 评估 Harness (测试框架)
- 审查评论和响应
- 管理仓库本身的脚本
- 生产仪表板定义文件
人类始终保持在循环中,但在比我们过去习惯的不同的抽象层面上工作。我们确定工作的优先级,将用户反馈转化为验收标准,并验证结果。当智能体挣扎时,我们将此视为信号:识别缺少什么——工具、护栏、文档——并将其反馈回仓库,始终是通过让 Codex 本身编写修复程序来实现。
智能体直接使用我们的标准开发工具。它们拉取审查反馈,内联响应,推送更新,并经常压缩和合并它们自己的拉取请求。
提高自主水平
随着越来越多的开发循环直接编码到系统中——测试、验证、审查、反馈处理和恢复——该仓库最近跨越了一个有意义的门槛,Codex 现在可以端到端地驱动新功能。
给定一个提示,智能体现在可以:
- 验证代码库的当前状态
- 重现报告的错误
- 录制演示故障的视频
- 实现修复
- 通过驱动应用程序验证修复
- 录制演示解决方案的第二个视频
- 打开拉取请求
- 响应智能体和人类的反馈
- 检测并修复构建失败
- 仅在需要判断时升级给人类
- 合并更改
这种行为在很大程度上取决于该仓库的具体结构和工具,如果没有类似的投资,不应假设可以通用化——至少目前还不行。
熵和垃圾回收
完全的智能体自主性也引入了新的问题。 Codex 复制仓库中已经存在的模式——即使是不均匀或次优的模式。随着时间的推移,这不可避免地导致漂移。
最初,人类手动解决这个问题。我们的团队过去每个周五(一周的 20%)都要花时间清理“AI 垃圾(AI slop)”。不出所料,这无法扩展。
相反,我们开始将所谓的“黄金原则”直接编码到仓库中,并建立了一个定期的清理过程。这些原则是固执己见的、机械的规则,使代码库对未来的智能体运行保持清晰和一致。例如:(1) 我们更喜欢共享实用程序包而不是手写的助手,以保持不变量集中,以及 (2) 我们不以“YOLO 风格”探测数据——我们验证边界或依赖类型化的 SDK,这样智能体就不会意外地建立在猜测的形状上。按照固定的节奏,我们有一组后台 Codex 任务扫描偏差,更新质量等级,并打开有针对性的重构拉取请求。其中大多数可以在一分钟内审查完毕并自动合并。
这就像垃圾回收一样。技术债务就像高息贷款:分小步持续偿还几乎总是比让它复利并在痛苦的爆发中解决要好。人类的品味被捕获一次,然后持续强制执行在每一行代码上。这也让我们能够每天捕获并解决不良模式,而不是让它们在代码库中蔓延数天或数周。
我们仍在学习什么
到目前为止,这一策略在 OpenAI 内部发布和采用过程中运作良好。为真实用户构建真实产品有助于将我们的投资锚定在现实中,并引导我们实现长期的可维护性。
我们还不知道在一个完全由智能体生成的系统中,架构的一致性在多年内是如何演变的。我们仍在学习人类判断在哪里增加最大的杠杆作用,以及如何编码该判断使其产生复利。我们也不知道随着模型随着时间的推移变得更有能力,这个系统将如何演变。
清楚的是:构建软件仍然需要纪律,但这种纪律更多地体现在脚手架上,而不是代码中。保持代码库一致的工具、抽象和反馈循环变得越来越重要。
我们现在最困难的挑战集中在设计环境、反馈循环和控制系统上,这些系统帮助智能体实现我们的目标:大规模构建和维护复杂、可靠的软件。
随着像 Codex 这样的智能体承担软件生命周期的更大一部分,这些问题将变得更加重要。我们希望分享一些早期的经验教训能帮助你推理应该在哪里投入精力,以便你可以专注于构建事物。