找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1533

积分

0

好友

203

主题
发表于 19 小时前 | 查看: 2| 回复: 0

在过去的五个月里,我们团队进行了一项极限挑战:从头开发并发布一款内部产品,过程中完全没有人工编写任何一行代码。

如今,这款产品已拥有活跃的内部用户与外部的 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 个 Pull Request (PR)。这意味着平均每位工程师每天产出 3.5 个 PR。令人惊讶的是,当团队扩大到 7 人时,人均产出率反而进一步提升。

更重要的是,这并非为了刷量而进行的无效产出:该产品已被数百名内部用户使用,其中包括每天重度依赖它的核心用户。在整个开发周期中,人类从未直接贡献过任何一行代码。这逐渐成为了团队的核心哲学:坚决拒绝人工编写代码。

重新定义工程师的角色

由于不再亲自动手写代码,工程师的工作重心彻底转向了系统设计、脚手架搭建和效能杠杆。

项目早期的进展比预期要慢,但这并非因为 Codex 能力不足,而是因为环境的“规范性”不够。Agent 缺乏实现高层目标所必需的工具、抽象和内部结构。因此,工程团队的首要任务变成了:赋能 Agent,使其能够有效地开展工作。

在实践中,这意味着采用一种深度优先的工作方式:将宏大的目标拆解为微小的构建块(包括设计、代码、评审、测试等)。驱动 Agent 去构建这些块。然后,利用这些已存在的块去解锁更复杂的任务。当任务失败时,修复方案几乎从来不是“再试一次”。因为必须通过 Codex 来推进工作,人类工程师会介入并思考:“我们缺失了什么关键能力?如何才能让这种能力对 Agent 而言既清晰可见又可强制执行?”

人类与系统的交互几乎完全通过提示词完成:工程师描述一项任务,运行 Agent,并授权其开启一个 Pull Request。为了推动 PR 最终合并,我们会指示 Codex 在本地审查自己的代码改动,并请求其他特定的 Agent(无论是在本地还是云端)进行交叉评审。Codex 会根据人类或其他 Agent 给出的反馈进行响应,并在循环中不断迭代,直到所有 Agent 评审员都感到满意——这实际上形成了一个自洽的反馈闭环。Codex 直接调用我们的标准开发工具(如 GitHub CLI gh、本地脚本以及集成在仓库中的技能),自主获取所需上下文,无需人类在命令行中手动复制粘贴。

虽然人类可以审查 PR,但这并非强制要求。随着时间的推移,我们已将几乎所有的代码评审工作都移交给了 “Agent 对 Agent” 的协作模式。

增加应用的“可读性”

随着代码产出率的飙升,我们的瓶颈变成了人类的质量保证(QA)能力。由于人类的时间和注意力始终是唯一的稀缺资源,我们致力于通过让应用的用户界面(UI)、日志和指标对 Codex 直接可见且可理解,从而为 Agent 赋予更多能力。

例如,我们使应用程序能够针对每个 Git 工作树(worktree)独立启动,这样 Codex 就可以为每一次代码变更运行并驱动一个专属的应用实例。我们还将 Chrome DevTools Protocol (CDP) 接入 Agent 运行时,并创建了处理 DOM 快照、截图和导航的技能。这使得 Codex 能够直接复现 Bug、验证修复结果并推导 UI 行为。

Codex通过Chrome DevTools MCP驱动并验证应用的工作流程

我们对可观测性工具也做了同样的处理。日志、指标和分布式链路追踪通过一个本地的、临时性的可观测性栈暴露给 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 行)被注入到每次任务的上下文中,它主要充当“地图”的角色,包含指向分布在仓库各处的更深层“事实来源”的指针。

AGENTS.md
ARCHITECTURE.md
docs/
├── design-docs/
│   ├── index.md
│   ├── core-beliefs.md
│   └── ...
├── exec-plans/
│   ├── active/
│   ├── completed/
│   └── tech-debt-tracker.md
├── generated/
│   └── db-schema.md
├── product-specs/
│   ├── index.md
│   ├── new-user-onboarding.md
│   └── ...
├── references/
│   ├── design-system-reference-llms.txt
│   ├── nixpacks-llms.txt
│   ├── uv-llms.txt
│   └── ...
├── DESIGN.md
├── FRONTEND.md
├── PLANS.md
├── PRODUCT_SENSE.md
├── QUALITY_SCORE.md
├── RELIABILITY.md
└── SECURITY.md

设计文档被系统编目和索引,其中包含验证状态以及一套定义了“Agent 优先”运营原则的核心信条。架构文档提供了一个关于领域划分和包分层的顶级地图。一份质量文档则会对每个产品领域和架构层级进行评分,并长期跟踪其中的差距。

