问一个编程Agent做完没有,它说做完了。从10月19日起,Favur Evals不再采信这句话。一次运行现在按评测框架实际观察到的情况计分,模型只能拿到它能证明的那部分工作对应的分数。
Agent的回答仍然值得读。它会列出跑过哪些测试、改过哪些文件、满足了哪些标准,大多数时候这份清单是诚实的。问题在于,这份清单是Agent对自己工作的自述,写它的正是干活的那个模型,清单里没有任何东西能告诉你,哪些行是被看见发生的,哪些只是被说出来的。
Favur Evals是面向编程Agent模型的公开基准,上面每一次运行都构建在Favur之内——这是他们自研的评测框架,一个负责运行Agent团队的程序。在此前,每次得分有四分之一来自一个事实:这次运行有没有跑完。现在,已测量的那部分分数原样保留,这四分之一里的大部分被挪到了证据上。
分数原本测的是什么
四分之三的分数一直来自工作本身。八个科目从日志和分析器读取;代码质量来自lint、复杂度和覆盖率工具;速度来自请求延迟;成本纪律来自缓存行为;工具纪律来自工具报错和失败请求。这些都不依赖Agent如何描述自己。
另外四分之一来自运行的最终状态,读取的是运行留下的两个文件。这个状态能很好地回答一个问题:这次运行是否以成功结束。它说不出这次运行一开始被要求做什么、过程中哪些步骤被看见发生、沿途每一条声明是否成立。这些正是新增20分要回答的问题。
声明和观察是两种记录
整个升级背后的核心,是一个大多数Agent工具从未划出的区分。当Agent说“六份文档全部创建”,这句话是一个断言,一条有作者的声明。当评测框架看到一个进程以退出码0结束,或读取一个文件并记录它的摘要——那个只要改动一个字节就会变化的指纹——那是一条观察,是基础设施自己记下的事实。
两者都值得保留。断言告诉你Agent相信什么,当你想知道它下一步为什么那样做时,这有用。观察告诉你发生了什么。评测框架现在把两者存为不同类型的记录,下游任何环节都无法把一种误认成另一种。
榜单只对观察计分。Agent可以报告任何内容,它的报告会成为又一条记录,被标记为断言,与事实并排放着。当榜单判断某项要求是否达成时,它读的是评测框架捕获的凭据,比如运行过的进程、产生的输出、留在磁盘上的字节。
要求在开工前冻结
凭据只有在你知道它本该证明什么时才有意义,所以每个任务的要求现在都会在任何Agent被派出去之前写下并冻结。Favur把这份冻结的集合称为契约,其中包含任务的验收标准、必须交付的产物,以及用来判定它们的检查项。
冻结的契约不会漂移。如果计划中途变化,变化会产生契约的新修订版,旧版留在记录里,因此一次运行始终按它当时被要求的内容来评判。无论人还是模型,都不能在看到结果之后把某条要求改得更容易。
每条标准都指定自己的评判者。冻结的标准仍需要东西来判定,所以契约还会为它指定一个评估器——一个带版本的小程序,读取特定观察,针对这一条标准返回裁决。
每个评估器只做一件窄事。进程评估器读取一条命令的每次最终尝试,连同退出码、环境和它运行的源码。报告一致性评估器取走Agent声称的计数,比如跑了多少测试、过了多少测试,与测试解析器从真实输出里读到的结果精确比对。需求映射评估器则让每条原始需求穿过设计、计划、代码和测试。
评估器从不写分数,也从不推动流程前进。它写的是裁决。如果它崩溃或超时,裁决记为未知,绝不记为悄悄通过;失败的测试记为失败的实测证据。记录还会保留谁评判了什么,因此同一个模型换个提示词问两次,不算独立评审。
每次尝试都有自己的身份
评测框架现在会在工作放出之前,给每个参与者、每次委派、每次工具或进程尝试一个身份。身份来自基础设施,绝不来自Agent,重试会拿到新身份,而不是覆盖第一个。
这听起来像记账,而正是这种记账让其他一切可信。每条记录都写明产生它的那次尝试和它对应的契约,于是从“这被要求过”到“这被观察到”再到“这被接受”的链条可以一环一环走通。在一次不同Agent使用不同模型的运行里,这也意味着每份工作都绑定到真正做它的那个模型。
20分怎么算
一次运行的证据分是三个因子的乘积:
- 捕获率:应存在的记录中有效存在的比例。一半计运行的验收标准和交付物,一半计围绕它们的活动,比如派发、步骤、工具调用、进程和Agent的开启与关闭。
- 闭合度:运行干净结束、没有遗留项时为1.0,带着未完成项结束为0.7,记录中途断掉为0.4。
- 完整性:确认每个引用都指向真实存在的东西,每个摘要都与字节匹配。
三者相乘再折算到20分。一次运行若每条标准都有记录在案的检查通过、结束时没有遗留项、记录保持完整,就能拿满20分。
大部分记录由评测框架完成,所以捕获率的大部分和完整性的全部反映的是框架。模型能控制的那部分,才是基准真正在意的部分:它决定有多少条冻结标准走到通过且有记录的检查,以及任务结束时是否没有遗留项。
捕获率是个分数,分数的诚实程度取决于分母。如果应记录清单是按生产者自己宣告的内容构建的,那么一条记录连同它的宣告一起消失,清单也会跟着缩水,分数看起来依然漂亮。所以运行应该记录什么的清单,是在任何生产者运行之前独立推导并冻结的,每一次到达都对照它检查。生产者无法缩小自己的分母,这意味着高捕获率说明这次运行把期望它记录的东西都记下来了。
第一次完整记录的运行
他们用新规则给第一次完整记录的运行打了分。那是一个小型绘画游戏的完整构建,14个角色、87个Agent。
评测框架从13个生产者写出了9,934条记录,每一条都通过了完整性检查。所有预期操作都到达了:2,438条中的2,438条操作记录,来自39次派发、293个工作流步骤,以及1,468次工具调用。启动的87个Agent全部关闭,并绑定到各自运行的模型。6份契约在任何Agent启动前冻结,覆盖29条标准。
捕获率的操作那一半是满分。另一半要追着29条标准和交付物走到有记录的裁决,而这次金丝雀构建结束时,其中一些检查仍未闭合,所以这次运行拿到20分证据分中的10.7分——这些分在旧公式下根本不存在。剩下的分就停在记录指出的位置:那些有名字、更强的运行可以闭合的标准里。它还把分数的覆盖率,也就是建立在实测数据上的分数占比,抬到了0.82。没有记录的运行上限是0.80,所以有记录的运行是榜单能逐行背书的运行。
往后会改变什么
规则适用于榜单上的每一次运行。今天列出的262次运行都构建于记录机制存在之前,现在每一行的证据栏都显示“未记录证据”。他们没有选择事后补填。记录必须在工作发生时写下,事后重建恰恰是这次升级要取代的那种声明。
这就把量表顶端的20分空了出来。第一批有记录的运行将最先认领它们,从那以后,两次代码完成度相近的运行,可以靠能证明多少工作来拉开差距。一个把更多标准带到通过检查、结束时没有遗留项的模型,会在榜单上体现出来。
分数本身的含义也变了。Favur Evals上的一个数字现在会展示它的推导过程:从代码测出的科目、写代码时捕获的证据,以及一个说明总分中有多少建立在测量之上的覆盖率数字。比较两个模型的读者,不只能看到谁分高,还能看到每个分数里有多少是被观察到的。
Favur采用邀请制且闭源,其运行产出的代码仓库是开放的。评分方法发布在Favur Evals上,产品有自己的站点,新结果在@favurdev上发布。
热门跟贴