OpenAI 也把工程师经验“蒸馏”进 skill 了,Harness 爆文作者曝内部玩法:一个百万行代码系统,全程零人工编码和审核
最近,OpenAI 的 Ryan Lopopolo 前不久发了一篇很长的文章《Harness engineering》,成为圈子里的热门话题。
在那篇文章里,Ryan 第一次比较系统地揭开了 OpenAI 新近成立的 Frontier 团队究竟是如何工作的:这个团队如今已经成了 OpenAI 内部对 Codex 使用最重度的团队。他们维护着一个代码量超过一百万行的代码库,而且整套系统里,没有一行代码是人工手写的。更关键的是,在代码合并之前,也没有人工参与代码审查。
Ryan 对这套方法几乎可以说抱有一种传教士般的热情。他甚至直言,如果你现在每天还不用超过十亿 tokens,那几乎都快算得上“失职”了。按照当前市场价格和缓存假设来估算,这大概意味着每天要花掉两三千美元的 token 成本。
在过去几个月里,他们做了一场非常极端的实验:从零开始构建并交付一个内部测试产品,整个过程里,没有任何一行代码是人工写出来的。在这个实验中,他们逐渐形成了一种完全不同的工程工作方式:当 agent 失败时,团队不再想着“换个提示词试试”,或者让它“再努力一点”,而是反过来追问:到底缺的是哪一种能力、哪一类上下文,或者哪一层结构?
这个实验最终产出了 Symphony。它被 Ryan 形容为一个“幽灵库”(ghost library),同时也是一个参考性的 Elixir 实现,由 Alex Kotliarskyi 完成。它的作用,是搭起一整套庞大的 Codex agent 系统。每个 agent 都会被喂入极其细致的提示信息,精细程度接近一份真正的产品需求文档,但又不会直接给出完整实现。
于是,未来的轮廓开始变得越来越清晰:coding agent 不再只是坐在你旁边的副驾驶(copilot),而是在逐渐变成任何人都可以真正调用的“队友”。而 Codex 也在沿着这条方向持续加码,甚至在对外发出了强势信息:你只需要直接开始构建就行。
Ryan 一直在推动一件事:如果你不再围绕人的使用习惯来优化代码库、工作流和组织,而是转向围绕 agent 的可读性来优化,最后会发生什么?
在参与 Latent Space 和 AI Engineer 的播客期间,详细分享了 Harness Engineering 这个概念最初是怎么来的,以及推动整场实验启动的那个核心约束:Ryan 一开始就刻意不自己写代码,逼着 agent 必须从头到尾把事情做完。
还有 OpenAI 内部团队到底是怎么使用 Codex 的;为什么在 AI 原生软件开发里,真正的瓶颈变成了人的注意力;他们为什么会如此痴迷于构建速度:为什么“一分钟”被设定成内部循环(inner loop)的上限,以及团队如何一遍遍重做构建系统,只为保证 agent 能始终保持高效产出等。
我们对原对话进行了翻译和整理,并在不改变原意基础上进行了部分删减,以飨读者。
有无限的 token,“零人工写码”做产品
swyx:你最近写了一篇关于 harness engineering 的重磅文章,它很可能会成为这个新兴方向最有代表性的一篇文章。
Ryan Lopopolo:谢谢。我觉得这件事挺有意思的,好像我们某种程度上真的先把这场讨论的框架立起来了。
swyx:这应该是你第一次上播客。那先说说,你现在在哪个团队?做的又是什么?
Ryan Lopopolo:可以。我现在在 Frontier Product Exploration 团队,做的是 OpenAI Frontier 这条线上的新产品开发。OpenAI Frontier 本质上是我们的企业平台,目标是让企业可以以大规模、可治理而且安全的方式部署 agent。我们这个团队的职责,就是去探索一些新的方法,看看怎么把模型包装成企业真正愿意买单的产品和解决方案。
swyx:我顺带把你的背景也补充一下。你之前在 Snowflake、Brex、Stripe、Citadel 待过。
Ryan Lopopolo:对,基本上这辈子都在服务企业客户。
Vibhu:我得说一句,我之前看你 Twitter 的时候,其实没想到你是这样的背景,因为你在网上整个人的气质,完全是那种“AI 直接梭哈”“coding all in”“坐 Waymo 也得把电脑扣在腿上继续干”的感觉。结果我一看你的履历,发现你又完全是另一种。然后我就想,“哦,这反而太合理了。”
Ryan Lopopolo:我觉得,如果你真要活成一个 AI 极致主义者,那 OpenAI 确实是最适合的地方。
swyx:你们最不缺的就是 token,是吧。
Ryan Lopopolo:对。内部没有速率限制,这确实帮了大忙。所以我真的可以像你说的那样,彻底 all in。
swyx:也就是说,Frontier 下面,你们又是一个相对特别的团队。
Ryan Lopopolo:对。公司确实给了我们一块可以“自己发挥”的空间,这点特别让人兴奋。
这也是为什么,我一开始给自己设了一个听起来有点夸张的限制:我不自己写任何代码。我的想法很简单:如果我们要做的是那些未来能真正部署进企业的 agent,那它们就应该能完成我平时做的那些事情。而我和这些 coding model、coding harness 一起工作了好几个月之后,我确实感觉,不管是模型本身还是 harness 这层能力,都已经发展到某种程度上和我“同构”了。也就是说,在干活能力这件事上,它们已经足够接近我。
所以,当我一开始就给自己加上“不能亲自写代码”这个约束后,我想完成自己工作的唯一办法就只剩下一个:让 agent 来替我把工作做完。
模型搞不定时,问题不一定出在提示词
Vibhu:这其实就是你那篇文章讲的核心实验。你们做的是,在几个月时间里,围绕一个内部工具做开发,没人工手写代码,整个代码库累计超过一百万行代码。你还说,这基本上比你自己亲手写还要更快。也就是说,这就是你们一开始的思路?
Ryan Lopopolo:对,就是这个意思。
我们一开始用的还是 Codex CLI 很早期的版本,搭配的是 Codex Mini 模型。它当然远不如我们今天手里的模型强,但其实反而是个很好的约束。因为那种感觉非常直接:你让模型去帮你做一个产品功能,它就是拼不起来,根本没法把那些部件完整组装起来。
也正是这种挫败感,逼着我们慢慢形成了一套心法:每当模型就是做不出来的时候,你必须立刻把任务拆开,深入进去做出更小的基础组件,然后再把它们组装回大目标中。
说实话,这个过程一开始是很痛苦的。头一个多月,我们的速度大概只有我自己正常写代码时的十分之一。但正因为我们前面付了这笔“学费”,后面才真正搭出了一整套工具和构建栈,让 agent 最终能把整件事做下来。而一旦这套东西成型,它的生产力就远远超过了任何一个单独的工程师。
后来,我们一路经历了 GPT-5、5.1、5.2、5.3、5.4 这些模型迭代。你会很直观地感受到,每一代模型都有自己的怪脾气,也有各自不同的工作方式。这意味着,当模型升级时,我们不得不连代码库一起调整,跟着它去“换挡”。
一个特别有意思的例子是,在 5.2 那一代,Codex harness 还没有后台 shell 这个能力,所以那时候,我们还能依赖一些阻塞式脚本去做长时间任务。但到了 5.3 有了后台 shell 之后,模型就变得没那么有耐心了,不太愿意一直卡在那儿等。于是,我们不得不把整个构建系统都重做一遍,目标就是让构建时间控制在一分钟以内。
如果是一个正常人类团队在维护代码库的话,我几乎觉得这是不可能做到的事。因为人会有自己的偏好,会有各种争论,会纠结到底该不该折腾,但当时我们的唯一目标,就是在一周的尺度上把 agent 的生产力最大化。所以我们一路从自定义的 Makefile 构建,切到了 Bazel,又切到 Turbo,再切到 Nx,最后哪边快就在哪边停下来。
为什么把构建时间死死压在一分钟以内
swyx:挺有意思的,你多讲讲 Turbo 和 Nx 吧,因为别人往往是在往另一个方向走。
Ryan Lopopolo:说实话,我自己在前端仓库架构这块,并没有特别多的实战经验。
swyx:你说 Jessica 搭了整套系统,我认识 Nx 团队,也认识 Jared Palmer 和 Turbo 那边的人。我就会觉得这种对比还挺有意思的。
Ryan Lopopolo:但我们当时要“爬的那座山”,其实就一件事:让它更快。
swyx:这里面有 micro frontend 吗?还是 React 复杂度很高?
Ryan Lopopolo:是一个基于 Electron 的单体应用,差不多就是这种结构。
swyx:而且必须控制在一分钟以内?这个限制挺有意思的。我其实对后台 shell 那块不是特别熟,应该是在 5.3 的发布里提到过。
Ryan Lopopolo:基本上就是,Codex 可以在后台拉起一些命令,然后在等待它们执行完的同时,继续去做别的事。比如说,它可以先启动一个特别耗时的 build,然后自己一边等,一边去 review 代码。这样对使用 harness 的人来说,时间利用率就会高很多。
swyx:那为什么是一分钟,不是五分钟?
Ryan Lopopolo:因为我们想把 inner loop(内部循环)压到尽可能快。一分钟只是一个很圆整、也确实能达到的目标。
swyx:如果一分钟没跑完,会直接 kill 掉吗?
Ryan Lopopolo:不会。我们只是把它当作一个信号,说明现在得停下来,重新梳理任务,我们要把构建图谱(Build Graph)拆解得更细,直到把复杂度降到阈值以下,好让 Agent 继续高效运行。
swyx:这感觉像一种棘轮机制。你是在用一种非常强硬的方式,逼自己死守构建速度这条底线。因为你不这么做,时间就会越来越长。你也提到,你现在自己在做的软件,构建时间已经十二分钟了,那体验特别差。
Ryan Lopopolo:对。这基本就是我以前在平台团队里经常遇到的:大家心里会有一个“还能接受”的构建时长区间,等它一路涨到超标,再花两三周把它压回平均值下方。
但现在 token 实在太便宜了,而模型又可以疯狂并行,所以我们完全可以像修花园一样,持续不断地修剪这套系统,并维持这些核心指标。这样一来,代码和整个 SDLC 的离散程度就会低很多,我们反而能把很多东西做得更简单,也能在写软件时依赖更多稳定的不变量。
人成了瓶颈
Vibhu:你在文章里提到过一句特别扎眼的话:人变成了瓶颈。你们一开始只是三个人,结果做出了一个一百万行代码、上千个 PR 的系统。那这里面的思路到底是什么?你前面讲了很多关于“代码是可抛弃的”,但与此同时你们还是要做大量 review。文章里其实一直在反复强调,要把所有东西都重新表述成 prompting,也就是 agent 看不见的东西,基本就等于垃圾。那么从更高层面看,你们到底是怎么搭这套系统的?在人类已经成了 PR review 瓶颈的情况下,人类在其中到底还剩什么角色?
Ryan Lopopolo:说实话,我们现在已经走到一个阶段:连代码 review 这件事,都不再主要靠人了。现在大部分人工 review,其实都发生在代码合并之后。
swyx:等等,合并之后?那等于合并前根本不 review?只是为了让大家心理上舒服一点?
Ryan Lopopolo:你根本没有办法再沿用旧思路了。模型本质上是可以被极其容易地并行化的。只要我愿意多砸 GPU、多花 token,它就能在我的代码库上持续干活。真正稀缺的东西,反而变成了我团队里那种必须实时在线的“人类注意力”。
虽然说实话,机器在那儿跑起来以后,你很难不想继续去戳它、继续给它喂东西,但一天就那么多小时,我们还得吃午饭,我最好还是睡觉。所以你必须后退一步,用系统思维去看事情,不停问自己:agent 到底在哪里犯错?我自己的时间到底花在哪儿了?以后怎么才能不再花这部分时间?然后在这个基础上,一点点建立对自动化的信心,也就是:好,这一部分 SDLC 我已经真正自动化掉了。
而这通常意味着什么呢?最开始的时候,我们必须极其仔细地盯着代码看。因为 agent 当时还没有合适的 building blocks,做不出真正模块化、真正能被正确拆解的软件,也做不出可靠、可观测、还能不断长出前端界面的系统。
所以,为了不让我们自己整天只能盯着终端,我们首先做的就是把可观测性给到模型。这就是文章里那张图讲的东西。
swyx:对,我们来过一遍那张图吧。从 traces(追踪)开始讲。哪个是最先出现的?
Ryan Lopopolo:最开始我们只有 app,后面从 vector 一直到各种 logging、metrics、API 这些东西,基本上只花了我半个下午。我们是非常刻意地选择高层级、快开发的工具链。现在市面上这类东西已经很多了。我们用了 MISE 之类的工具,可以很轻松地把这些用 Go 写的 Victoria Stack 二进制拉到本地开发环境里,再写一点点 Python 胶水代码把它们全都拉起来,就能直接跑。
这里有个挺有意思的点:我们一直在尽量把整个流程“倒过来”。通常大家会先搭一个环境,再把 coding agent 丢进去,但我们不是。我们的入口就是 Codex。也就是说,先拉起 coding agent,然后再通过 skills 和 scripts 赋予它自行启动整套栈的能力(如果它认为自己需要这么做的话)。与此同时,我们会告诉它怎么设置环境变量,让 app 和本地开发环境都指向这套由它自己决定是否启动的栈。
我觉得,这就是推理模型和过去那些 4 系、4o 系模型最本质的差别之一。过去的模型不会思考,所以你只能把它们装进一个预定义状态迁移的“盒子”里。但现在不一样了,现在我们可以让模型和 harness 本身就变成那个“盒子”,然后只给它一堆可以选的路径,再给足够的上下文,让它自己做更聪明的判断。
Vibhu:这其实和脚手架关系很大。过去做 agent,很多时候都是先定义好一套脚手架,它就在里面运行、再试、失败了再来。但有了推理模型后,反而越来越不该给它太重的脚手架。
Ryan Lopopolo:对,就是这个方向。
重新发明了 skills ?
Vibhu:你们还会做很多非常细的东西,比如 Spec.md,还有一个很短的 agent.md。你甚至把整套结构都列得很清楚了。
相关截图,非完整版
Ryan Lopopolo:这种结构还有一个特别大的好处,它让你往仓库里加新内容的成本变得特别低,而且这些内容既能引导人类,也能引导 agent。
swyx:某种程度上,你们其实是重新发明了 skills ?
Ryan Lopopolo:是的。因为我们开始做这套东西的时候,skills 这个概念其实都还不存在。
Vibhu:你们有一个大概一百行左右的总目录,然后下面再拆成很多小的 skills ?比如 core beliefs.md、tech tracker。
Ryan Lopopolo:这里面,像 tech tracker 和 quality score 其实特别有意思。因为它们本质上就是一个很小的脚手架。
比如一张 Markdown 表格,它本身就是一个 hook,让 Codex 能 review 应用里定义的所有业务逻辑,再判断这些逻辑是否符合我们设定的 guardrails,最后再给自己列出一批后续改进建议。在我们还没有用 Linear 之类的系统之前,这些任务其实就直接记在 Markdown 里,然后我们再拉一个 agent,把这些任务一个个销项。
这里面有一个特别妙的地方:模型天生就“渴望文字”。所以我们做的很多事情,本质上都是在想办法把文字持续注入系统。
比如线上某个服务触发了报警,原因是漏写了 timeout。那我可以直接在 Slack 里 @Codex,说:我现在准备通过加 timeout 来修这个问题,你顺便更新下可靠性文档,把“所有网络调用都必须设置 timeout”写进去。
这样一来,我不只是打了个补丁,还把“什么是正确做法”这类过程知识,真正沉淀成了系统的一部分。接着,我们会把这些新规矩交给主 Agent(root agent)去执行。你甚至可以基于这些内容进一步蒸馏出测试用例,或者训练出一个 Code Review Agent,让它也盯着这套规范,从而收紧最终代码的可接受范围。
swyx:我对这类做法的一个担心是,你会以为自己做了一个很正确、可以长期保留的规则,但实际上你可能没考虑到各种例外情况,最后反而得把它撤回来。
Vibhu:但这里面有一部分其实也还是 skill 的特点,对吧?也就是说,它会自己判断什么时候要调用这些工具,而不是每次都机械执行。比如它会自己决定,要不要去看质量评分。
Ryan Lopopolo:对。而且我们在给 agent 的提示词里,也会明确允许它“反驳”。
比如我们刚开始把 code review agent 接进 PR 流程时,整个过程是这样的:本地的 Codex CLI 写出改动,推一个 PR 上去;然后在同步 PR 时,review agent 会自动触发,留下评论。我们会要求负责写代码的那个 Codex 至少要“确认并回应”这些反馈。
最开始的问题是,负责写代码的 Codex 太容易被 reviewer agent“欺负”了。结果就可能出现一种情况:两边都在说话,但根本收敛不了。
所以,后来我们不得不在两边的 prompt 里都加更多的可选空间。比如,我们会要求 reviewer agent 在判断时偏向“尽快合并”,不要提出高于 P2 的问题。虽然我们其实没有特别严格地定义 P2 到底是什么,但至少我们给了它一个大概的方向。
swyx:但你们其实是有定义 P2 的。
Ryan Lopopolo:我们给了它一个框架,让它能在这个框架里对自己的输出结果打分。
swyx:那也就是说,比分高于 P0 反而更糟,对吧?
Ryan Lopopolo:对。P2 就非常好了。P0 的意思是,如果你把这个东西合并进去,你就得把这块代码的报警直接给“静音”了。
swyx:就是你一旦把它合进去,系统立马就炸了。
Ryan Lopopolo:但在代码编写智能体(code authoring agent)这一侧,我们也给了它一种灵活性:它可以选择暂缓处理,也可以对评审反馈提出异议、往回顶一下。
这个场景其实特别常见。比如我碰巧注意到某个问题,就留了一条代码评审意见,可这条建议很可能会让任务量瞬间翻倍。其实我并不是想让它立刻当场解决。这更像是个 FYI(供参考),意思是:“我提个醒,你先把它放进待办列表,等下次专门的 Fix-it Week 再统一处理。”
如果不明确赋予 Agent 这种“拒绝”的权力,coding agents 就会陷入那种死脑筋的惯性:不管指令合不合理,只管一路埋头执行到底。
swyx:我还想确认几件事。你们那个代码评审智能体(coding review agent)是可以自主合并的。我觉得这件事很多人其实都不太能接受。你这里列了一长串智能体在做的事情:产品代码和测试、CI 配置和发布工具、内部 DevRel 工具、文档、评估、harness 评审、评论、管理仓库本身的脚本、生产仪表盘定义文件,几乎什么都做。
Ryan Lopopolo:对。
swyx:那它们就是同时一直跑?团队里有没有什么总控记录,或者说有没有哪种机制能让人把一切先按停?
Ryan Lopopolo:因为我们做的是原生应用,不是那种全自动的持续部署,所以在切发布分支的时候,还是得由人来盯着。我们要求在推向发布环节之前,必须先通过一轮由人工确认的冒烟测试。类似这种节点,还是有人在把关。
swyx:所以你们现在做的是 app,不是在做那种对可靠性要求非常高的基础设施吧?
Ryan Lopopolo:对,是这样。另外得补充一点:这一切都是在一个完全从零开始的新项目(Greenfield)里搞出来的。我并不想暗示这套脚本是什么“万能灵药”,能直接套用到所有场景里。
swyx:但这是生产环境里的东西,是你们真的要发给客户的?
Ryan Lopopolo:当然。这些都是真实的东西。
Vibhu:我比较好奇的是,到底人参与的环节还剩多少?也就是说,现在还有哪些瓶颈是你依然希望自动化掉的?另一部分问题是,你怎么看模型能力的演进轨迹,未来还能替掉哪些人参与的环节?我们现在刚有了 5.4,它真的非常强。
Ryan Lopopolo:顺便说一句,这模型太棒了。
Vibhu:对,这是第一个真正把顶级编码能力合进来的模型。也就是说,它同时具备 Codex 级别的编码能力和推理能力。通用推理和编码,第一次都在同一个模型里了。
Ryan Lopopolo:还有计算机使用(computer use)和视觉。现在有了 5.4,Codex 直接写了那篇博客文章。之前,我还得在 chat 和别的工具之间来回平衡。
swyx:天啊,那我可能要失业了。
Ryan Lopopolo:这其实就是“闭环”的一个典型例子。就像你刚才提到的仪表盘,我们让 Codex 去写 Grafana 仪表盘的 JSON 并直接发布,同时它还会对接告警系统。也就是说,当告警触发时,它已经完全掌握了上下文:目前定义了哪些仪表盘、有哪些监控项,甚至能精准定位到是代码库里的哪一行日志触发了这次警报。因为所有这些信息都被整合进了一个统一的上下文空间。
这还意味着,如果发生了一次“静默事故”(没触发警报),它手里依然有现成的指标和日志数据。它能自主诊断,到底是仪表盘漏掉了监控,还是底层的埋点指标有问题,然后顺手一次性修掉。这就像是一个全栈工程师,能一路从后端逻辑排查到前端展示,彻底把问题搞定。
软件也得写给模型看
Vibhu:所以听下来,你们很多工作的核心逻辑,其实是让整个团队彻底顺应模型,按照 AI 喜欢的方式去写软件。这意味着你们调低了对“传统人类可读性”的追求,转而换取更极致的代码逻辑清晰度和智能体可读性。你觉得这种转向会对更大范围的团队产生什么影响?
首先是在 OpenAI 内部,这会不会演变成一套关于“软件该怎么写”的新方法论?因为可以想象,如果你带着这种思维进入一个新团队,那将是一场剧变。从代码评审(CR)到代码组织架构,原本几乎所有东西都是为了适配人类的阅读习惯而设计的。
那么,我们是不是都该进行这种整体切换?这套范式会如何反馈给 OpenAI 甚至整个软件工程行业?这显然不是小修小补,而是底层逻辑的重构。对于那些想入场的团队来说,是不是唯一的出路就是直接 All-in?
Ryan Lopopolo:我的心态其实很明确,我已经从具体过程里抽离出来了。也就是说,我不可能对代码层面的细节一直保持特别深的意见。这就好像我是一个五百人组织的群组技术负责人。在这种角色里,我不适合陷在每一个 PR 的细节里。
所以我才会觉得“合并后代码评审”那个机制是个很好的类比。通过抽查具有代表性的代码样本,我能看清团队最终产出的成色,进而反推大家的卡点在哪、哪里需要支援、哪里已经在飞速狂奔。这样我就能把精力从细碎的执行中抽离出来,去关注更高维度的东西。所以我其实对“代码具体是怎么写出来的”没有太多意见。
但我确实有一个基于命令(command-based)的类,它可以把业务逻辑做成可重复的模块,而且天然自带追踪、指标和可观测性。真正该关注的,不是这段逻辑到底怎么组织,而是它有没有使用这个原语,因为我知道,只要用了它,系统就默认具备了杠杆效应。
Vibhu:你在博客里也写到了这部分内容,比如怎么通过设定边界来强制架构和技术品味,怎么规定哪些东西能用、哪些东西不能用,还有关于重新定义工程之类的内容。
Ryan Lopopolo:而且,随着模型越来越强,它们也越来越擅长主动提出这些抽象层,来给自己解堵。这样一来,我就能不断往更高层去看,站得更高、看得更远,去理解真正阻碍团队发版的东西到底是什么。
swyx:你刚才提到,它其实是一个一百万行代码的 Electron app。但它也管理自己的服务,所以它有点像 backend for frontend 那种结构。
Ryan Lopopolo:我们里面确实有后端,但它是托管在云上的。而这种结构,其实也体现在分开的主进程和渲染进程里。
swyx:就是在 Electron 里面?
Ryan Lopopolo:对,这本来就是 Electron 的工作方式。当然,所以我们也同样用很严格的方式去处理 MVC 风格的拆分(model view controller),这件事其实挺有意思的。
这里面有个很有意思的地方可以探索:Codex + harness,作为构建 AI 产品的一部分。现在大家的重心都在让模型越来越擅长编码。我们已经看到,模型哪怕只是小版本更新,它能处理的任务复杂度也会迎来巨大的跨越。
如果你能把产品逻辑或者想解决的用户旅程(user journey),转化压缩成“代码”这个形态,那很自然地,你就可以直接用 Codex Harness 来搞定。因为它已经把所有的底层链路都打通了,你只需要通过沟通和提示词,让模型自己去发挥就行。这件事真的特别有意思。
而且这里还有一种对工程师非常友好的增强能力的方式,你只需要把你本来就会给自己写的那些脚本,直接交给模型。
swyx:所以,Ryan 的意思其实就是:软件工程,或者说面向代码的工作流,会把知识工作里很多非编码的部分也吃掉。原本你会觉得,“哦,这一块得单独做个智能体”,但其实不是。你应该先从编码智能体开始,然后再从那里往外扩。OpenClaw 底层其实就是这种思路。
Ryan Lopopolo:对。
swyx:那我顺便问一句,可能这也是今天唯一一次提到它,你自己有在用 OpenClaw 吗?
Ryan Lopopolo:没有没有。我自己没在用,我家里又没有一堆闲着乱放的 Mac Mini。
swyx:你提到了 ticketing systems,也提到了 PR,这两样东西是不是都得消失,或者至少要被重造,才能适应这种编码方式?因为 Git 本身对多智能体其实非常不友好。
Ryan Lopopolo:对。我们非常重度地使用 worktree。
swyx:可即便如此,我刚发了一期和 Cursor 的播客,他们还在说想把 worktree 干掉,因为 merge conflict 还是太多了、太不直观。
Ryan Lopopolo:模型在解决合并冲突(merge conflicts)这件事上,其实非常擅长。
而且,当我已经不需要同步地待在终端里、亲自盯着整个环节的时候,几乎也就不太在乎 merge 冲突这件事了。
swyx:因为它是可抛弃的。
Ryan Lopopolo:对。我们会调用一个叫 dollar land 的 skill,它会引导 Codex 去这样做:先推一个 PR,等人类和智能体评审;等 CI 变绿;如果有不稳定测试,就把它修掉;接着跟上游分支合并;如果 PR 出现冲突,就继续处理;等一切都通过后,把它放进 merge queue;继续处理不稳定性,直到它真正进到 main;结束。
这才叫真正的完全委托。在一个很大的模型仓库里,对人类来说,把 PR 合进去可能是很重的负担,但智能体完全能做这件事。我现在根本不需要操心,只要把笔记本电脑开着,剩下的交给它就行。
swyx:对。我以前是那种特别强的控制狂,但现在我越来越觉得,只要给足上下文,它在这件事上真的能做得比我更好。
Ryan Lopopolo:对,没错。
工程经验,正在被写进skills、文档和测试里
swyx:关于 harness 本身,还有别的吗?
Ryan Lopopolo:我觉得有一件事,我可能在文章里没有讲得特别清楚。但我在 Twitter 上看到一个挺有意思的回应。
归根结底,我们写进文档、测试、评审 Agent 以及各种机制里的所有内容,本质上都是在做一件事:将“构建大规模、高质量、高可靠软件”所需的非功能性需求,通通编码进一个能被 Agent 感知的上下文空间里。我们要么把它写成文档,要么打通链路,让报错信息本身就能指引正确做法。
这整套系统的核心,其实就是把我团队里所有工程师脑子里那些隐性经验,比如“什么才叫好”“默认该怎么做”“新同事入职时老员工手把手教的那些诀窍”等,尽可能地从人脑里抽离出来,固化成系统的一部分。
这也就是为什么,我们会死盯着 Agent 犯下的每一个错误。因为每一次报错其实都在提醒:它写出的代码,与某个尚未被显性化的非功能性需求之间发生了错位。
还有一件很妙的事,我完全没想到,很多人直接把我那篇文章的链接扔给 o1 或者 Codex,然后跟它说:“把我的 repo 变成这样。”
Vibhu:你这等于搞出了一个完整递归。
Ryan Lopopolo:而且效果好得离谱。
模型处理复杂度最多是中等水平
swyx:我们之前请过 Brett Taylor 上节目,他现在是你们的董事长,这已经够离谱了。更离谱的是,他居然也在读你的文章,还真的参与讨论。他当时说,软件依赖会逐渐消失。基本上,以后它们都可以直接 vendored 进去。你怎么看?
Ryan Lopopolo:我 100% 同意。
swyx:但你现在还是会用 QR,你还是在给 Datadog 付钱,还是在给 Temporal 付钱。
Ryan Lopopolo:对。以模型现在的能力来看,我们能内部消化的依赖复杂度,大概还停留在低到中等这个区间。
swyx:你说的中等,到底算什么级别?
Ryan Lopopolo:一个只有几千行代码的依赖,其实完全可以自己内部消化掉,根本不是什么大问题,花一个下午基本就能搞定。很妙的是,这类代码里大部分内容你可能压根都不需要。你一旦内部实现、自己做抽象,就可以把里面那些通用但和你无关的部分全都剥掉,只保留你真正需要的那部分,专注于把具体问题解决掉。
这件事还有另一个很有意思的地方。比如我们把 Codex Security 部署到仓库里后,它能以一种摩擦极低的方式,对那些已经被内部化的依赖进行深度审查和修改。这个过程,比起你给上游开源项目提 PR、等他们发布新版本、再拉回本地、再确认和你仓库里所有传递依赖都兼容,成本低太多了。
所以,如果代码产出的成本几乎为“零”,或者说 Token 已经足够便宜,那么“依赖内部化”本身就会变成一件顺理成章、且门槛极低的事情。
swyx:对,我觉得我唯一反对这个方向的理由就是规模化测试,像 Linux、MySQL、Datadog、Temporal 这种更大规模的软件系统,问题还是不一样。再比如安全测试这块,我记不清是不是 Linus Torvalds 说的,大意就是:开源安全最好的消毒剂,就是把东西放在阳光下。
Ryan Lopopolo:很多双眼一起看。
swyx:对,很多双眼一起看。可一旦你把依赖直接内联进来、自己重写,你就得重新踩别人踩过的坑。
Ryan Lopopolo:对,没错。你一旦把这个依赖内部化,就相当于又回到零开始。你得重新把那些零碎的部分一点点拼起来,才能对现在这份代码建立起足够高的信心。
Vibhu:其实你一开始就提到了,几乎所有东西都是 Codex 写的,包括内部工具。所以内部工具这件事,某种程度上就像是你在可视化系统里正在发生的事情,而这些工具本身还是它写给自己用的。
Ryan Lopopolo:这里有个特别好笑的故事。
我们当时把应用部署给第一批的十几个内部用户时,遇到了一些性能问题。于是我们让他们导出一份 trace 给我们,拿到一个 tar 包之后交给值班工程师。
他和 Codex 配合得特别好,做出了一个非常漂亮的本地开发者关系工具,一个 Next.js 应用:你把 tar 包拖进去,它就能把整条追踪链路完整可视化出来。这工具做得非常棒,也只花了一个下午。但问题是,这一切其实根本没必要。因为你完全可以直接启动 Codex,把 tar 包丢给它,问它同样的问题,马上就能得到答案。
所以从某种意义上说,我们当时费尽心思去优化调试过程、非要让它对人类更可读,其实是错的。那相当于在不必要地把工程师硬拽在链路里。事实上,你完全可以放手让 Codex 自己去跑五分钟,两者得到的结果几乎没差。
swyx:这其实也验证了你的直觉,这只是我们过去会采用的解决方式,或者说,这是我过去用来解决问题的方法。
Ryan Lopopolo:对。就拿这个本地可观测性栈来说,当然你可以部署 Yeager 来可视化追踪,但我本来就不觉得自己应该去看这些追踪,因为反正我也不会亲手写代码来修它们。
swyx:所以本质上,你还是需要有这样一套“自有技术栈”,并且掌控整个闭环。我觉得这一点已经非常明确了。听起来你们之后可能也会分享更多这方面的东西?
Ryan Lopopolo:对,我觉得我们很期待继续讲这些。我们等会儿会讲到 Symphony,不过我们现在分发它的方式其实是“Spec(规格)分发”。我看到 Twitter 上已经有人把这种东西叫作 Ghost Libraries。
这名字真的太酷了。它的含义其实是:向全世界分享软件的成本将被极度压缩。你只需要定义一份 Spec,告诉别人该怎么去构建它,其中尽可能把一个 coding agent 在本地重新组装所需的内容说明清楚。
这个流程非常有意思。我们会把专有仓库里原本存在的所有脚手架抽离出来,单独起一个新仓库;然后让 Codex 参考我们的老库去草拟这份 Spec。
接着,我们让它启动一个 tmux 团队,拉起一个离线状态的 Codex 去根据 Spec 搞实现;等它做完,再启动另一组 Codex 和 tmux 团队,对照上游源码进行对标审查,不断修正 Spec,缩小它与上游的偏差。你就这样一轮又一轮地迭代,就像 Ralph 的那种风格,直到你磨出一份高保真 Spec,它能近乎完美地把整套系统复现出来。这整个过程真的太棒了。
Vibhu:而且你们基本上没有往里面加太多人类偏见,对吧?
Ryan Lopopolo:对,没错。
swyx:一个智能体能不能写出一份自己根本解不出来的 Spec?它是不是总只能想象自己做得到的事情?还是说,它也能想象那些实际上根本不可能完成的事?
Ryan Lopopolo:我觉得拿 Symphony 来说,这里面有一个坐标轴:有些事情是容易还是困难,有些事情是成熟还是全新。对我来说,那些既难又新的事情,模型还是离不开人。但坐标轴上其他那几个象限,我觉得大体上已经被解决得差不多了。只要你有合适的脚手架,有合适的驱动方式把智能体一路推到完成,它就能跑通。
但这也意味着,人类这种时间和注意力都有限的存在,终于可以把精力放到最难的事情上,比如面前是一整片空白、完全没有现成答案的问题;或者那些最深层次的重构问题,你根本不知道接口的正确形态应该是什么。
这才是我想花时间的地方,因为这样我才能为下一层级的规模化做好准备。
Symphony 起源
swyx:那我们来正式聊聊 Symphony 吧。其实前面已经时不时提到它了。你们居然选了 Elixir,这挺有意思的。
Ryan Lopopolo:对。还是那句话,Elixir 在这里的出现,本质上更像是一个衍生结果。这是模型选的。
它之所以选择 Elixir,是因为它的进程监督和 GenServer(通用服务器)机制,简直是为我们这种进程编排量身定制的。在这套架构下,你本质上是为每一个执行中的任务都开启了一个“小型守护进程”,并一路护送它直到任务完成。也正因如此,基于 Elixir 和 BEAM 虚拟机,模型几乎能白嫖到一大堆现成的能力。
swyx:Symphony 的起源是什么?你们拿它来做什么?它是怎么形成的?有没有哪些后来放弃掉的路线?
Ryan Lopopolo:到去年年底,我们每个工程师每天大概能产出 3.5 个 PR,那还是在 5.2 版本发布之前。等到年初 5.2 上线,大家休假回来,趁着仓库里还没有乱七八糟的任务打断,产出一下子猛增到人均每天 5 到 10 个 PR。
我不知道你们怎么看,但那种不停切换上下文的感觉真的很耗神。每天收工时,我整个人基本已经彻底被榨干了。再回到那个问题:人到底把时间花在哪儿了?其实全是耗在那些活跃的 tmux 窗格(Panes)之间来回切、不停地盯着 Agent 往前走。
所以我们又一次想,得做个东西把自己从这个环路里解放出来。这就是 Frontier 当时拼命冲刺做 Adapt 的原因:找到一种办法,不再需要人坐在终端前面盯着。
于是就有了很多关于 DevRel 盒子、自动拉起智能体之类的实验。那个终极状态其实非常诱人:我的生活像在海边度假一样,我一天只打开两次 Live,看着这些东西说一句 yes 或 no 就行。
而且,这种模式会彻底改变你的工作思维。我会变得对延迟极其敏感,但对代码具体怎么写的执念反而少了很多。说实话,我对“亲手写代码”这件事几乎已经没有投入感了。所以如果它写得太烂,我完全可以直接扔掉,一点也不会心疼。
在 Symphony 里有一个“返工(Rework)”状态:当 PR 被提交并升级到人工审核时,这种审核成本本就该非常低。行就合并,不行就打回。这个 Elixir 服务会直接清空整个工作树和 PR,然后推倒重来。
而这又给了我们一次反思的机会:为什么它刚才产出的是垃圾?智能体到底在哪儿搞错了?只要修正这个错误,就能再次把任务推回“进行中”状态。
swyx:那为什么这些东西还没进 Codex app?感觉你们已经走在 Codex app 前面了。
Ryan Lopopolo:对,我们团队的工作方式就是尽可能“AI 原教旨主义(AI-pilled)”,也就是尽可能地走在技术的最前沿。
我们做过的很多东西,后来其实都沉淀进了产品里。比如我们和 Codex 团队有很深的协作,推动 Codex app 这个产品真的落地;也推动了 skills 成为 Codex 可直接使用的能力,这样我们就不用自己再单独造一套;再比如把自动化放进产品里,这样我们那些自动重构智能体(automatic refactoring agents)就不用继续维持那些手搓的控制循环了。
某种程度上,这种和 Frontier、Codex 的正式产品开发节奏解绑的状态特别好,因为我们可以非常快地去试,看看什么真的有效,然后再找那个可以大规模部署的方案。
这种工作方式非常有意思。当然,也确实很混乱。我经常会彻底搞不清当前代码到底是什么状态,因为我根本没有参与其中。
有一阵子,我们甚至把 Playwright 直接接到了 Electron 应用上。至于 MCP、MCCP 这些,我其实挺不看好的,因为 harness 会强行把那些 Token 注入到上下文里,我对此几乎没有控制权。它们还会干扰自动压缩,智能体甚至可能忘了怎么用这个工具。
而实际上,在 Playwright 里,我真正会用的调用大概也就三种。为了少数几个调用,我却得为一大堆没必要的东西买单。后来有人 vibe 出了一个本地守护进程,启动 Playwright,再用一个极简的命令行工具来驱动。而这件事发生的时候,我完全不知道。因为在我看来,我只是运行 Codex,然后它突然就能用了,而且还更好用了。我对这背后发生了什么完全一无所知。
所以在人和人协作的空间里,我们花了很多时间做知识同步和共享。我们每天的站立会要开 45 分钟,因为不得不这样做,我们必须尽量把当前状态的理解同步扩散给所有人。
swyx:我刚才就想说,这套东西对“一个人 + 多智能体”当然很好,但一旦变成“多人 + 多智能体”,复杂度就爆炸了。
Ryan Lopopolo:对,这也是为什么我们的应用架构会这么死板,几乎像是给一万名工程师设计出来的。因为我们必须想办法把空间切开,不然大家一定会互相踩来踩去。
swyx:解那个“一万人级别”是什么意思?
Ryan Lopopolo:我们的仓库结构里大概有五百个 NPM 包。对于一个七人团队来说,这绝对算是架构过度了,远远超出一般人会觉得正常的范围。但如果每个人实际上都相当于带着 10 到 50 个智能体一起工作,那你就会理解为什么我们会这么深地做拆解、分片、以及严格的接口边界,一切都会变得合理很多。
Vibhu:你们现在选的是 Linear 作为问题跟踪器(issue tracker),对吧?
Ryan Lopopolo:对,我们其实也大量使用 Slack。我们会直接把 Codex 派出去做很多那种动作型、弹性修复之类的事情,也包括那些把知识同步进代码仓库的活儿。而且成本特别低,直接交给 Codex 做就行。
swyx:我最大的私心是,OpenAI 真的该自己做一个 Slack。你们得拥有 Slack,自己造一个,把这套东西直接变成 Slack。
Ryan Lopopolo:我确实看到相关消息了。
如果我们真的相信,这些智能体应该去做有经济价值的工作,而这本来就是我们的使命,我们希望 AI 被大规模部署,用来完成真正有经济价值的工作,那我们就必须找到一种方式,让它们能自然地和人协作。这也就意味着,协作工具会是一个很值得探索的方向。
Vibhu:现在 Codex 已经从 Codex Model,到 CLI,再到 App,App 也能让我并行地发出去多个 Codex。但到现在为止,Codex 还没有一个特别好的团队协作能力。如果有人也在做五倍、五十倍的扩展,他们到底应该做那种只适合自己团队工作流的高度垂直工具,还是应该做更通用、能让别人也用起来的东西?这里面会不会存在一个细分空间?
Ryan Lopopolo:我觉得这件事目前还不确定,我们也没有找到一个通用答案。
但我确实觉得,如果能让代码和流程尽可能保持一致,你会获得很大的杠杆。因为如果你相信“代码就是上下文”,“代码就是提示词”,那么从智能体行为的角度看,最理想的状态就是:它看到 X、Y、Z 目录下的一个包时,不需要为了理解它再深挖到别的目录里,因为它们拥有同样的结构、使用同样的语言、内部也遵循同样的模式。
同样的杠杆,也来自于对一套统一 skill 的对齐:你把每个工程师的偏好都往这一套 skill 里灌,让智能体真正变得有效。
比如在我们的代码库里,真正用到的 skill 可能也就六个左右。如果软件开发闭环里的某个环节没有被覆盖,我们的第一反应并不是再新造一个 skill,而是先想办法把这部分能力编码进现有那几套基础 skill 里。这样,调整智能体行为的成本,往往会比改“人类驾驶员”的行为更低。
不要把 agent 关进太小的盒子里
swyx:你们有没有试过让 agent 去修改它自己的行为?
Ryan Lopopolo:试过。我们确实做了一些和技能蒸馏(skill distillation)相关的东西。比如,Codex 有个挺妙的用法,你可以直接把它自己的会话日志丢给它,然后问它:你觉得我怎样才能把这个工具用得更好?或者你也可以直接让它去做一些事。
你完全可以把事情“交给 Codex”。我们内部甚至还拿这个做了一个很傻但很好笑的表情梗,就是“你直接 Codex 一下就好了”“你直接 prompt 一下就好了”。某种意义上,我们确实活在一个挺辉煌的未来里。
不过,一对一这么用只是最表层。更进一步的做法是,我们会把整个团队的这些日志全都放进 blob storage 里,然后每天跑 agent 分析:作为一个团队,我们到底还能在哪些地方做得更好?这些经验又该怎么重新写回代码仓库?这样,每个人都可以免费吃到其他人的经验红利。
PR 评论也是一样,它们本质上都是反馈。代码被评论,说明当前写出来的东西偏离了“好的标准”;构建失败也是某种信号,说明在某个时刻,agent 缺了上下文。我们要做的,就是想办法把这些东西都吸收进来,再塞回仓库里。
swyx:对,这件事我也确实在做。我以前用 Claude Code 做知识工作时,都会在最后让它告诉我:下次我可以怎样做得更好?这其实也是一种元编程式的反思。
所以我会觉得,在你们的 Symphony 体系里,那六层(产品负责人、策略、配置、协调、执行、集成、可观测性)外,我不知道是不是其实还存在一个“第零层”:我们现在的合作方式本身是不是高效?能不能进一步优化自己协作的方式?能不能不靠改什么 Markdown 文件,直接修改我自己的工作流?
Ryan Lopopolo:当然可以,这套东西甚至也能给自己创建 ticket,因为我们给了它完整权限。你甚至可以先让它去创建一个 ticket,内容就是“以后请继续帮我创建 ticket”,作为后续工作的一部分。
不要把 agent 关进一个太小的盒子里。你应该让 agent 对它所在的整个领域拥有足够完整的可访问性。
swyx:你刚才说“不要把 agent 关进盒子里”的时候,我脑子里的第一反应其实是:我觉得还是应该给它一个盒子。只是这个盒子里,你得把它需要的一切都给全。
Ryan Lopopolo:对,核心就是上下文和工具。
swyx:只是作为开发者,我们已经很习惯去调用各种外部系统了。而你这里的做法,是把像 Prometheus 这类开源工具都拉到本地来跑,这样整个闭环就能完整跑通,对吧?
Ryan Lopopolo:对。
Vibhu:你也会希望尽量减少对云端的依赖?
Ryan Lopopolo:对,越少越好。
Vibhu:还有一点也很关键,你得认真想清楚 agent 到底能接触到什么。它能看到什么?这些信息会不会重新回流进循环?最基本的就是:它至少应该能看到自己的调用、自己的 traces,这样它才能判断自己哪里做错了。
Ryan Lopopolo:因为归根到底,这一切都是文本。我的工作,本质上就是想办法把文本从一个 agent 引到另一个 agent 那里去。
swyx:这件事其实挺奇妙的。因为在这一波 AI 浪潮刚开始时,Andre 就说过一句特别有名的话:“英文会成为最热门的新编程语言。”现在看,这话真的在应验了。
Vibhu:还有一个变化也特别明显:以前很多软件、很多工具都有图形界面(GUI),它们本来就是为人设计的。现在我们正在看到另一种演化,几乎所有工具都开始长出命令行接口(CLI)。因为 agent 特别会用这类东西。只要再配上更好的视觉能力、更好的小沙箱,这就是当下一种非常高效的方式。
Ryan Lopopolo:是,基本就是这样。另外,我们还在做一件事:把一些原本不那么“文本化”的东西,也尽量转成这种形式,以此改善模型的行为。
比如我们希望 agent 能看懂 UI,但 agent 感知 UI 的方式和我们并不一样。它不会像我们一样“看到一个红框”,它更像是“看到一个红框按钮”这类概念,它是在 latent space 里理解这些东西的。
总之,如果我们真想让它更准确地理解页面布局,有时候更简单的办法反而是先把图像栅格化,再去调用 OCR,把结果喂给 agent。
而且这两种做法完全不冲突,你可以同时做。这样就能更细地控制模型到底是怎么理解、怎么感知自己正在操作的对象的。
swyx:很好。要不要再讲讲这里面另外几层?有没有哪几层你觉得特别值得展开的?
Ryan Lopopolo:我会说,这里面最难做对的,其实是协调层(coordination layer)。
这其实是在把 Spec 翻译成 Elixir 的过程中,模型自己走了一个“捷径”。它会想:我现在已经有很多现成的原语可以用,而且我所处的这个运行时本身就原生支持进程监管。所以,某种意义上,它是把规范“映射”成了更容易被实现的选择,也就是做出那些能自然贴合这个领域的问题分解。
这有点像什么呢?就像你如果要做全栈 Web 开发,你通常会更愿意用 TypeScript 来做整套仓库,因为前后端共享类型会显著降低复杂度。但这里没有人参与。也就是说,我个人会不会写 Elixir,已经不重要了。这件事根本不该影响我们是否使用“适合这份工作”的工具。这个变化真的很疯狂。
swyx:这样一套层级结构本身很有意思。你可以在这些层之间上下走,它成了一种描述整个系统的共同语言。
Ryan Lopopolo:我觉得 policy 那一层也特别有意思。因为你根本不需要再写一堆代码,去保证系统一定要等 CI 通过。你只需要把 GH CLI 给它,再加一段文本,告诉它“CI 必须通过”就够了。这样整个系统的维护会容易很多。
更适合 agent 的 CLI 输出
swyx:你觉得 CLI 的维护者,未来需要专门为 agent 做些什么吗?还是说现在这样其实已经够好?毕竟像 GitHub CLI 这类工具,当初做出来的时候肯定没想到今天会发生这种事。
Ryan Lopopolo:对,最初肯定没想到。但 GH CLI 已经非常棒了,真的很好用,也非常符合工程直觉。说实话,我现在和 GitHub Web UI 的唯一互动,基本就是运行 gh pr view --web 扫一眼。看完之后丢下一句“行,发吧”,差不多就结束了。
CLI 最大的好处在于特别省 token,而且还特别容易被进一步改造成更省 token 的形式。比如你去看 Buildkite 或 Jenkins,经常是一大篇构建日志直接“糊”在脸上。为了帮人类快速排障,开发效能团队通常会做一件事:把真正的异常从日志海洋里提取出来,置顶在页面最上面,方便你一眼看到。
CLI 其实也应该是同样的思路。比如,你应该给 prettier 加个 --silent,因为 agent 根本不关心每个文件是不是“已经格式化过了”,它只需要知道:格式化好了还是没好。这样它再决定要不要执行写入命令。
同样地,我们以前有一个基于 pnpm 的分布式脚本运行器,递归执行 --recursive 时会吐出一座“文字大山”。但这些输出里绝大部分都是无关紧要的成功记录,完全没必要全量读取。所以最后我们在外面又封装了一层脚本,只过滤出核心信息。
swyx:我以前在公司里也维护过 CLI,这个点真的是深深戳到我了。但你现在等于是把我工作也给“vibe”掉了。
Ryan Lopopolo:对,就是这个意思。
swyx:还有别的吗?这份 Spec 真的很长,我很欣赏,因为里面有很多非常明确的立场。除了这些之外,还有没有什么点是你特别想提醒大家的?
Ryan Lopopolo:归根结底,软件之所以更灵活,是因为它能适应自己最终部署进去的环境。也就是说,像 Linear、GitHub 这些工具,虽然都被写进了 Spec,但它们并不是不可替代的固定部件。你完全可以把它理解成一种更“柏拉图式”的理想形态,你也可以把它们换成 Jira、Bitbucket 之类的。
但与此同时,如果你能把 ID 格式、或者是单个 Agent 的 Loop 逻辑定义得非常严紧,那你就能极快地拉起一套“规格明确”的系统,并在其基础上持续迭代。
我们从来没打算把这份 Spec 做成那种死板、不可更改的文档。它更像是一张蓝图,核心目的是帮你尽快搭出一个足以起步的框架。至于后续怎么发展,你完全可以按自己喜欢的方式继续 “Vibe” 下去。
另外,你会发现这里面塞了很多代码和脚本,说白了其实就是:“我觉得这个 Prompt 效果很好,所以把它固化了下来。”只不过有时候,这类 Prompt 确实会写得非常长。本质上,agent 非常擅长遵循指令,所以你就该给它足够清晰、确定的指令,这样输出结果的可靠性才会大幅提升。
就像我们自己使用 Symphony 一样,我们并不希望开发者还得守在旁边,盯着 agent 一点点把这个系统“vibe”出来。我们希望它能自己做。所以,我们在“什么算成功”这件事上会非常强势、非常严格。因为只有这样,部署成功率才会上去。这样一来,我们自己也不用再为这套东西不断收 ticket。
代码是可抛弃的
Vibhu:这其实又回到了“代码是可抛弃的”那个点。我第一次强烈体会到这个,是 Deep Research 刚出来的时候。我拿一个关于 LLM 的问题去问它,它居然理解成了法律方向的问题,花了很久,最后给我吐回来一份完全跑偏的报告。当时我第一反应就是:好吧,我还是得盯着它一点。但真正的答案其实不是“盯着它”,而是应该把系统本身搭到让它更容易走对路。你不应该整天坐在旁边盯着你的 agents。
Ryan Lopopolo:对。就拿你那个 Deep Research 的例子来说,看完那个错误结果之后,你大概马上就知道下次 prompt 要怎么改,对吧?这其实就是你把一道 guardrail 重新喂回了代码库、喂回这个任务里,让 agent 的执行方式和你的目标更对齐。这里逻辑是完全一样的。
swyx:说到 Symphony,现在外部用户那边是什么感受?
Ryan Lopopolo:其实没有外部客户。它本来就是我们放到内部里的一个东西。
swyx:那如果从外部视角来看,这件事意味着什么?
Ryan Lopopolo:我会说,大家其实对这种“更便宜地分发软件和想法”的方式非常兴奋。拿我们自己来说,它已经把生产力又往上推了好几倍。所以我觉得,这里面存在一种很可能长期成立的模式:关键不只是把人从流程里移除,而是要找到一套真正能让人信任结果的方法。
我们发的那个视频,其实就是我们希望 coding agent 自动附在 PR 里的那类视频。
而我觉得,这也是整件事里最酷的地方:它真的在把“agent 和你一起工作”这件事,往“像一个真正队友”那边推进。
就像我不会整天站在你旁边,盯着你一周里做的那些 ticket 一样,我根本不想这么做。我也不会想看你在 Cursor 或 Claude Code 里整段会话的屏幕录制。我更期待的是,你按你认为合适的方式把该做的都做了,然后用一种让我能看懂的方式,告诉我这段代码为什么是好的、为什么可以 merge。
也就是说,你需要把一整条复杂的执行轨迹,压缩成一种对 Reviewer 友好的、可读的形式。而这一点真的特别有意思:即便 Codex 在过程中搞得到处是乱七八糟的东西,但最后它总能交付给你一个清晰、可理解的结果。这点太棒了。
模型的边界
Vibhu:现在很多东西都变得可抛弃了,你可以直接放出去一批有预算限制的智能体跑。那其中一个问题就是:你是不是永远都是那种“超高思考强度”的人?然后你怎么看 Spark?
Ryan Lopopolo:Spark 和这些模型真的非常不一样。跟 5.0 这类模型里那种超高层级的推理能力相比,它完全是另一种东西。它就是一个特别快、更小的模型。
说实话,我还没有完全想明白该怎么用它。我之前会下意识地把它拿去做那些我原本会交给超高推理模型去做的任务。然后结果就是,它在真正写出一行代码之前,已经先跑完三轮压缩了。
Vibhu:这对工程师来说其实特别关键。你可以在不得不压缩之前,让它持续运行更久。一个任务在压缩之前,消耗的 token 越多,效果通常就越好。
Ryan Lopopolo:对,没错。至于 Spark 怎么部署,我现在还不太确定。我觉得你的直觉是对的,它特别适合快速试做原型、快速探索想法、处理那些文档更新之类的事情。
对我们来说,它在拿反馈然后把这些反馈转成 lint 规则这件事上特别强。因为我们在代码库里已经有很好的 ESLint 基础设施了,这类事它做起来特别顺手。它能让我们很快解堵,去做那种让代码库更抗脆弱的自我修复类任务。
swyx:你们现在是真的把模型逼到极限了。那你觉得,当前的模型还有哪些事情做得不够好?
Ryan Lopopolo:它们显然还没到那一步:能从一个全新的产品想法出发,直接一枪到底,一次性跑通原型。
我现在花很多精力“把控方向盘”的地方,就在这里:把一个全新事物的 mock 最终态,翻译成一个真的能玩的产品。这里说的是那种全新的东西,没有任何现成页面可以参考。
类似地,虽然模型每次更新都在进化,但那些最棘手、乱糟糟的重构依然是我耗时最多的地方,也就是那些我会最频繁打断它、最频繁介入的地方。
随后我会进一步深挖,开始为它搭建工具,辅助它去完成诸如“拆分单体架构”之类的事情。但我觉得,这件事肯定会变得越来越好。仅仅一个月时间,我们已经从处理低复杂度任务,跨越到了“低复杂度”与“大任务”并行的阶段。
这就是所谓的“永远不要和模型对赌”。你应该预期,它会不断把自己推进到越来越高复杂度的空间里。所以我们做的这些事情必须能兼容这种进化。而这最终意味着,我可以把自己的时间从琐事中抽离出来,去突破下一个瓶颈。
Vibhu:我也觉得这其实是另一类任务。Codex 特别擅长理解代码库、在代码库里工作。但像 Lovable、Bolt、Replit 这些公司,它们解决的是一个很不一样的问题。它们在做的是从零到一的脚手架,是产品想法层面的事情。那块也有很多人在做,而且模型在那里也在发生阶跃式的变化。只是它和今天的软件工程智能体不是一回事。
Ryan Lopopolo:就像我说的,这个模型和我是“同构”的。唯一不同的地方在于,怎么把我脑子里的东西塞进模型的上下文里。
而对于这些“白纸区域”项目,说实话,我自己就不擅长。所以在智能体执行轨迹里,我经常是走着走着,才意识到我们到底缺了哪些信息。这也就是为什么我始终觉得,现阶段离不开“同步交互”。
但我预期,只要有合适的 harness、合适的脚手架,能把这些东西从我脑子里勾出来,或者把可能空间收束起来,比如,对使用什么框架特别有主见,或者直接先放一个模板进去,这些都是在给模型补齐那些非功能性需求,给它额外上下文,让它有一个能锚定的点,避免结果发散得太厉害。
做 agent 的部署底座
swyx:我还想聊聊 Frontier。你们大概一个月前发布了它。按我的理解,这本质上是你们的企业级产品。那它到底是一个产品,还是很多个产品?
Ryan Lopopolo:我不能在这里讲完整的产品路线图,但我能说的是,Frontier 是我们希望拿来推动“每一家企业 AI 转型”的平台,而且不管企业规模大小。
我们想做这件事的方式,是让企业能很容易地把那些高可观测、安全、可控、可识别的智能体部署到工作场所里。我们希望它能和你们公司原生的 IAM 栈协同工作,希望它能接入你们已有的安全工具,也希望它能接入你们正在使用的工作空间工具。
swyx:你们其实就是在把各种 Specs 抽出来,对吧?
Ryan Lopopolo:我预计这里面会有一些 harness 相关的东西。Agents SDK 会是其中的核心部分,它能让创业公司开发者和企业开发者都拥有一套“默认就能工作”的 harness。这套 harness 要能用上我们模型最好的那些能力,从 Shell tool,到带文件附件和容器的 Codex Harness,再到其他所有我们已经知道、构建高可靠复杂智能体所需要的东西。
我们想把这件事做好,也想让这些东西能很容易地安全组合起来。比如说,GPT-OSS safeguard model。它最酷的一点在于天生具备与安全规范深度交互的能力。而安全规范,对企业来说,本来就是高度定制的。我们有责任去帮这些企业找到方法,让他们能在自己的企业环境里给智能体“加装仪表”,避免他们特别在意的数据外流,比如让模型知道公司内部的代号之类的。
所以,我们现在在探索的空间就是:既要提供正确且丰富的 hooks,让这个平台足够可定制;又要尽可能让它对大多数人来说,不需复杂配置默认就已经能跑起来。
swyx:这个产品到底是给谁用的?是 CEO?CTO?还是 CISO 这类人?
Ryan Lopopolo:至少按我个人的看法,我们在这里要服务的“买方”,一类是那些正在高效使用这些智能体的员工。对他们来说,重点是这些智能体出现在哪些界面里、能访问哪些连接器之类的事情。
而像这种仪表盘,更像是给 IT、GRC 和治理团队、AI 创新办公室、安全团队这些人准备的。也就是公司里那些要对“成功把智能体部署进员工真正工作场景里”负责的人,以及要确保整个过程安全、符合法规要求、客户证明等要求的人。所以,真正终端体验下面,其实是一整座冰山。
swyx:你每往 UI 里下一层,某种程度上就是在沿着智能体的抽象层往下走,对吧?
Ryan Lopopolo:对。能一路下钻到单个智能体轨迹这个层级,会特别强大。这不只是从安全视角上强大。对于那些要对“skills 开发”负责的人来说,也一样很重要。
还有一件有意思的事,我们之前也发博客写过我们做了一个内部数据智能体(data agent)。它用了很多 Frontier 的技术,让我们的数据本体对智能体是可访问的,让它能理解数据仓库里到底有什么。
swyx:那什么叫 active user 呢?
Ryan Lopopolo:公司里可能就那么五个数据科学家,定义出了这个黄金标准。
swyx:对,而且这里面还有内部政治。比如贡献到底怎么算,市场部会说“这部分是我的功劳”,销售会说“这部分是我的功劳”,最后加起来超过百分之百。我就会想,你们这帮人根本是定义不一样。
Vibhu:如果你是创业公司,那一切都是 ARR。
swyx:数据作为反馈层,是你必须先解决的东西。只有先把这个问题解掉,产品的反馈闭环才能真正闭上。
Ryan Lopopolo:对,而这正是你构建那种“不只会写代码”的智能体的方法。如果它真的要理解你的业务是怎么运转的,那它就必须理解什么叫 revenue、你的客户分层是什么、你的产品线是什么。
公司上下文和梗图文化
Ryan Lopopolo:再回到我们前面讲的 harness 代码库。我们有一个 core beliefs.md 文件,里面写着团队里有哪些人、我们在做什么产品、我们的终端客户是谁、我们的试点客户是谁、接下来十二个月我们想实现的完整愿景是什么。这些全部都是上下文,它们会直接影响我们会怎么去构建软件,所以这些也得一起给智能体。
Vibhu:我猜你这些东西应该是高度动态的,会不断变化吧?也就是说,它不只是一个大规格说明(Spec),而是一个会不断迭代的东西。
Ryan Lopopolo:有一件事我觉得会更让你脑子炸掉:我们甚至还有一些 skill,是教它怎么正确生成那种高糊表情包、怎么融入 Slack 里的公司文化。现在你已经可以在 Codex 里用 Slack ChatGPT app 了,所以我甚至可以让智能体替我去整活儿。这其实也是幽默感的一部分。
swyx:可以啊。我一直觉得幽默本身就是一个特别难的智能测试,因为你得把大量上下文压进非常少的几个词里,“会不会接梗”很重要。
Ryan Lopopolo:这也是为什么 5.4 对我们来说提升这么大。它更接近“我自己”的感觉。
所有公司都该学的模式
swyx:我觉得这里面其实还有一个更大的结论:不只是你们在做这件事,而是外面每一家公司都应该采用这种模式,不管他们最后是不是和你们合作。这是一个好几百亿美元的机会。
Ryan Lopopolo:这就是让人们真正得到收益、真正把它铺开所需要的东西。
swyx:当然会有很多定制化需求。但我觉得,光是把这件事做成服务,就足够诞生好几家独角兽了。真正让我一下子想通的,是这些东西是一个个放出来的:先是这个,再是 Harness engineering,再是 Symphony。然后我突然意识到,原来这才是你们真正交付出去、用来完成那整套事情的东西。
Ryan Lopopolo:对,这里其实有一组 building blocks,我们先把它们组装成这些智能体,而这些基础构件本身,也就是产品的一部分。比如,能够给模型“指方向”、在模型开始失准时撤销授权,这些东西全都可以通过 Frontier 来访问。
而且公司里会有很多不同的利益相关方,他们各自都需要在这个平台里看到自己该看到的东西。所以我们会把这些东西都建进 Frontier 里,这样才能真正做到广泛铺开到整个世界。这才是好玩的部分。
swyx:这也让我想起以前那个“EGI 分级(levels of EGI)”的说法。我不知道 OpenAI 现在还讲不讲这个。
Ryan Lopopolo:你知道我前面提到过,我们团队现在正玩得很开心,一路往前猛冲。我们还在做一件事,就是把 Codex 的所有智能体轨迹都收集起来,统一吞进去,再做蒸馏。
这件事的意义,其实就是在为团队搭建我们自己的团队级知识库,再把这些东西反过来映射回代码库里。但它其实不一定非得这么做,也不一定只能绑定在 Codex 上。我也希望 ChatGPT 能学会我们的含义文化、学会我们正在做的产品、学会我们的工作方式。这样一来,当我去问它问题时,它也能拥有我工作方式的完整上下文。所以我对 Frontier 能把这件事做出来,真的非常兴奋。
swyx:模型团队的人看到你们这么做时,会怎么说?你们显然有大量反馈,也有大量使用量,还有大量轨迹。我不觉得这些东西对他们来说大部分都有用,但其中总有一些是有价值的吧。
Ryan Lopopolo:对,这里面有一个根本性的张力,就是:我们到底应该继续把投入加在 harness 上,还是应该更深入地投入训练流程,让模型默认就能做更多这类事情?
我觉得,按照我们现在这种工作方式来看,真正的成功意味着模型本身的“品味”会变得更好,因为我们可以给它指出方向。而且我们做出来的这些东西,没有任何一样是在主动削弱智能体表现的。因为说到底,它们真正做的无非就是跑测试,而“跑测试”本来就是写可靠软件非常重要的一部分。
如果我们是在 Codex 外面,又额外包了一整套 Rust 脚手架,专门拿来限制它的输出,那我会觉得这更像是一种额外的 harness,而且很容易将来就被废弃掉。
但如果反过来,我们能把所有护栏都做成一种原生于 Codex 已经在输出的东西,也就是代码,那我觉得这既不会给模型继续进化带来摩擦,同时也符合好的工程实践,而这本来就是重点所在。
swyx:我之前也和一些研究科学家聊过类似的问题。在强化学习(RL)里,对应的概念就是 on-policy 和 off-policy。所以你其实是在说,应该去构建一个 on-policy 的 harness,也就是它本身就处在分布之内,你是在这个基础上继续调整。如果你做的是 off-policy 的东西,那它就没那么有用了。
Ryan Lopopolo:对,就是这个意思。
swyx:还有没有什么我们还没聊到、但你觉得应该讲出来的?
Ryan Lopopolo:我只是想说,我真的特别享受 Codex 团队这段时间疯狂“开火”带来的红利。他们的交付速度真的非常狠,“持续、猛烈地交付”本来也是我们的核心工程价值观之一,而他们那个团队真的把这一点体现到了极致。
像 5.3、Spark、再到 5.4,感觉几乎就是在一个月内接连出来,这个速度快得惊人。
swyx:确实,刚好一个月前还是 5.3,昨天就已经是 5.4 了。照这个节奏下去,是不是下个月就该 5.5 了?
Ryan Lopopolo:这个我可不能说,不然预测市场的人要不高兴了。
swyx:我觉得很有意思的一点是,这个节奏显然也和增长挂钩。他们公布说现在已经有两百万用户了,但感觉大家几乎都不再把 Codex 当成重点来讨论了。现在真正的核心,是那个“最终形态”。写代码当然很酷,但更大的其实是知识工作本身。
Ryan Lopopolo:就是这样。这才是真正值得追的方向。我们团队现在也非常兴奋能去支持这件事。
swyx:我还有一个挺有意思的观察。OpenAI 以前本质上是一家非常以 San Francisco 为中心的公司。我认识一些人,他们当初要么拒了工作,要么没拿到 offer,就是因为他们不想搬去旧金山。现在这条路显然已经行不通了。你们得开 London,也得开 Seattle。我也很好奇,这会不会带来一种文化上的变化。当然,这种事你未必方便讲。
Ryan Lopopolo:我算是 Seattle 办公室最早的一批工程招聘之一。它现在能发展成这样,本来也是我一直努力想推动的方向之一,而且它确实发展得很好。我们在那边已经做出了非常扎实、可持续的产品线,同时也有大量从零到一的工作在进行。
而这恰恰就是我们在公司里做应用型 AI 工作的核心方式:快速往前冲,追着新东西跑,去找出模型到底能在哪些场景里真正成功落地。
对,完全是这样。我们在 New York 也有办公室,而且那边也有非常强的工程团队。New York 办公室,和 Seattle 的办公室相比,前者更有一种《Mad Men》那种办公室氛围,很漂亮。Bellevue 这个则是绿植很多、金色装饰件很多,很有太平洋西北的感觉,整个 vibe 也特别酷,很有本地气质。
原文链接: https://www.youtube.com/watch?v=CeOXx-XTYek
本文来自微信公众号 “InfoQ”(ID:infoqchina),作者:褚杏娟,36氪经授权发布。