计划(Plans)被当作一等公民对待。 临时性的轻量计划用于微小的变更,而复杂的工作则会被详细记录在执行计划中,连同进度和决策日志一起提交到仓库进行版本管理。活跃计划、已完成计划以及已知的技术债都会放在一起,使 Agent 能够无需依赖任何外部上下文(如 Jira、Notion)即可自主开展工作。

这实现了渐进式披露:Agent 从一个微小、稳定的入口点(AGENTS.md)开始,并被告知下一步该去哪里寻找更具体的信息,而不是一开始就被海量的信息所淹没。

我们通过机械化手段强制执行这一点。专门的 Linter 和 CI 任务会验证知识库是否处于最新状态、是否正确进行了交叉引用以及结构是否符合规范。一个循环运行的“文档园丁”Agent 会持续扫描那些无法反映真实代码行为的陈旧或过时文档,并主动开启修复类 PR。

以“Agent 可读性”为目标

随着代码库的演进,Codex 的设计决策框架也随之不断进化。

由于整个仓库完全由 Agent 生成,它首先针对 Codex 的可读性 进行了优化。正如开发团队致力于为新入职工程师提高代码的可导航性一样,我们人类工程师的目标是让 Agent 能够直接从仓库本身推导并理解完整的业务领域知识。

从 Agent 的视角来看,任何在运行时无法通过其上下文获取的信息,实际上就等同于不存在。存储在 Google Docs、聊天记录或仅仅存在于人们大脑中的隐性知识,系统是无法访问的。只有仓库本地的、版本化的工件(如代码、Markdown 文档、Schema、可执行计划)才是它可见的全部世界。

Codex知识局限性:任何它无法看见的知识对系统而言都不存在

我们意识到,随着时间的推移,我们需要将越来越多的关键上下文“推入”仓库。比如那次让团队在某个重要架构模式上达成一致的 Slack 讨论,如果它对 Agent 来说是不可检索的,那么它就是“不可读”的——这就像对于三个月后入职的新员工来说,这段关键的背景信息是完全缺失的一样。

赋予 Codex 更多上下文,意味着需要精心组织并暴露正确的信息,以便 Agent 进行有效推理,而不是用大量的临时指令让它不堪重负。就像你会向新队友系统性地介绍产品原则、工程规范和团队文化(甚至包括表情符号的使用偏好)一样,向 Agent 提供这些结构化信息会带来更加一致和符合预期的产出。

这种思路让许多技术选型上的权衡变得异常清晰。我们更青睐那些可以被完全内化并在仓库内进行逻辑推理的依赖项和抽象。那些通常被称为“乏味”或“基础”的技术,往往因为其组合性、API 稳定性和在模型训练集中的高覆盖率,反而更容易被 Agent 准确建模。在某些情况下,让 Agent 重新实现一部分功能,比试图绕过公共库中不透明的上层行为成本更低。例如,我们没有引入通用的 p-limit 风格的并发控制包,而是实现了自己的并发映射助手:它与我们的 OpenTelemetry 监控紧密集成,拥有 100% 的测试覆盖率,并且其行为完全符合我们运行时的特定预期。

将系统的更多部分转化为 Agent 可以直接检查、验证和修改的形式,不仅极大地提升了 Codex 的杠杆效能,也同样造福了其他在同一代码库中工作的 Agent。

强制执行架构与审美

仅靠文档并不足以保持一个完全由 Agent 生成的代码库的长期连贯性。通过强制执行“架构不变量”而非微观管理具体实现细节,我们让 Agent 在保持高速交付的同时,不会破坏系统的根基。例如,我们要求 Codex 在系统边界处必须进行严格的数据格式验证与解析,但并不强制规定具体的实现方式或库(模型似乎偏好使用 Zod,但我们从未在规则中指定过这个库)。

Agent 在边界严格且结构可预测的环境中效率最高。因此,我们围绕一套僵化的架构模型构建了整个应用。每个业务领域被清晰地划分为一组固定的层级,拥有经过严格验证的依赖方向和数量有限的允许连接点。这些约束通过自定义 Linter(当然,这些 Linter 本身也是由 Codex 生成的!)和结构化测试进行机械化强制执行。

下图清晰地展示了这一规则:在每个业务领域(如“应用设置”)内,代码只能沿着一组固定的层级“向前”依赖(类型定义 → 配置 → 仓库层 → 服务层 → 运行时 → UI)。所有跨领域的关注点(如认证、外部连接器、遥测、特性开关)都通过单一且明确的接口进入:即提供者(Providers)。除此之外的任何依赖都是被严格禁止的,并由上述的机械化手段强制执行。

