目 录CONTENT

文章目录

驾驭工程:在“智能体优先”世界中利用 Codex

Administrator
2026-02-18 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

📢 转载信息

原文链接:https://openai.com/index/harness-engineering

原文作者:Ryan Lopopolo, Member of the Technical Staff


在过去的五个月里,我们的团队进行了一项实验:构建并发布了一个内部 Beta 软件产品,其中0 行手动编写的代码

该产品拥有内部日常用户和外部 Alpha 测试人员。它进行发布、部署、出现故障,并得到修复。不同之处在于,每一行代码——应用程序逻辑、测试、CI 配置、文档、可观测性以及内部工具——都是由 Codex 编写的。我们估计,使用这种方式构建的时间大约是手工编写代码所需时间的 1/10。

人类引导。智能体执行。

我们故意选择这一限制,目的是构建提升工程速度数量级所需的一切。我们只有几周的时间来发布最终达到一百万行代码量的项目。要做到这一点,我们需要理解,当一个软件工程团队的主要工作不再是编写代码,而是设计环境、明确意图,并构建允许 Codex 智能体可靠工作的反馈循环时,会发生什么变化。

本文将探讨我们通过使用智能体团队构建全新产品中学到的经验——哪些方面出了问题,哪些方面相互促进,以及如何最大限度地利用我们真正稀缺的资源:人类的时间和注意力。

我们从一个空的 Git 仓库开始

首次提交到一个空仓库是在 2025 年 8 月下旬。

最初的脚手架——仓库结构、CI 配置、格式化规则、包管理器设置和应用程序框架——是 Codex CLI 使用 GPT‑5 生成的,并由一套小型现有模板指导。甚至指导智能体如何在仓库中工作的 AGENTS.md 文件本身也是由 Codex 编写的。

一开始,仓库中没有任何预先存在的人工编写的代码。从一开始,仓库的形态就由智能体塑造。

五个月后,该仓库在应用程序逻辑、基础设施、工具、文档和内部开发人员实用工具中包含了大约一百万行代码。在此期间,由三名工程师驱动 Codex 团队共打开并合并了大约 1,500 个 Pull Request。这相当于每位工程师每天的平均吞吐量为 3.5 个 PR,令人惊讶的是,随着团队扩大到七名工程师,吞吐量反而增加了。重要的是,这不仅仅是为了产出而产出:该产品已被数百名内部用户使用,其中包括日常的内部高级用户。

在整个开发过程中,人类从未直接贡献任何代码。这成为团队的一个核心理念:不写任何手动代码

重新定义工程师的角色

缺乏亲自动手编码的引入了另一种工程工作,专注于系统、脚手架和杠杆作用

早期的进展比我们预期的要慢,不是因为 Codex 没有能力,而是因为环境的规范性不足。智能体缺乏实现高层次目标所需的工具、抽象和内部结构。我们工程团队的主要工作变成了赋能智能体执行有用的工作。

在实践中,这意味着要采取深度优先的方式:将较大的目标分解成更小的构建块(设计、代码、审查、测试等),提示智能体构建这些块,并使用它们来解锁更复杂的任务。当出现故障时,修复方法几乎从不是“再努力一点”。由于取得进展的唯一方法是让 Codex 完成工作,人类工程师总是介入任务并问道:“缺少什么能力,我们如何使其对智能体既清晰又可执行?”

人类几乎完全通过提示与系统交互:工程师描述任务,运行智能体,并允许它打开 Pull Request。为了完成一个 PR,我们指示 Codex 在本地审查其更改,请求本地和云端额外的特定智能体审查,响应任何人类或智能体给出的反馈,并在循环中迭代,直到所有智能体审阅者满意为止(这实际上是一个 Ralph Wiggum 循环(opens in a new window))。Codex 直接使用我们的标准开发工具(gh、本地脚本和仓库嵌入式技能)来收集上下文,而无需人类复制粘贴到 CLI 中。

人类可以审查 Pull Request,但并非必须。随着时间的推移,我们已将几乎所有的审查工作推向了由智能体之间处理。

提高应用程序的可读性

