TL;DR
Harness 对照评测要固定任务、环境、验收和预算,让模型与配置交叉组合。先比较同一任务的结果,再用消融定位组件作用,检查模型与 Harness 的交互。等预算实验回答效率,成本曲线回答取舍;更多重试带来的成功,不能直接归功于架构改进。
分数涨了,先查实验改了什么
如果同时换了模型、加了浏览器工具,又把重试次数从一次增加到五次,成功率提高无法归因。要判断 Harness 的价值,必须让其他条件可比。
Agent Harness 包括工具接口、上下文策略、调度、重试和验收。所谓“同一个模型”,也要核对模型版本、采样参数和系统指令;两个商业产品声明使用相同模型,不代表它们的隐藏配置相同。
Anthropic 的 2026 年应用开发实验展示了单 Agent 与完整 Harness 的结果差异。其中一组案例约为 20 分钟、9 美元,对比 6 小时、200 美元。作品对比有参考价值,但预算差别很大,不能据此宣称等成本提升。这些数值也是作者的特定运行记录,并非标准价格或独立复现。
实验开始前写清一个问题。例如:“在每任务相同费用上限内,加入结构化评估反馈是否提高验收通过率?”这比“我们的新架构是否更强”更容易设计,也更容易被推翻。
用四组实验分开模型与 Harness
两个模型分别运行两套 Harness,可以观察模型收益、Harness 收益,以及二者是否互相影响。
| 配置 | 旧 Harness H0 | 新 Harness H1 |
|---|---|---|
| 模型 M0 | Y00 | Y01 |
| 模型 M1 | Y10 | Y11 |
Y 表示相同任务集上的平均验收结果。任务、起始快照、评分器和预算规则保持一致。以通过率为例:
M0 上的 Harness 收益 = Y01 - Y00
M1 上的 Harness 收益 = Y11 - Y10
交互效应 = (Y11 - Y10) - (Y01 - Y00)
交互效应大,说明 Harness 收益依赖模型。某模型需要频繁重置上下文,另一模型通过压缩就能继续;工具描述对一种模型有效,也不一定能原样迁移。不要把其中一格的结果写成普遍最佳实践。
同一任务在四组都运行,形成配对比较。随机打乱执行顺序,避免某组集中遇到接口故障或模型服务更新。无法冻结的外部服务要记录时间、版本和异常,并在报告中说明影响。
固定预算,再看成本曲线
等预算比较和质量—成本曲线解决不同问题,应该同时报告。
| 比较方式 | 固定条件 | 可以得出的结论 |
|---|---|---|
| 等费用上限 | 每任务总费用,包括失败和评估 | 该费用约束下哪组更好 |
| 等时间上限 | 每任务墙钟时间与并发规则 | 该延迟约束下哪组更好 |
| 多预算点 | 逐步增加费用或时间上限 | 改善是否值得额外成本 |
| 原生默认配置 | 各产品按默认策略执行 | 默认体验的差异,难以归因 |
费用包含生成、评估、工具和失败重试;时间包含排队与等待。达到上限仍未通过的任务计为失败或未完成,不能从统计中删除。报告所有任务的成本分布,同时单列成功任务的成本,避免幸存者偏差。
“每次成功的成本”可以用总费用除以成功数,但成功数为零时应报告未定义。不能把失败任务的费用忽略,也不能让两个系统用不同的成功定义。
消融要保留可解释的对照
消融是逐项关闭组件,观察结果变化。它测量组件在当前组合中的作用,不能直接证明组件单独使用也有效。
例如评估反馈依赖浏览器运行。关闭浏览器后反馈失效,不能简单推断“评估器无用”。应补测浏览器开关与反馈开关的四组组合,区分单独作用和依赖关系。
关闭反馈时,可以给对照组同等预算的独立重采样,测量“多花推理”与“获得缺陷信息”的区别。该对照回答的是预算内替代策略的价值;如果只是不执行评估器,则回答的是移除组件后系统整体如何变化。两种问题都合理,但不要混写。
失败切片比总分更容易指导修改:工具选择错误下降,但超时上升,说明组件可能改善决策却增加延迟。相关定义见Agent 轨迹。
Go 实践:计算配对差异与交互
下面的 Go 1.23 程序使用四个合成任务,每个任务包含四组通过结果。它演示计算口径,不代表实际模型表现。
package main
import "fmt"
type Task struct {
ID string
Pass [4]int
}
func analyze(tasks []Task) ([4]float64, error) {
var means [4]float64
if len(tasks) == 0 {
return means, fmt.Errorf("empty task set")
}
seen := make(map[string]bool)
for _, task := range tasks {
if task.ID == "" || seen[task.ID] {
return means, fmt.Errorf("missing or duplicate task identity")
}
seen[task.ID] = true
for cell, value := range task.Pass {
if value != 0 && value != 1 {
return means, fmt.Errorf("invalid outcome for %s", task.ID)
}
means[cell] += float64(value)
}
}
for cell := range means {
means[cell] /= float64(len(tasks))
}
return means, nil
}
func main() {
tasks := []Task{
{ID: "t1", Pass: [4]int{0, 1, 1, 1}},
{ID: "t2", Pass: [4]int{0, 0, 0, 1}},
{ID: "t3", Pass: [4]int{1, 1, 1, 1}},
{ID: "t4", Pass: [4]int{0, 0, 0, 1}},
}
y, err := analyze(tasks)
if err != nil {
panic(err)
}
gainM0 := y[1] - y[0]
gainM1 := y[3] - y[2]
fmt.Printf("cells=%.2f %.2f %.2f %.2f\n", y[0], y[1], y[2], y[3])
fmt.Printf("harness_gain M0=%.2f M1=%.2f interaction=%.2f\n",
gainM0, gainM1, gainM1-gainM0)
}
运行 go run main.go:
cells=0.25 0.50 0.50 1.00
harness_gain M0=0.25 M1=0.50 interaction=0.25
数组顺序是 M0H0、M0H1、M1H0、M1H1。新 Harness 在 M0 上提升 25 个百分点,在 M1 上提升 50 个百分点,交互为 25 个百分点。这里只有四个任务,不能据此判断统计显著性。
正式实验应为每格重复执行,先计算逐任务平均,再配对聚合。用任务级 bootstrap 估计差异区间,并报告样本量和抽样方法。具体重复指标见Agent 可靠性评测;把所有 Trial 当独立样本会低估任务聚集带来的不确定性。
结果报告保留哪些信息
一份可复查的报告至少包含任务与环境版本、四组配置、预算、验收器、重复次数、配对差异及失败切片。只给平均分,别人无法判断改动是否值得采用。
分析前确定主要指标与切片,避免结果出来后只挑有利任务。开发集用于调策略,最终比较使用未参与调优的任务。若反复用同一测试集选方案,它也会成为开发集。
报告可以写:“在这批代码任务、该模型版本和每任务费用上限下,结构化反馈提高了通过率,同时增加了中位延迟。”不要省略条件写成“反馈 Harness 全面领先”。机制详见Evaluator 反馈与终止策略。
常见问题
没有权限查看商业产品的完整配置怎么办?
把比较定义为产品默认体验评测,记录可见设置。可以比较结果和成本,但不要声称隔离了模型权重或隐藏指令的影响。
所有消融结果都应该相加吗?
不应该。组件可能互补或互相替代。只有实验支持近似可加时,才适合叠加估计;否则直接测量关键组合。
某组频繁超时,是否应该剔除?
如果超时属于系统运行结果,计入主指标。基础设施事故可另做敏感性分析,但剔除规则应预先确定,并同时保留原始结果。
一个预算点领先,是否就应该迁移?
还要检查任务覆盖、延迟、严重失败和维护成本。用多个预算点验证收益,再在真实工作流中做小规模验证。
参考资料
- Anthropic:Harness design for long-running application development,2026-03-24,具体应用与预算记录。
- Anthropic:Demystifying evals for AI agents,2026-01-09,模型与 Harness 共同构成被测系统。