在过去五个月里,我们团队做了一个实验:用零行人工编写代码,构建并上线一款内部测试的软件产品。
这个产品有内部的日常活跃用户,也有外部的 Alpha 测试用户。它会发版、部署、出故障、被修复。不同的是,代码里的每一行——业务逻辑、测试、CI 配置、文档、可观测性以及内部工具——全部由 Codex 生成。我们估算,整个产品的开发时间大概只有如果完全手写代码的十分之一。
人类负责驾驶,代理负责执行。
我们刻意选了这么苛刻的约束条件,好逼着自己去搭建能够把工程效率提升若干数量级的东西。我们只有几周时间,要交付的最终产物却是一座百万行代码的代码库。要做到这一点,我们必须搞清楚,当一个软件工程团队的主要工作不再是“写代码”,而是设计环境、明确意图、构建反馈回路,让 Codex 代理能稳定可靠地完成工作时,会发生什么变化。
本文讲的是,我们如何带着一群代理从零做出一个全新的产品——哪些地方趴了坑,哪些地方形成了正反馈,以及如何把我们唯一真正稀缺的资源:人类的时间和注意力,发挥到极致。
从一个空仓库开始
第一个提交落在一个空的 Git 仓库,是在 2025 年 8 月末。
最初的脚手架——仓库结构、CI 配置、格式化规则、包管理器设置、应用框架——都是由使用 GPT‑5 的 Codex CLI 生成的,只是用了一小套已有模板来引导。甚至连指导代理如何在仓库里工作的初始 AGENTS.md 文件,都是 Codex 写的。
一开始,仓库里没有任何人手写的代码可以作为锚点。从第一天起,仓库就是由代理“塑形”的。
五个月后,这个仓库已经扩展到大约一百万行代码,涵盖应用逻辑、基础设施、工具、文档以及内部开发者工具。在这段时间里,我们总共打开并合并了大约 1500 个 Pull Request,而一开始只有 3 名工程师在驱动 Codex。平均下来,每名工程师每天大约能推进 3.5 个 PR,而且随着团队扩展到如今的 7 人,人均吞吐量反而还在提高。重要的是,这不是为了“刷代码量”而输出的东西:这款产品在内部已有上百位用户使用,其中包括每天都用的重度用户。
在整个开发过程中,人类从未直接往仓库里写过一行代码。这逐渐演变成团队的核心哲学:不用手写代码。
重新定义“工程师”的角色
不再写代码这件事,引入了一种完全不同的工程工作重心:关注系统、脚手架与杠杆效应。
早期的进展比我们预期慢,并不是因为 Codex 能力不行,而是因为环境“规格不够”。代理缺少实现高层目标所需要的工具、抽象和内部结构。工程团队的首要任务,变成了帮助代理具备“干正事”的能力。
在实践中,这意味着我们要“向下挖深”:把大目标拆成更小的构建块(设计、代码、评审、测试等),通过提示让代理去构造这些块,再用这些块去解锁更复杂的任务。当事情出了问题,解决方案几乎从来不是“再试一次”。因为唯一的前进方式是让 Codex 来做事,人类工程师每次介入任务时都会问一句:“缺的到底是什么能力?我们如何让它对代理既清晰又可被强制执行?”
人类几乎完全通过“提示”与系统交互:工程师描述一个任务,运行代理,让它发起一个 PR。为了把 PR 推到可合并状态,我们会指示 Codex 在本地审查自己的改动,请求更多特定的代理在本地和云端参与评审,响应所有人类和代理给出的反馈,并在一个循环中迭代,直到所有代理评审都表示满意为止(本质上是一种 Ralph Wiggum Loop)。Codex 直接使用我们的标准开发工具(gh、本地脚本以及仓库里嵌入的“技能”)获取上下文,无需人类来复制黏贴到 CLI 里。
人类可以审查 PR,但并不是硬性要求。随着时间推移,我们把几乎所有的评审工作,都尽量下放给代理之间互相完成。
提高应用对代理的“可读性”
随着代码吞吐量的增加,我们的瓶颈变成了人类 QA 的精力。既然我们唯一固定的约束是人类的时间和注意力,我们就必须通过让代理能够直接“读懂”应用的 UI、日志和指标,把更多能力交给它。
例如,我们让应用可以按 git worktree 启动,这样 Codex 就可以针对每个改动分别拉起并操作一个实例。我们还把 Chrome DevTools Protocol 接到了代理运行时里,为操作 DOM 快照、截图和导航创建了对应的技能。有了这些能力,Codex 就能自己重现场景、验证修复效果,并直接推理 UI 行为。
我们在可观测性工具上也做了同样的事情。日志、指标和链路追踪会通过本地的可观测性栈暴露给 Codex,这个栈对于每个 worktree 都是一次性的。Codex 在一个完全隔离的应用实例上工作——包括它的日志和指标——一旦任务完成,这一整套环境就会被销毁。代理可以用 LogQL 查询日志,用 PromQL 查询指标。有了这些上下文,像“确保服务启动时间不超过 800 毫秒”、“这四条关键用户路径中的任意一个 span 都不能超过两秒”这样的提示就变得可操作。
我们经常看到,同一次 Codex 运行会围绕一个任务连续工作六个小时以上(通常人类这会儿已经在睡觉了)。
让仓库知识变成“事实源”
在让代理完成大型复杂任务的时候,如何管理上下文,是最大挑战之一。我们很早学到的一条简单原则是:“给 Codex 一张地图,而不是一本 1000 页的说明书。”
我们试过搞一个“大号的 AGENTS.md”文档,结果毫无意外地翻车了:
- 上下文是稀缺资源。一份巨大的说明文件会把任务、代码和真正相关的文档都挤出上下文之外——代理要么漏掉关键约束,要么开始优化错误的东西。
- 指导信息太多,等于没有指导。当所有事情都被标红为“重要”,其实就等于没有优先级。代理最终只能在局部做模式匹配,而不是有目的地导航。
- 它会立刻开始腐烂。单一的大文档很容易变成陈旧规则的墓地。代理区分不了哪些内容仍然有效,人类也懒得维护,最终这个文件悄无声息地演变成一种“危险诱饵”。
- 很难验证。一整坨 blob 文本不利于做自动检查(覆盖率、时效性、归属、交叉链接),于是“漂移”不可避免。
因此,我们不再把 AGENTS.md 当作百科全书,而是把它当作目录。
仓库的知识库真正存放在结构化的 docs/ 目录里,并视为系统的事实源。一个短小的 AGENTS.md(大概 100 行)会被注入到上下文中,主要作用是地图:指向其他更深入的“真相源”。
设计文档被整理并索引,包括验证状态以及一组定义“代理优先”运营原则的核心信念。架构文档提供了域和包分层的顶层地图。一份质量文档会对每个产品域和架构层打分,并随时间跟踪差距。
“计划”被视为一等公民。小改动用轻量的临时计划来描述,而复杂工作则通过版本化的执行计划来呈现,其中记录了进度和决策,并被提交到仓库中。正在进行的计划、已完成的计划以及已知的技术债,全都版本化并聚合在一起,让代理无需依赖外部上下文就能开展工作。
这就实现了渐进式揭示(progressive disclosure):代理从一个小而稳定的入口开始学习,被教会下一步该去哪里找,而不是一上来就被信息淹没。
我们还通过机制来强制执行这一点。专门的 linter 和 CI 任务会验证知识库是否是最新的、是否有正确的交叉链接、结构是否合理。一个定期运行的“文档园丁”代理会扫描那些与真实代码行为不符、已经过时或失效的文档,并发起修正 PR。
目标是让代理“看得懂”
随着代码库的演化,Codex 做设计决策的框架也必须一同演化。
因为仓库完全是由代理生成的,它首先是为Codex 的可读性优化的。就像团队会努力提高代码对新入职工程师的可导航性一样,我们人类工程师的目标,是让代理能够**仅凭仓库本身**就能推理整个业务领域。
对代理来说,任何它在运行中无法访问到的东西,等同于不存在。存在于 Google Docs、聊天记录或者人脑里的知识,对系统来说就是不可见的。仓库本地、具版本控制的物件(比如代码、Markdown、Schema、可执行计划)构成了它所能看见的一切。
我们发现,随着时间推移,我们必须往仓库里推更多上下文。那段在 Slack 上,把团队对某个架构模式对齐起来的讨论?如果代理找不到,那它的“不可读性”就跟一个三个月后刚入职的新同事完全不知道这事一模一样。
给 Codex 更多上下文,意味着要有组织地暴露正确的信息,让代理可以在其上推理,而不是随意堆砌一堆指令把它淹没。就像你会给新同事做入职培训,讲产品原则、工程规范和团队文化(包括用什么 emoji),把这些信息给代理,同样会收获更对齐的输出。
这个视角也帮助我们看清了很多技术选型的权衡。我们偏好那些能被彻底内化到仓库里并在本地推理的依赖和抽象。在训练数据中常被称为“无聊”的技术栈,往往更容易被代理建模,因为它们具有良好的可组合性、稳定的 API,以及广泛的使用案例。在某些场景下,让代理重新实现某些功能子集,反而比与公共库的黑盒行为斗争要更划算。比如,与其引一个通用的 `p-limit` 类库,我们不如实现一个自己的并发 map helper:它与我们的 OpenTelemetry 埋点深度整合,测试覆盖率 100%,行为完全符合运行时的预期。
把更多系统部分拉进代理可检查、可验证、可直接修改的范围,不仅可以提高 Codex 的杠杆,还能惠及其他在这份代码库上工作的代理(例如 Aardvark)。
通过“约束”和“品味”保持架构
光靠文档不足以维护一个完全由代理生成的代码库的整体性。通过强制执行不变量,而不是事无巨细地干预实现细节,我们让代理在不破坏地基的前提下高速出货。比如,我们要求 Codex 必须在系统边界解析数据结构(parse data shapes at the boundary),但并不规定必须用哪套工具(模型目前似乎很偏爱 Zod,但这不是我们硬性指定的库)。
代理在那些具有**明确边界和可预期结构**的环境中效果最好,因此我们围绕一个非常刚性的架构模型来构建整个应用。每个业务域都被划分成一套固定的层次,依赖方向严格受限,允许的边只存在于有限的几种模式中。这些约束是通过自定义 linter(当然也是 Codex 生成的!)和结构化测试来强制执行的。
这类架构通常是你在团队扩展到几百号工程师时才会投入去建设的。而在有编码代理的世界里,它反而成为早期的前置条件:正是这些约束,让高速度与低衰减、低架构漂移共存成为可能。
在实践中,我们用自定义 linter 和结构化测试,再加上一小撮“品味不变量”来落地这些规则。比如,我们通过静态检查强制结构化日志、强制 Schema 和类型的命名约定、文件大小上限以及平台级的可靠性要求。由于 linter 是定制的,我们还可以通过错误提示向代理注入具体的修复指引。
在以人类为中心的开发流程里,这类规则可能显得很“事儿”、很约束。在有代理参与的模式中,它们反而成了放大器:一旦编码进系统,便能在整个代码库里无处不在地发挥作用。
同时,我们也很清晰地划分了哪里需要强约束、哪里不需要。这很像运营一个大型工程基础平台团队:在中心化的边界上强制规范,在局部解决方案上则给予自治。你会对边界、正确性和可复现性高度在意,而在这些边界之内,则允许团队——或者代理——在解决方案的表达方式上保有相当大的自由度。
代码结果并不总是符合人类的审美,这没有关系。只要输出是正确的、可维护的,并且对未来的代理运行保持足够可读,就算达标。
人类的“品味”会持续被反馈回系统。评审意见、重构 PR 和用户面对的线上问题,会以文档更新或者工具规则的形式被编码进仓库。当纯文档形式不够用时,我们就把规则“晋升”为代码。
吞吐量改变了“合并哲学”
当 Codex 的吞吐量越来越高,很多传统的工程规范开始变得适得其反。
我们以极少的阻塞式合并门槛来运转这个仓库。PR 的生命周期很短。对于测试偶发性的 Flaky,我们更多通过再次运行来解决,而不是无止境地卡住进度。在一个代理吞吐远超人类注意力的系统里,修正成本很低,而等待的代价很大。
在一个低吞吐环境里,这样做可能非常不负责任。但在这里,这往往是更好的权衡。
“由Agent生成”究竟意味着什么?
当我们说这份代码库是由 Codex 代理生成的,我们指的是:仓库里的一切都是如此。
代理负责生成:
- 产品代码和测试
- CI 配置和发布工具
- 内部开发工具
- 文档和设计历史
- 评测用的执行框架
- 评审意见和回应
- 管理仓库本身的脚本
- 生产环境仪表盘配置文件
人类始终在环内,但所工作的抽象层次已经和以前很不一样了。我们负责排定优先级,把用户反馈翻译为可验收标准,并验证最终结果。当代理“卡壳”时,我们把它视为信号:识别缺失的是什么——工具、护栏、还是文档——然后把这些缺口反馈回仓库,并始终通过让 Codex 自己来写补丁的方式来填平。
代理直接使用我们的标准开发工具。它会拉取评审意见、在评论中逐条回复、推送更新,甚至经常会自己把 PR squash 并合并。
不断提升的自治水平
随着越来越多的开发闭环被直接编码到系统里——测试、验证、评审、反馈处理和回退恢复——这个仓库最近迈过了一个重要门槛:Codex 现在可以端到端地驱动一个全新特性。
在收到一个简单提示后,代理现在可以:
- 验证当前代码库状态
- 复现已报告的 bug
- 录制一段展示问题的演示视频
- 实现修复
- 通过驱动应用验证修复效果
- 再录制一段展示问题已被解决的视频
- 打开 PR
- 回应代理和人类的反馈
- 发现并修复构建失败
- 只有在需要判断力的时候才会升级给人类
- 合并改动
这种行为高度依赖当前这份仓库的特定结构和工具链,不能简单假设它会在没有类似投入的前提下自然泛化——至少目前还不会。
熵与“垃圾回收”
完全自治的代理也带来了一些全新的问题。Codex 会复制仓库中已存在的模式——包括那些不均衡甚至不理想的模式。随着时间推移,这不可避免地会导致“漂移”。
一开始,这些问题都是由人类手动处理。我们的团队曾经每周五都拿出一天(占整周的 20%)来清理所谓的“AI 泥浆”。毫不意外,这套做法根本撑不住长期运行。
于是,我们开始把所谓的“黄金原则”直接编码进仓库,并构建一套周期性的清理流程。这些原则是一些带有主观偏好的、但可以机械化的规则,用来让代码库对未来的代理运行保持足够一致与可读。比如:(1)我们更偏好共享的工具包,而不是到处手写小工具,以便集中维护不变量;(2)我们不允许“YOLO 式”地探测数据结构,而是要求在边界做验证,或者依赖类型化的 SDK,这样代理就不会在“猜测的数据形状”上继续往上搭建。
在一个固定的节奏下,我们会跑一组后台 Codex 任务,扫描违反这些原则的地方,更新质量评分,并打开有针对性的重构 PR。大部分这类 PR 一分钟之内就能审完,然后自动合并。
这套机制就像“垃圾回收”。技术债就像一笔高利贷:几乎总是更划算的是持续用小额偿还的方式,而不是任其滚雪球,最后再用一次痛苦的大手术去处理。人类的品味被编码一次,之后就能在每一行代码上持续发挥作用。这也让我们可以在日常就捕捉和纠正坏模式,而不是让它们在代码库里蔓延数天乃至数周。
我们仍在探索的部分
这种策略到目前为止在 OpenAI 内部的上线和推广过程里表现不错。为真实用户构建真实产品,让我们的投入始终有现实锚点,也迫使我们更关注长期可维护性。
但我们还不知道,在一个完全由代理生成的系统里,架构的一致性在**多年尺度**上会如何演化。我们仍在摸索人类判断力在哪些地方能带来最大杠杆,以及如何把这种判断编码进系统,使其能不断复利。另外,我们也不知道,随着模型能力持续提高,这套系统会如何随之演化。
可以肯定的是:构建软件依然需要纪律,只不过这种纪律越来越体现在“脚手架”而不是“代码”本身。那些维持代码库连贯性的工具、抽象和反馈回路,变得愈发重要。
我们现在最难的问题,都围绕着如何设计环境、反馈回路和控制系统,帮助代理实现我们的目标:在规模上构建并维护复杂而可靠的软件系统。
当像 Codex 这样的代理承担起软件生命周期中越来越大的一部分工作时,这些问题只会愈发关键。希望这些早期经验,能帮你更好地思考该把精力投入在哪些地方,才能真正“只管去构建东西”。
原文:Harness engineering: leveraging Codex in an agent-first world, OpenAI