随着代码吞吐量的增加,我们的瓶颈变成了人类 QA 能力。由于固定的限制是人类的时间和注意力,我们致力于通过使应用程序 UI、日志和应用程序指标本身直接可供 Codex 读取,来增加智能体的更多能力。

例如,我们使应用程序可以根据 git 工作树启动,以便 Codex 可以为每次更改启动并驱动一个实例。我们还将 Chrome 开发者工具协议接入了智能体运行时,并创建了处理 DOM 快照、屏幕截图和导航的技能。这使 Codex 能够直接重现错误、验证修复并对 UI 行为进行推理。

Diagram titled “Codex drives the app with Chrome DevTools MCP to validate its work.” Codex selects a target, snapshots the state before and after triggering a UI path, observes runtime events via Chrome DevTools, applies fixes, restarts, and loops re-running validation until the app is clean。

我们对可观测性工具也做了同样的事情。日志、指标和跟踪通过一个本地可观测性堆栈暴露给 Codex,该堆栈对于任何给定的工作树都是短暂的。Codex 在一个完全隔离的该应用程序版本上工作——包括其日志和指标,这些都在任务完成后被销毁。智能体可以使用 LogQL 查询日志,使用 PromQL 查询指标。有了这些上下文信息,像“确保服务启动时间少于 800 毫秒”或“这四个关键用户旅程中没有一个跨度超过两秒”这样的提示就变得可以处理了。

Diagram titled “Giving Codex a full observability stack in local dev.” An app sends logs, metrics, and traces to Vector, which fans out data to an observability stack containing Victoria Logs, Metrics, and Traces, each queried via LogQL, PromQL, or TraceQL APIs. Codex uses these signals to query, correlate, and reason, then implements fixes in the codebase, restarts the app, re-runs workloads, tests UI journeys, and repeats in a feedback loop。

我们经常看到单个 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

仓库内知识存储布局。

设计文档被编目和索引,包括验证状态和一组定义智能体优先操作原则的核心信念。架构文档(opens in a new window) 提供了域和包分层的顶层地图。质量文档对每个产品域和架构层进行评分,随着时间的推移跟踪差距。

计划被视为一等工件。瞬态的轻量级计划用于小型更改,而复杂的工程则记录在带有进度和决策日志的执行计划(opens in a new window) 中,这些日志被提交到仓库中。活动的计划、已完成的计划和已知的技术债务都经过版本控制并共置,使智能体能够在不依赖外部上下文的情况下运行。

这实现了渐进式披露:智能体从一个小的、稳定的入口点开始,并被告知下一步在哪里查找,而不是一开始就被信息淹没。

我们通过机械方式强制执行这些规则。专用的 linter 和 CI 作业验证知识库是最新的、交叉链接的且结构正确。一个定期的“文档整理”智能体会扫描不反映真实代码行为的过时或过期的文档,并打开修复 Pull Request。

智能体可读性是目标

随着代码吞吐量的增加,Codex 的设计决策框架也需要随之发展。

因为仓库完全由智能体生成,所以它首先是为Codex的可读性而优化的。就像团队旨在提高代码对新工程招聘人员的可导航性一样,我们人类工程师的目标是使智能体能够直接从仓库本身对完整的业务领域进行推理。

从智能体的角度来看,任何它在有效运行时无法在上下文内访问的东西都不存在。存在于 Google 文档、聊天线程或人们头脑中的知识对系统是不可访问的。仓库本地的、经过版本化的工件(例如,代码、Markdown、Schema、可执行计划)是它能看到的一切。

Diagram titled “The limits of agent knowledge: What Codex can’t see doesn’t exist.” Codex’s knowledge is shown as a bounded bubble. Below it are examples of unseen knowledge—Google Docs, Slack messages, and tacit human knowledge. Arrows indicate that to make this information visible to Codex, it must be encoded into the codebase as markdown.

我们发现需要随着时间的推移将越来越多的上下文推送到仓库中。Slack 中就架构模式达成一致的讨论?如果智能体无法发现它,那么它对新员工来说就像对三个月后加入的同事一样是不可读的。

为 Codex 提供更多上下文意味着组织和公开正确的信息,以便智能体可以对其进行推理,而不是用临时指令来淹没它。就像你会向新团队成员介绍产品原则、工程规范和团队文化(包括表情符号偏好)一样,向智能体提供这些信息可以带来更协调的输出。