分层领域架构与明确的跨域边界

这种级别的架构约束通常是在公司拥有数百名工程师后才会考虑推行的大型治理项目。但在使用编程 Agent 时,它是一项前置的必要条件:正是这些明确的约束,才使得系统在经历高速迭代的同时,不会出现不可控的架构腐化或偏离。

在实践中,我们通过自定义 Linter、结构化测试以及一小套“审美不变量”来执行这些规则。例如,我们通过静态检查强制要求:所有日志必须结构化记录、架构和类型的命名必须遵循统一规范、单个文件大小不得超过限制,以及必须满足针对特定平台的可靠性要求。由于 Linter 是自定义的,我们可以编写专门的、对人类友好的错误信息,甚至可以将具体的修复指令直接注入到 Agent 的上下文中,引导其快速修正。

在以人类为中心的传统工作流中,这些规则可能显得过于死板或限制创造力。但在 Agent 主导的开发环境下,它们变成了强大的效能倍增器:规则一旦被编码固化,就会立即且一致地应用于所有地方。

与此同时,我们明确区分了哪些地方需要中央集权式的严格约束,哪些地方可以放权。这非常像领导一个大型工程平台组织:中央平台团队强力执行边界、正确性和可复现性;而在这些清晰的边界之内,则允许各业务团队(或 Agent)在表达和实现具体解决方案时拥有极大的自由度。

最终由 Agent 生成的代码并不总是完全符合人类工程师的个人审美偏好,但这没关系。只要产出在功能上是正确的、在长期是可维护的,并且对未来的 Agent 运行而言是清晰可理解的,它就达到了我们的核心标准。

人类的审美偏好会持续反馈到系统中。评审评论、成功的重构 PR 以及面向用户的 Bug 修复案例,都会被转化为文档更新,或直接编码进自动化工具链。当发现文档不足以有效约束行为时,我们就将规则“晋升”为可执行的代码。

吞吐量的提升改变了合并哲学

随着 Codex 吞吐量的指数级增加,许多传统的工程规范反而变得适得其反。

我们在仓库运行时设定了极低的阻塞性合并门槛。Pull Request 的生命周期被设计得非常短暂。对于测试中出现的偶发性失败(Flaky Test),我们的策略通常是通过后续的自动重运行来解决,而不是无限期地阻塞当前进度。在一个 Agent 的吞吐量远超人类注意力带宽的系统中,事后纠错的成本是相对廉价的,而等待和阻塞的代价则是昂贵的。

在低吞吐量的传统研发环境中,这种做法可能被视为不负责任;但在这里,这通常是正确的工程权衡。

“Agent 生成”的真正含义

当我们说这个代码库是由 Codex Agent 生成时,我们指的是代码库中的一切

Agent 产出的内容包括:

  • 核心产品代码与完整的测试脚本套件
  • CI/CD 流水线配置与发布工具链
  • 内部开发者效率工具
  • 所有文档与设计决策历史
  • 评估框架(Evaluation harnesses)
  • 代码评审评论及回复
  • 管理仓库本身的各种自动化脚本
  • 生产环境监控仪表盘的定义文件

人类依然掌控着全局方向和最终决策,只是工作的抽象层级发生了根本变化。我们现在的核心任务是排列优先级、将模糊的用户反馈转化为精确的验收标准,并最终对产出结果进行质量把关。一旦 Agent 在某个开发任务上持续受阻,这本身就是一个明确的信号,提醒我们人类工程师需要介入复盘:系统里到底缺了什么关键元素?是工具能力不足,还是安全护栏不稳,或者是引导文档有误?找到症结后,我们会把这些反馈精确地注入仓库的规范或工具中,但依然坚持让 Codex 自己动手来编写具体的修复方案。

Agent 直接使用我们团队的标准开发工具链。它们自主获取评审反馈、进行行内回复、推送代码更新,并且通常会自主完成压缩(Squash)并合并自己的 PR。

持续提升的自主化水平

随着越来越多的开发反馈环路(包括测试、验证、评审、反馈处理及故障恢复)被直接编码进系统中,该仓库最近跨越了一个重要的里程碑:Codex 已经能够端到端地驱动全新特性的完整开发流程。

仅需一段描述清晰的提示词,Agent 现在就可以自主完成以下全链路流程:

  • 验证代码库的当前健康状态
  • 精确复现被报告的 Bug
  • 录制一段展示故障过程的视频
  • 实现并提交修复方案
  • 通过实际操作应用来验证修复结果
  • 录制第二段展示修复后正常效果的视频
  • 开启一个包含所有改动的 Pull Request
  • 响应其他 Agent 及人类可能提出的反馈
  • 检测并自动修复可能导致的构建失败
  • 仅在遇到需要人类高级判断的模糊情况时才会上报
  • 最终自主合并变更

