
作者 | Ryan Lopopolo
译者 | 田橙
策划 | Tina
在过去的五个月里,我们团队进行了一项挑战:开发并发布一款完全没有人工编写代码的内部测试产品。
目前,该产品已经拥有内部日活用户和外部 Alpha 测试人员。它在真实的开发环境中运行、部署、报错并接受修复。其独特之处在于,从应用逻辑到测试脚本,再到 CI 配置、文档、可观测性及内部工具,每一行代码都出自 Codex 之手。据我们估算,这种开发模式的效率极高,耗时仅为手动开发代码的 10%。
人类掌舵,Agent 执行。
我们特意设定了这个限制,就是想看看工程效能能否实现量级上的突破。当时我们需要在短短几周内交付上百万行代码,这迫使我们必须重新思考:如果工程师不再把“写代码”当成主业,而是转去设计环境、定义意图并构建反馈循环,好让 Codex Agent 产出可靠的成果,那么研发模式到底会发生什么变化?
在这篇文章中,我们将分享通过 Agent 团队构建全新产品的心得,包括哪些尝试失败了,哪些产生了复利效应,以及如何最大化利用我们最宝贵的资源:人类的时间与注意力。
从空仓库起步
2025 年 8 月底,我们向这个空仓库提交了第一次 Commit。
初始脚手架由 Codex CLI 调用 GPT-5 生成,并辅以少量现有模板作为引导,涵盖了仓库结构、CI 配置、格式化规则、包管理器设置以及应用框架。甚至连指导 Agent 如何在仓库中工作的初始 AGENTS.md 文件,也是由 Codex 亲笔完成。
这里没有任何预存的人工代码来作为系统的“锚点”。从一开始,整个仓库的形态就是由 Agent 塑造的。
五个月后,该仓库已拥有约 100 万行代码,涵盖应用逻辑、基础设施、工具链、文档和内部开发组件。在此期间,一支仅有 3 名工程师的小团队驱动 Codex 开启并合并了约 1500 个 PR。这意味着平均每位工程师每天产出 3.5 个 PR。令人惊讶的是,随着团队扩大到 7 人,人均产出率反而进一步提升。
更重要的是,这并非为了刷量而产出:该产品已被数百名内部用户使用,其中包括每天重度使用的核心用户。在整个开发过程中,人类从未直接贡献过任何一行代码。这成了团队的核心哲学:拒绝人工编写代码。
重新定义工程师的角色
由于不再亲自动手写代码,工程师的工作重心转向了系统设计、脚手架搭建和杠杆效能。
早期的进展比预期要慢,这并非因为 Codex 能力不足,而是因为环境的“规范度”不够。Agent 缺乏实现高层目标所需的工具、抽象和内部结构。于是,工程团队的首要任务变成了:赋能 Agent 开展有效工作。
在实践中,这意味着采用深度优先的工作方式:将宏大目标拆解为微小的构建块(设计、代码、评审、测试等)。驱动 Agent 构建这些块。利用这些已有的块去解锁更复杂的任务。当任务失败时,修复方案几乎从不是“再试一次”。因为必须通过 Codex 来推进工作,人类工程师会介入并思考:“缺失了什么能力?我们如何让这种能力对 Agent 而言既清晰可见又强制执行?”
人类与系统的交互几乎完全通过 提示词 完成:工程师描述一项任务,运行 Agent,并授权其开启一个 Pull Request。为了推进 PR 最终合入,我们会指示 Codex 在本地审查自己的代码改动,并请求其他特定的 Agent(无论是在本地还是云端)进行交叉评审。Codex 会根据人类或 Agent 给出的反馈进行响应,并在循环中不断迭代,直到所有 Agent 评审员都感到满意——这实际上形成了一个所谓的 “拉尔夫·维格姆循环”(Ralph Wiggum Loop)【见译注】。Codex 直接调用我们的标准开发工具(如 GitHub CLI gh、本地脚本以及集成在仓库中的技能),自主获取上下文,无需人类手动在命令行中复制粘贴。
译注:Ralph Wiggum Loop:这是一个来自《辛普森一家》的梗(那个坐在教室后面自言自语的小男孩),在软件工程语境下,通常指代一种“自给自足、闭环且带有某种幽默色彩的自推导循环”。
虽然人类可以审查 PR,但这并非强制要求。随着时间的推移,我们已将几乎所有的评审工作都交给了 “Agent 对 Agent” 的协作模式。
增加应用的“可读性”
随着代码产出率的提升,我们的瓶颈变成了人类的 QA 能力。由于人类的时间和注意力始终是唯一的稀缺资源,我们致力于通过让应用 UI、日志和指标对 Codex 直接可见且可理解,从而为 Agent 增加更多能力。
例如,我们使应用能够针对每个 Git 工作树(worktree)独立启动,这样 Codex 就可以为每一次代码变更运行并驱动一个实例。我们还将 Chrome DevTools Protocol 接入 Agent 运行时,并创建了处理 DOM 快照、截图和导航的技能。这使得 Codex 能够直接复现 Bug、验证修复结果并推导 UI 行为。
![]()
我们对可观测性工具也做了同样的处理。日志、指标和链路追踪通过一个本地的可观测性栈暴露给 Codex,这个栈对于任何给定的工作树来说都是临时的。Codex 运行在该应用的一个完全隔离的版本上,包括其日志和指标,这些内容会在任务完成后被销毁。Agent 可以使用 LogQL 查询日志,使用 PromQL 查询指标。有了这些上下文,诸如“确保服务启动在 800ms 内完成”或“这四个关键用户旅程中没有任何 Trace Span 超过 2 秒”之类的提示词,就变得具有可操作性了。
我们经常看到单次 Codex 运行持续处理一个任务超过 6 小时(通常是在人类睡觉的时候)。
以仓库知识作为“事实来源”
上下文管理是让 Agent 处理复杂任务的最大挑战之一。我们学到的核心教训是:给 Codex 一张地图,而不是一本千页的使用手册。
我们曾尝试过“单一 AGENTS.md 大文件”方案,但很快就失败了:1. 上下文是稀缺资源:巨大的指令文件会挤占任务代码和相关文档的空间。这会导致 Agent 要么遗漏关键约束,要么开始针对错误的目标进行优化。2. 引导过度等于没有引导:当所有内容都被标榜为“重要”时,就失去了重点。Agent 最终只会进行局部的模式匹配,而无法有目的地理解全局。3. 文档极易腐化:单体式的手册很快就会变成陈旧规则的坟场。Agent 无法判断哪些规则依然有效,人类也懒得维护,结果这份文件反而成了误导 Agent 的诱饵。4. 难以验证:这种单一的大块内容无法进行机械化检查(如覆盖率、时效性、归属权或交叉链接),架构偏离也就成了必然。
因此,我们将 AGENTS.md 视为目录而非百科全书。
代码库的知识库存在于一个结构化的 docs/ 目录中,并被视为唯一事实来源。一份简短的 AGENTS.md(约 100 行)被注入到上下文中,它主要充当地图的角色,包含指向分布在各处的更深层“事实来源”的指针。
└── SECURITY.md设计文档被编目并索引,其中包含验证状态以及一套定义了“Agent 优先”运营原则的核心信条。架构文档提供了一个关于领域划分和包分层的顶级地图。一份质量文档则会对每个产品领域和架构层级进行评分,并长期跟踪其中的差距。
计划(Plans)被视为一等公民。临时性的轻量计划用于微小的变更,而复杂的工作则会被记录在执行计划中,连同进度和决策日志一起提交到仓库。活跃计划、已完成计划以及已知的技术债都会进行版本化管理并放在一起,使 Agent 能够无需依赖外部上下文即可开展工作。
这实现了渐进式披露:Agent 从一个微小、稳定的入口点开始,并被告知下一步该去哪里寻找信息,而不是预先就被海量信息所淹没。
我们通过机械化手段强制执行这一点。专门的 Linter 和 CI 任务会验证知识库是否处于最新状态、是否正确进行了交叉引用以及结构是否合规。一个循环运行的“文档园丁”Agent 会扫描那些无法反映真实代码行为的陈旧或过时文档,并开启修复类 PR。
以“Agent 可读性”为目标
随着代码库的演进,Codex 的设计决策框架也随之进化。
由于整个仓库完全由 Agent 生成,它首先针对 Codex 的可读性 进行了优化。正如开发团队致力于为新入职工程师提高代码的可导航性一样,我们人类工程师的目标是让 Agent 能够直接从仓库本身推导并理解完整的业务领域知识。
从 Agent 的视角来看,任何在运行时无法通过上下文获取的信息,实际上都不存在。存储在 Google Docs、聊天记录或存在于人们大脑中的知识,系统是无法访问的。只有仓库本地的、版本化的工件(如代码、Markdown、Schema、可执行计划)才是它可见的全部世界。
![]()
我们意识到,随着时间的推移,我们需要将越来越多的上下文推入仓库。比如那次让团队在架构模式上达成一致的 Slack 讨论,如果它对 Agent 来说是不可检索的,那么它就是“不可读”的——就像对于三个月后入职的新员工来说,这段背景是缺失的一样。
赋予 Codex 更多上下文,意味着需要组织并暴露正确的信息,以便 Agent 进行推理,而不是用大量的临时指令让它不堪重负。就像你会向新队友介绍产品原则、工程规范和团队文化(甚至包括表情符号的使用偏好)一样,向 Agent 提供这些信息会带来更加一致的产出。
这种思路让许多权衡变得清晰。我们更青睐那些可以被完全内化并在仓库内进行推理的依赖项和抽象。那些通常被称为“乏味”的技术,往往因为其组合性、API 稳定性和在训练集中的高覆盖率,更容易被 Agent 建模。在某些情况下,让 Agent 重新实现一部分功能,比绕过公共库中不透明的上层行为成本更低。例如,我们没有引入通用的 p-limit 风格的包,而是实现了自己的并发映射助手:它与我们的 OpenTelemetry 监控紧密集成,拥有 100% 的测试覆盖率,并且完全符合我们运行时的预期。
将系统的更多部分转化为 Agent 可以直接检查、验证和修改的形式,不仅提升了 Codex 的杠杆效能,也同样造福了其他在同一代码库中工作的 Agent(例如 Aardvark)。
强制执行架构与审美
仅靠文档不足以保持一个完全由 Agent 生成的代码库的连贯性。通过强制执行“不变量”而非微观管理实现细节,我们让 Agent 在快速交付的同时,不破坏系统的根基。例如,我们要求 Codex 在系统边界处必须进行数据格式解析,但并不强制规定实现方式(模型似乎偏好 Zod,但我们从未指定过这个特定的库)。
Agent 在边界严格且结构可预测的环境中效率最高。因此,我们围绕一套僵化的架构模型构建了应用。每个业务领域被划分为一组固定的层级,拥有严格验证的依赖方向和有限的允许连接点。这些约束通过自定义 Linter(当然也是 Codex 生成的!)和结构化测试进行机械化强制执行。
下图展示了这一规则:在每个业务领域(如“应用设置”)内,代码只能沿着一组固定的层级“向前”依赖(类型定义 → 配置 → 仓库层 → 服务层 → 运行时 → UI)。跨领域关注点(如认证、连接器、遥测、特性开关)通过单一且明确的接口进入:提供者(Providers)。除此之外的任何依赖都是被禁止的,并由机械化手段强制执行。
![]()
这种架构通常是在拥有数百名工程师后才会考虑推行的。但在使用编程 Agent 时,它是前置的必要条件:正是这些约束,才使得系统在高速迭代的同时,不会出现腐化或架构偏离。
在实践中,我们通过自定义 Linter、结构化测试以及一小套“审美不变量”来执行这些规则。例如,我们通过静态检查强制要求:结构化日志记录、架构和类型的命名规范、文件大小限制,以及针对特定平台的可靠性要求。由于 Linter 是自定义的,我们可以编写专门的错误信息,以便将修复指令直接注入到 Agent 的上下文中。
在以人类为中心的工作流中,这些规则可能显得过于死板或受限。但在 Agent 环境下,它们变成了效能倍增器:规则一旦被编码,就会立即应用于所有地方。
与此同时,我们明确区分了哪些地方需要约束,哪些地方不需要。这非常像领导一个大型工程平台组织:中央强制执行边界,地方允许自主。 你需要极度关注边界、正确性和可复现性;而在这些边界之内,你允许团队(或 Agent)在表达解决方案时拥有极大的自由。
最终生成的代码并不总是符合人类的审美偏好,但这没关系。只要产出是正确的、可维护的,并且对未来的 Agent 运行而言是可理解的,它就达到了标准。
人类的审美会持续反馈到系统中。评审评论、重构 PR 以及面向用户的 Bug 都会被转化为文档更新,或直接编码进工具链。当文档不足以约束行为时,我们就将规则晋升为代码。
吞吐量的提升改变了合并哲学
随着 Codex 吞吐量的增加,许多传统的工程规范反而变得适得其反。
仓库运行时的阻塞性合并门槛极低。Pull Request 的生命周期非常短。对于测试偶发失败,通常通过后续运行来解决,而不是无限期地阻塞进度。在一个 Agent 吞吐量远超人类注意力的系统中,纠错是廉价的,而等待是昂贵的。
在低吞吐量的传统环境中,这样做是不负责任的;但在这里,这通常是正确的权衡。
“Agent 生成”的真正含义
当我们说代码库是由 Codex Agent 生成时,我们指的是代码库中的一切。
Agent 产出的内容包括:- 产品代码与测试脚本 - CI 配置与发布工具 - 内部开发者工具 - 文档与设计历史 - 评估框架(Evaluation harnesses)- 评审评论及回复 - 管理仓库本身的脚本 - 生产环境仪表盘的定义文件
人类依然掌控全局,只是工作的抽象层级变了。我们现在的任务是排列优先级、把用户反馈转化为验收标准,并最终对结果进行把关。一旦 Agent 开发受阻,这就是一个明确的信号,提醒我们要去复盘:系统里到底缺了什么?是工具不够,护栏不稳,还是文档有误?找到症结后,我们会把这些反馈注入仓库,但依然坚持让 Codex 自己动手来编写修复方案。
Agent 直接使用我们的标准开发工具。它们获取评审反馈、进行行内回复、推送更新,并且通常会自主压缩(Squash)并合并自己的 PR。
持续提升的自主化水平
随着越来越多的开发环路(测试、验证、评审、反馈处理及故障恢复)被直接编码进系统中,该仓库最近跨越了一个具有里程碑意义的门槛:Codex 已经能够端到端地驱动新特性的开发。
仅需一段提示词,Agent 现在就可以自主完成以下流程:- 验证代码库的当前状态 - 复现报告的 Bug- 录制一段展示故障过程的视频 - 实现修复方案 - 通过操作应用来验证修复结果 - 录制第二段展示修复效果的视频 - 开启 Pull Request- 响应 Agent 及人类的反馈 - 检测并修复构建失败 - 仅在需要人类判断时才上报 - 合并变更
这种行为极度依赖于本仓库特定的结构和工具链。在没有类似投入的情况下,不应假设这种能力可以被直接泛化,至少目前还不行。
熵增与垃圾回收
完全的 Agent 自主权也带来了全新的挑战。Codex 会复制仓库中已有的模式——即便是那些不均衡或非最优的模式。 随着时间的推移,这不可避免地会导致架构偏离。
最初,人类通过手动方式解决这个问题。我们的团队曾固定在每周五(占一周工作时间的 20%)清理“AI 废料”。不出所料,这种模式根本无法扩展。
针对这些问题,我们选择将所谓的“金科玉律”直接写入代码仓库,并建立了一套周期性的清理机制。这些原则是一些带有明确主张的机械化规则,目的是确保代码库在后续的 Agent 运行中始终保持清晰、一致。具体实践包括:第一,我们更倾向于使用共享的工具包,而不是手写辅助函数,这样可以集中管理那些不变量;第二,我们拒绝“全凭运气”的数据探测,必须在边界处进行校验,或者依赖强类型 SDK,防止 Agent 采样猜测的数据形状来编写代码。我们会定期运行一组 Codex 后台任务,专门扫描偏离规则的代码,更新质量评分并开启针对性的重构 PR。由于这些规则非常明确,大部分 PR 在一分钟内就能完成评审并自动合并。
这种机制运行起来就像“垃圾回收”。技术债就像高利贷:连续进行小额偿还,几乎总是优于让其复滚并最终在痛苦的爆发式清理中解决。人类的审美被捕获一次后,便会持续强制执行到每一行代码中。这还让我们能够在日常工作中及时发现并消除不良模式,而不是任由它们在代码库中蔓延数天甚至数周。
我们仍在探索的领域
到目前为止,这套策略在 OpenAI 内部产品的发布和推广中表现良好。通过为真实用户构建真实产品,我们的投入得以为现实需求服务,并引导系统走向长期可维护。
目前我们尚不清楚,在一个完全由 Agent 生成的系统中,其架构连贯性在长达数年的跨度下会如何演进。我们仍在摸索人类判断力在何处能产生最大的杠杆效应,以及如何将这种判断力转化为可沉淀、可产生复利的规则。同时,随着模型能力持续增强,这套系统将如何进化也仍是未知数。
但有一点已经非常明确:构建软件仍然需要严谨的纪律,只不过这种纪律不再体现在代码编写上,而是体现在“脚手架”的搭建上。那些能保持代码库连贯性的工具链、抽象层和反馈循环,正变得愈发重要。
我们现在面临的最艰巨挑战在于如何设计环境、反馈循环和控制系统。唯有如此,才能帮助 Agent 达成我们的目标,即大规模地构建并维护复杂且可靠的软件。
随着 Codex 等 Agent 承担起软件生命周期中越来越多的份额,这些问题将变得至关重要。希望这些早期教训能帮助你思考该在何处投入精力,从而让你能更纯粹地去创造产品。
https://openai.com/index/harness-engineering/
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.