作者:Factory|原文发布于 2026 年 8 月 27 日
当 Agent 必须遵守一套由它们自己写下的“完成标准”时,它们把复杂程序重建到了接近完整行为一致的程度。
模型已经非常擅长处理成功标准紧凑而稳定的问题。过去一年里,数学和约束优化方面的许多进展都属于这一类:对长期未解 Erdős 问题进行机器检验的证明、在国际数学奥林匹克竞赛中达到金牌水平,以及为数十年前的组合数学问题找到新的界限。搜索空间可以非常巨大,但最终结果仍然能够作为一个整体被判断。
大型软件任务则不同。一份软件规格可以在语义上完整描述想要的结果,却未必说明在宣布完成之前,究竟必须运行什么、检查什么、比较什么。需求描述的是“什么必须成立”,但需求本身并不测量实际成果是否真的满足它。
缺少这种测量时,Agent 只能一边工作,一边零散地构造自己的判断标准。它把任务拆开,在产生每个局部结果的上下文中验证它,最后自行决定已经完成。每一个局部判断都可能很合理,但整体仍有许多部分从未被测量。
目前通常由人来补上这个闭环:监督 Agent,始终记住完整目标,并在它偏离时把它引回去。
Factory 想知道的是:模型能否自己闭合这个循环?
从零重建 gdal
为了测试这一点,Factory 在 24 个经过筛选的 ProgramBench 任务和三个模型上,对比了单 Agent 与多角色系统两种运行方式。以 gdal 为例,他们要求 Droid 用两种方式从头重建它。两次实验中,Droid 都可以无限次执行参考程序,但不能访问其源码、测试或互联网。
gdal — C/C++ · 上游约 200 万行代码 · 约 60 万行能力可通过 CLI 触达
gdal 是 GDAL 项目的命令行工具,也是地理空间数据处理领域的基础设施。它把数十年积累的功能放在几十个子命令后面。GDAL 自 1998 年起持续开发,位于全球大量地图软件的底层——包括 QGIS、ArcGIS 和 PostGIS——并能读取两百多种栅格与矢量格式,从卫星影像到航海图。
在单 Agent 条件下,Droid 自己实现、检查工作,并自行决定何时结束。它写了 17,000 行 C++,复现了程序 36% 的行为。代码质量不错,常见路径也能正常工作,但程序的大部分能力仍然缺失。它不是耗尽了时间或预算;它之所以停下,是因为按照自己的判断,任务已经完成。
随后,Factory 把 Droid 组织成由不同角色组成的系统。在任何实现开始之前,其中一个角色先建立一套可执行的完成标准——明确这项重实现必须做到什么,以及需要什么证据才能证明做到——之后所有实现都必须接受这套标准的检验。这个版本最终增长到 115,000 行代码,行为一致度达到 90%。
这次系统运行产出的是一个独立程序:无论结构还是规模,它都不像原始 GDAL。它只使用了 GDAL 一小部分的代码量,并以自己的方式组织。
这并不是一个偶然案例。在 24 个任务中,同一套系统把 7-Zip 重实现的行为一致度从 54% 提升到 95%,把 DuckDB 从 34% 提升到 80%。还有多个重实现项目达到了 90% 的高位。
图中每一行代表一个任务。圆环是单 Agent 前沿:综合公开排行榜中的所有结果和 Factory 自己的单 Agent 实验,该任务上任何单 Agent 达到过的最好成绩。24 个圆环都使用虚线,是因为 Factory 的单 Agent 在这 24 个任务上全部占据前沿。实心点是系统前沿,颜色表示保持该成绩的模型,旁边的数字表示闭合循环带来的增益。
底层模型没有变化。但当模型必须对自己制定的完成标准负责时,它复现出了远多于单 Agent 条件的程序行为。
为什么同一个 Agent 会过早停止
Coding Agent 通常会随着实现过程自行验证工作:实现一个部分,编写或运行几项检查,查看输出,再决定是否继续。对于小型改动,这种方法很好用,因为任务、实现和证据都能放进同一个视野。
大型任务必须拆成多个功能、子系统和连续的工作轮次。Agent 每处理一个部分,也同时决定什么证据才算有效,以及现有证据是否已经足够。这些检查会继承产生它们的局部工作范围:它们可以证明 Agent 想到并决定构建的所有东西,却会排除那些 Agent 从未表示出来的功能、交互或约束。
因此,Agent 可以持续取得局部正确的进展,最后却在整体成果仍缺少大量内容时停下。问题不一定是它没有能力实现剩余部分,而是它从未建立一份完整清单,说明还有什么尚未完成。
在开始工作之前定义验证
要确认完整结果,仅有需求列表并不够。系统还需要一份待确认事项的清单、验证每一部分的具体程序,以及这些程序在即将交付的制品上确实通过的最新证据。
这套标准应该在实现把任务收窄成各个工作项之前,就从需求和相关事实来源中推导出来。它不必永远固定不变。随着系统学习,可以添加、替换或细化检查。但完成标准不能悄悄收缩成“当前已经构建出来的东西”。
为什么人类很少这样做
把需求与证据分开并不是新概念。安全关键型项目使用需求可追溯性,以及独立验证与确认;标准组织发布可供多个实现共同使用的一致性测试套件;产品团队也会编写验收测试。
真正少见的是,为每一个项目推导并维护一套全面标准。一致性测试套件可以把成本分摊到许多实现上,而产品团队每做一个应用、一次重写或一场迁移,都要重新承担这项成本。因此,大部分团队会采用增量验证,并依赖代码审查、产品反馈和参与者的连续经验来维持对整体的把握。
Agent 改变了这笔账的两边。它们生成工作的速度快于人类检查的速度,使非正式监督成为瓶颈。但同样的生产能力也可以用到完成标准本身:盘点完整结果、构建检查,并在制品变化时反复运行这些检查。
ProgramBench 代表了一个要求很高的极限场景:参考程序虽然可以运行,但模型必须同时发现它的行为空间,以及测量这些行为的方法。
ProgramBench
ProgramBench 是一个洁净室软件工程基准。每个任务都提供参考程序、固定数据和部分文档。参考程序是一个黑盒 Oracle:允许运行,但不允许阅读、反编译或跟踪。
目标是在完全从零开始的情况下,复现参考程序可被观察到的行为。每个任务最终都会由一套隐藏的行为检查进行评分。
衡量黑盒实现是否完整非常困难。任何单独行为都很容易验证——只需让参考程序和候选程序执行同样的输入——但整体并非如此。随程序提供的文档只覆盖接口的一部分,剩余行为都必须由系统自行发现。
于是问题变成三个:
- 前沿模型能否为一个庞大、未知的程序构造自己的完整度度量?
- 这套度量能否在漫长实现过程中持续有效?
- 对这套标准负责,能否真正产出更好的制品?
任务选择
Factory 根据当时排行榜上的最高分,从基准中选择了 24 个最困难的任务。
图中的每一个点都是 ProgramBench 的 200 个任务之一,位置表示任何公开排行榜结果在该任务上取得的最好成绩。深色点是被选中的 24 个任务;在原始交互图中,将鼠标悬停在点上可以看到名称。
这个集合由人工挑选,重点偏向公开最高分较低的任务。一些同样位于困难端的候选项——php-src、pueue、ditaa、quickjs、chroma、miller——在筛选阶段被移除,原因包括持续触发安全阻断、单 Agent 已经接近饱和,或者分数被某个未写入文档的环境变量所限制。
实验设计
对于每一个选定任务和模型面板,Factory 都分别运行一次单 Agent 条件和系统条件。系统条件增加了一套独立的完成度测量,但不会替代实现者原本的开发循环。
两种条件都从同样的任务脚手架和固定数据开始。在没有替换模型的面板中,单 Agent 和系统里的三个角色使用同一个模型、同一个推理等级。两种条件都能无限次运行参考程序,但都不能阅读、反编译或跟踪它,不能检查基准测试,也不能访问互联网。Fable 因安全机制被阻断后,有六个明确披露的实验单元改用了 Opus。
一旦启动,每场实验都不再有人类干预。两种条件没有做算力配平;每一场都会继续运行,直到单 Agent 或系统 Orchestrator 自己决定交付。
每个实验单元只代表一次运行,不是多次实验的平均值。实验结束后,最终候选程序只使用官方 pb-1.2.0 指标评分一次。
系统如何闭合循环
测量仪器(Instrument)
完整的行为一致度无法被直接测量。程序可能接受事实上无限多的输入、标志、文件格式、组合方式和错误条件。任何可实践的验证策略都必须对这个空间进行采样。
在 Factory 的系统中,这个样本被称为“测量仪器”。实现开始之前,Validator 会调查参考程序,绘制其行为分布的位置。然后,它建立一组带权重的测试案例,以及判断候选程序输出所需的比较规则。Factory 只对仪器提出大致轮廓;仪器内部的一切——哪些行为重要、如何加权、什么算作证据——都由 Validator 决定。
下面是 Validator 为 gdal 构建的仪器中的两个案例:
每个案例描述调用方式,评分策略则说明如何判断结果:
Validator 编写了数百个这样的案例,全部案例中只允许了两项放宽:调试跟踪中的堆地址会被遮盖,文件头中的日期可以忽略。两项都记录了证据,证明参考程序在这些位置无法生成稳定字节。
外层循环
系统由三个角色组成:Orchestrator、Implementer 和 Validator。Orchestrator 同时把工作委派给构建候选程序的 Implementer,以及使用仪器测量候选程序的 Validator。
Validator 先构建测量仪器。实现开始后,循环如下:
- Orchestrator 选择接下来应该测量什么;
- Validator 测试当前候选程序,并解释失败结果;
- Orchestrator 判断哪些发现真实有效,以及接下来应该开展什么工作;
- Implementer 独立调查参考程序,并推进候选程序。
当仪器不再能从连续版本中发现有意义的差异时,Orchestrator 可以要求 Validator 扩展薄弱区域,或者开始针对参考程序做定向差分测试。
Implementer 和 Validator 使用同一个模型与同一个推理等级,并且都能够访问参考程序,所以把仪器保留在测量侧不会损失信息,只会切断一条捷径。候选程序和归纳后的发现可以穿过边界,但仪器本身不能。评分只会在循环外进行一次,也是文章所有分数的来源。
隔离墙(The wall)
在 ProgramBench 中,完成标准还需要一层额外边界,因为仪器里的案例只是更大行为空间中的一组样本。
这道边界在两个方向上都成立。Validator 可以随着对参考程序的了解增加而扩展仪器,但不能为了迁就候选程序已有的内容而削弱或修改它。Implementer 既不编写仪器,也不运行仪器,更看不到其中的案例和原始输出:一旦稀疏样本对实现者可见,它就会变成优化目标;通过它只能证明这些案例本身,而无法证明这些案例原本代表的行为空间。
Validator 会用仪器测试当前候选程序,再按根本原因对失败进行分组。Orchestrator 审查这些发现,剔除噪声或无效测量,并把剩余问题转化为“缺少哪些功能、子系统或行为”层面的指令。Implementer 接收指令,独立调查参考程序,再自行决定如何修改候选程序。
下面是 gdal 实验中的一段指令:
这段指令告诉 Implementer 候选程序哪里薄弱,却不会泄露具体样本。
实验结果
Factory 使用三个前沿模型运行了实验:Fable 5、Kimi K3 和 GPT 5.6 Sol。
这里的每个分数都来自基准的隐藏测试套件——也就是所有角色都从未见过的同一行为空间中的独立样本。系统从自建仪器中得到的提升,成功迁移到了这套独立度量上。
每个面板代表一个模型,在同样的 24 个任务上分别运行两次:左侧是单 Agent,右侧是完整系统。每条线代表一个任务,位置是隐藏测试套件给出的官方分数。分数下降的线使用虚线。少数实验单元没有分数,因为某个测试在评估时挂起,评分未能完成;它们被放在面板底部。左侧的轨道按照任务难度——即每个任务的公开最高分——过滤,使用同样的 0–100 标尺。
系统运行的时间更长、成本也更高。以 gdal 为例,系统消耗的 credits 是单 Agent 的 14 倍,实际运行时间是 13 倍。但真正区分两种条件的不是预算。每一次单 Agent 实验结束,都是因为 Agent 自己决定结束。对于一个不打算继续消耗计算资源的 Agent,增加算力并没有帮助。Factory 改变的是它对“是否完成”的判断,更多计算投入只是这项判断带来的结果。
每一个任务、每一个模型、每一份记录——144 个实验单元的分数、花费、时间线和制品,都可以在完整文章的交互式页面中查看:探索全部实验。
方法说明
- 推理等级。 Fable 使用 xhigh,Kimi 使用 high,Sol 使用 max;单 Agent 与系统内三个角色统一使用相同等级。
- 每个实验单元只运行一次。 所有数字都来自单次运行,没有通过重复实验计算平均值,因此没有方差估计,也不应把结果解读为均值。
- 开篇案例。 开篇提到的 gdal、7-Zip 和 DuckDB 数字均来自 Fable 5 实验。
- 规模。 GDAL 上游大约有 200 万行 C/C++;移除打包的第三方库后约为 190 万行。按任务配置,可通过 gdal CLI 触达的部分——11 个驱动,不含 GEOS——约为 60 万行。重实现使用 115,000 行代码,匹配了这一范围内 90% 的被测行为。
- Opus 替代。 Fable 面板中有六个实验单元使用 Opus 替代被安全机制阻断的 Fable 运行,可能发生在单 Agent 或系统一侧:bedtools2、gromacs、pandoc、samtools、sox 和 tree-sitter。
- 覆盖情况。 144 个实验单元中已有 141 个完成评分。其余三个系统运行——Sol 上的 gdal 与 gromacs、Kimi 上的 samtools——在发布前被中断且没有重跑,因此没有分数。
- 评分。 所有分数都来自隐藏测试套件的官方指标,固定使用 pb-1.2.0,并以完全相同的方式计算单 Agent 和系统制品。
结论
单 Agent 缺少的不是能力,而是完成标准。由同一个模型编写、但独立于实现过程的标准,把最终实现推向了远高于单 Agent 的行为一致度。
ProgramBench 让这套标准呈现为一种特殊形式:从黑盒参考程序中恢复出来的行为清单与加权样本。
其他任务会从不同来源获得自己的完成标准。产品任务可以依据用户认可的流程与设计;迁移任务则可以依据被替换的旧系统。
真正可以推广到现实软件工作的原则是:系统需要一套外部的、可执行的完成标准。这套标准要从目标结果中推导,在实现开始收窄注意力之前建立,并持续维护,直到实际工作真正满足它。
Factory 正在把这套结构加入下一代 Missions。联系 Factory 加入候补名单。