必须强调的是,这种高度自主的行为极度依赖于本仓库特定的组织结构、工具链和已编码的规则。在没有进行类似深度投入和定制化构建的情况下,不应假设这种端到端能力可以被直接泛化到其他项目,至少目前还不行。

熵增与垃圾回收

完全的 Agent 自主权也带来了全新的挑战。Codex 会学习和复制仓库中已有的模式——即便是那些最初设计不均衡或并非最优的模式。随着时间的推移,这种模式复制不可避免地会导致架构上的细微偏离和“熵增”。

最初,人类通过手动方式解决这个问题。我们的团队曾固定在每周五(约占一周工作时间的20%)进行“AI 废料”清理。不出所料,这种依赖人工的清理模式根本无法跟上 Agent 的产出速度,完全不可扩展。

针对这些问题,我们选择将所谓的“金科玉律”直接写入代码仓库的规范中,并建立了一套周期性、自动化的清理机制。这些原则是一些带有明确主张和可执行定义的机械化规则,目的是确保代码库在后续无数次的 Agent 运行中始终保持清晰、一致和高质量。具体实践包括:
第一,我们更倾向于使用集中管理的共享工具包,而不是散落在各处的手写辅助函数,这样可以集中管理和演进那些关键的不变量;
第二,我们坚决拒绝“全凭运气”的数据探测(Data Probing),必须在系统边界处进行强校验,或者依赖具有强类型定义的 SDK,防止 Agent 通过采样猜测的数据形状来编写脆弱的代码。

我们会定期运行一组 Codex 后台任务,专门扫描偏离这些核心规则的代码,更新全局质量评分文档,并主动开启针对性的重构 PR。由于这些规则定义得非常明确且可机械化判断,大部分此类清理 PR 都能在一分钟内完成自动评审并合并。

这种机制运行起来就像编程语言中的“垃圾回收(Garbage Collection)”。技术债就像高利贷:持续进行小额、高频的偿还,几乎总是优于让其利滚利,最终在某个时间点不得不进行痛苦的、爆发式的大清理。人类的优秀工程审美被捕获并编码一次后,便会持续、自动地强制执行到未来新增的每一行代码中。这还让我们能够在日常工作中及时发现并消除刚出现的不良模式,而不是任由它们在代码库中悄悄蔓延数天甚至数周。

我们仍在探索的领域

到目前为止,这套策略在我们构建和发布 OpenAI 内部产品的过程中表现良好。通过为真实用户构建解决真实需求的产品,我们的所有工程投入都能服务于现实业务目标,并自然地引导整个系统走向长期可维护。

目前我们尚不清楚,在一个完全由 Agent 生成并维护的系统中,其架构的连贯性和代码健康度在长达数年的跨度下会如何演进。我们仍在不断摸索,人类的专业判断力在何处能产生最大的杠杆效应,以及如何将这种判断力高效地转化为可沉淀、可产生复利的自动化规则。同时,随着底层大模型能力的持续快速增强,这套高度定制化的系统将如何进化也仍是未知数。

但有一点已经变得非常明确:构建复杂、可靠的软件仍然需要极致的严谨和纪律,只不过这种纪律的表现形式发生了转移。 它不再主要体现在一行行代码的编写上,而是体现在“脚手架”的搭建上——即那些能定义环境、约束行为、提供反馈的系统性设计上。那些能保持大规模代码库长期连贯性的工具链、抽象层和自动化反馈循环,正变得前所未有的重要。

我们现在面临的最艰巨挑战在于如何创新性地设计环境、构建高效的反馈循环和控制系统。唯有如此,才能帮助 Agent 达成我们的终极目标:在大规模上持续构建并维护复杂且高度可靠的软件系统。

随着 Codex 及其他先进 Agent 承担起软件生命周期中越来越多的实质性工作份额,上述这些问题将变得至关重要。希望我们这些早期的实践经验与教训,能帮助你思考该在何处投入宝贵的工程精力,从而让你能更聚焦、更高效地去创造有价值的产品。

本文编译自 OpenAI 官方博客,原文链接:https://openai.com/index/harness-engineering/

关于如何利用 AI 提升工程效能,你有哪些独特的实践或思考?欢迎在 云栈社区 的“智能 & 数据 & 云”板块与更多开发者交流探讨。




上一篇:SAP AI战略演进:从嵌入式助手到无应用(No-App)ERP的颠覆之路
下一篇:智力不再稀缺时,AI创业者如何面对制度惯性与个人选择?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-25 21:49 , Processed in 0.451809 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表