这种框架阐明了许多权衡。我们倾向于那些可以完全在仓库中内化和推理的依赖项和抽象。通常被称为“无聊”的技术往往更容易被智能体建模,因为它们的组合性、API 稳定性和在训练集中的表示性更强。在某些情况下,让智能体重新实现部分功能比处理公共库中不透明的上游行为更划算。例如,我们没有引入通用的 p-limit 风格的包,而是实现了我们自己的带并发的 Map:它与我们的 OpenTelemetry 仪器紧密集成,具有 100% 的测试覆盖率,并且其行为完全符合我们运行时的预期。

将系统更多地纳入智能体可以直接检查、验证和修改的形式中,可以增加杠杆作用——不仅对 Codex,也对正在处理代码库的其他智能体(例如 Aardvark)如此。

执行架构和品味

仅仅依靠文档无法使完全由智能体生成的代码库保持一致性。通过执行不变量,而不是微观管理实现,我们让智能体快速发布而不会破坏基础。 例如,我们要求 Codex 在边界处解析数据形状,但不对如何实现这一点做出规定(该模型似乎喜欢 Zod,但我们没有指定特定的库)。

智能体在具有严格边界和可预测结构的环境中最为有效,因此我们围绕一个刚性的架构模型构建了应用程序。每个业务域被划分为一组固定的层,具有严格验证的依赖方向和一组允许的边。这些约束通过自定义 linter(当然也是 Codex 生成的!)和结构测试来机械执行。

下图显示了规则:在每个业务域内(例如,应用设置),代码只能通过一组固定的层“向前”依赖(类型 → 配置 → 仓库 → 服务 → 运行时 → UI)。横向关注点(身份验证、连接器、遥测、功能标志)通过一个明确的接口进入:提供者(Providers)。任何其他内容都是不允许的,并通过机械方式强制执行。

Diagram titled “Layered domain architecture with explicit cross-cutting boundaries.” Inside the business logic domain are modules: Types → Config → Repo, and Providers → Service → Runtime → UI, with App Wiring + UI at the bottom. A Utils module sits outside the boundary and feeds into Providers.

这种架构通常是你直到拥有数百名工程师后才会推迟的类型。对于智能体来说,它是一个早期的先决条件:约束条件是无需衰减或架构漂移即可实现速度的关键。

在实践中,我们使用自定义 linter 和结构测试以及一小组“品味不变量”来执行这些规则。例如,我们使用自定义 lint 静态地强制执行结构化日志记录、Schema 和类型的命名约定、文件大小限制以及特定于平台的可靠性要求。因为 lint 是自定义的,所以我们编写错误消息以将补救说明注入到智能体上下文中。

在以人为本的工作流程中,这些规则可能感觉很死板或有约束性。对于智能体来说,它们变成了乘数:一旦编码,它们就会同时应用于所有地方。

与此同时,我们明确了约束条件在何处重要,在何处不重要。这类似于领导大型工程平台组织:在中央强制执行边界,在本地允许自主权。你非常关心边界、正确性和可重复性。在这些边界内,你允许团队——或智能体——在解决方案的表达方式上有很大的自由度。

生成的代码并不总是符合人类的风格偏好,但这没关系。只要输出是正确的、可维护的,并且对未来的智能体运行是可读的,它就达到了标准。

人类的品味会持续反馈到系统中。审查评论、重构 Pull Request 和面向用户的错误会作为文档更新捕获,或直接编码到工具中。当文档不足时,我们将规则提升到代码中。

吞吐量改变了合并理念

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

仓库以最少的阻塞性合并门槛运行。Pull Request 的生命周期很短。测试抖动通常通过后续运行来解决,而不是无限期地阻止进度。在一个智能体吞吐量远超人类注意力的系统中,纠正成本很低,而等待成本很高。

在低吞吐量环境中,这样做是不负责任的。在这里,它通常是正确的权衡。

“智能体生成”的真正含义

当我们说代码库是由 Codex 智能体生成的时,我们指的是代码库中的所有内容。

智能体生成以下内容:

  • 产品代码和测试
  • CI 配置和发布工具
  • 内部开发工具
  • 文档和设计历史
  • 评估工具包
  • 审查评论和回复
  • 管理仓库本身的脚本
  • 生产仪表板定义文件

人类始终处于循环中,但他们工作的抽象层次与我们过去不同。我们确定工作的优先级,将用户反馈转化为验收标准,并验证结果。当智能体遇到困难时,我们将其视为一个信号:确定缺少什么——工具、护栏、文档——并将其反馈到仓库中,始终由 Codex 本身来编写修复程序。

智能体直接使用我们的标准开发工具。它们拉取审查反馈,内联回复,推送更新,并经常压缩和合并自己的 Pull Request。

提高自主级别

随着开发循环的更多部分直接编码到系统中——测试、验证、审查、反馈处理和恢复——仓库最近跨越了一个有意义的阈值,在此之后 Codex 可以端到端地驱动新功能。

给定一个单一的提示,智能体现在可以:

  • 验证代码库的当前状态
  • 重现报告的错误
  • 录制演示故障的视频
  • 实现修复
  • 通过驱动应用程序来验证修复
  • 录制演示解决方案的第二个视频
  • 打开 Pull Request
  • 响应智能体和人类的反馈
  • 检测并修复构建失败
  • 仅在需要判断时升级给人类
  • 合并更改

此行为在很大程度上取决于该仓库的特定结构和工具,在进行类似投入之前,不应假定它可以泛化——至少目前不能。

熵和垃圾回收

完全的智能体自主性也带来了新问题。 Codex 会复制仓库中已存在的模式——即使是参差不齐或次优的模式。随着时间的推移,这不可避免地会导致漂移。

最初,人类手动解决了这个问题。我们的团队过去每周五(占工作周的 20%)都会清理“AI 废料”。不出所料,这无法扩展。

相反,我们开始将我们称之为“黄金原则”的内容直接编码到仓库中,并构建了一个经常性的清理过程。这些原则是主观的、机械的规则,它们能让代码库对未来的智能体运行保持可读和一致。例如:(1)我们倾向于共享实用工具包而不是手工编写的助手,以保持不变量的集中化;(2)我们不会“随心所欲地”探测数据——我们会验证边界或依赖于类型化的 SDK,以便智能体不会意外地基于猜测的形状构建东西。在固定的时间表上,我们有一组后台 Codex 任务,它们会扫描偏差、更新质量等级并打开有针对性的重构 Pull Request。其中大部分可以在一分钟内审查并自动合并。

这类似于垃圾回收。技术债务就像高息贷款:持续不断地以小额增量偿还,通常比让其累积并在痛苦的爆发中解决它要好。人类的品味被捕获一次,然后持续应用于每一行代码。这也使我们能够每天捕获和解决不良模式,而不是让它们在代码库中扩散数天或数周。

我们仍在学习什么

到目前为止,这种策略在内部发布并在 OpenAI 内部得到采用后,一直运行良好。为真实用户构建真实产品有助于将我们的投入锚定在现实中,并引导我们走向长期的可维护性。

我们尚不清楚一个完全由智能体生成的系统的架构一致性在多年内会如何演变。我们仍在学习人类判断在哪里能增加最大的杠杆作用,以及如何编码这些判断以便它们能累积起来。我们也不知道随着模型不断变得更强大,这个系统将如何发展。

明确的是:构建软件仍然需要纪律,但这种纪律更多地体现在脚手架而不是代码中。工具、抽象和反馈循环是使代码库保持一致性,并且变得越来越重要。

我们目前最困难的挑战集中在设计环境、反馈循环和控制系统上,这些系统可以帮助智能体完成我们的目标:以规模化构建和维护复杂、可靠的软件。

随着像 Codex 这样的智能体承担软件生命周期中越来越大的部分,这些问题将变得更加重要。我们希望分享一些早期经验教训能帮助您思考在哪里投入精力,以便您可以只管构建事物

Author

Ryan Lopopolo

Acknowledgements

特别感谢 Victor Zhu 和 Zach Brock 为本文做出的贡献,以及为构建这个新产品付出的整个团队。




🚀 想要体验更好更全面的AI调用?

欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。

0

评论区