提出pass-all-k指标衡量AI系统真实用户体验,比平均准确率更能反映实际故障率;通过60行Python代码实现可靠性测试框架,并指出任务形状聚类是可行动的改进方向。
拿你已有的系统跑一下。
from collections import Counter
def pass_all_k(run, tasks, k=8):
"""run(task, variant) -> bool. Returns (pass_all_rate, mean_rate)."""
all_pass, total = 0, 0
for t in tasks:
results = [run(t, variant=i) for i in range(k)]
all_pass += all(results)
total += sum(results)
return all_pass / len(tasks), total / (len(tasks) * k)
返回两个数字。第二个是你仪表盘上看到的。第一个是用户实际经历的,因为用户没有"再试一次直到成功"的选项。
两者很少接近。在我测量过的系统里,平均值大约 0.85 时,pass-all-8 大约只有 0.45,而且这个差距从来没有反向出现过。
如果失败是独立的(失败率 p),pass-all-k 就等于 (1-p)^k,你就能直接算出来而不需要测量。但失败不是独立的——这才是关键。它们按任务类型聚类。
这种聚类才是可操作的部分。2026 年的一项可靠性研究在十个模型和 396 个任务的基准测试上运行了 23,392 个 episode,发现退化是领域相关的而非模型相关的:随着任务长度增加,软件工程的优雅退化分数从 0.90 降到 0.44,而文档处理几乎没动,从 0.74 到 0.71。
所以你 harness 的有趣输出不是那个数字,而是哪些任务在失败的集合里。
这是大多数自建 harness 犯错的地方。八个完全相同的调用测的是你的缓存。你需要八个真正不同的同一意图变体。
import random
REPHRASE = [
lambda s: s,
lambda s: s.lower(),
lambda s: f"I need to {s[0].lower()}{s[1:]}",
lambda s: f"{s} Please be thorough.",
lambda s: s.replace("?", "").strip() + ", if you can.",
]
def make_variant(task: dict, variant: int) -> dict:
rng = random.Random(f"{task['id']}:{variant}") # deterministic
out = dict(task)
out["prompt"] = rng.choice(REPHRASE)(task["prompt"])
if task.get("states"):
out["state"] = rng.choice(task["states"])
return out
用 task_id:variant 作为种子,而不是全局计数器。这样任务 7 的变体 3 跑出来的输入和上周一样——这就是"能跨版本对比的 harness"和"不能跨版本对比的 harness"之间的差别。
可靠性 harness 的失败模式是过早聚合。
import json, pathlib
def evaluate(run, tasks, k=8, out="reliability.jsonl"):
fh = pathlib.Path(out).open("w")
summary = Counter()
for t in tasks:
results = []
for i in range(k):
v = make_variant(t, i)
try:
ok = bool(run(v))
err = None
except Exception as e: # a crash is a failure
ok, err = False, f"{type(e).name}: {e}"
results.append({"variant": i, "ok": ok, "error": err})
rec = {
"task_id": t["id"],
"shape": t.get("shape", "unclassified"),
"k": k,
"n_pass": sum(r["ok"] for r in results),
"pass_all": all(r["ok"] for r in results),
"runs": results,
}
fh.write(json.dumps(rec) + "\n")
summary[t.get("shape", "unclassified")] += rec["pass_all"]
fh.close()
return summary
shape 是那个值得下功夫的字段。给你的任务打上"它是什么"而非"哪个模型跑了它"的标签:lookup、multi_step、writes_state、long_horizon、needs_tool。按 shape 分组看失败,通常第一轮跑完模式就出来了。
异常算失败。一个只统计答案错误而让超时溜过去的 harness 会告诉你一个让你安心的谎言。
2026 年的三项发现告诉你优先看哪里,每项都是你可以跑的一个检查,而非一个你需要相信的说法。
如果失败的 shape 是 multi-agent,测试一下 single-agent 版本。一项跨 180 个受控配置的研究发现,一旦单个 agent 在某任务上的准确率超过大约 45%,增加 agent 就开始产生负收益,而且独立 agent 相比 single-agent 基线放大了 17.2 倍错误,而集中式协调将其控制在 4.4 倍。读密集型工作可以并行。写密集型工作不行,因为两个 agent 写就会产生两个没人协调的决策。
如果失败的 shape 是 long-horizon,不要以为更好的模型能解决它。同样的可靠性研究:能力和可靠性排名出现了分化,高级模型展现了高达 19% 的崩溃率,原因是它们尝试了更困难的多步骤策略。
在你提高推理 effort 之前,先测量它。在 21,730 次 rollout 中,更高的推理 effort 在 21 个模型和基准组合的 36 种组合中产生了相等或更低的准确率。这是一个需要按任务调的参数,有真实的负面影响,不是质量旋钮。用相同的种子集跑三个 effort 级别只要一个下午。
for effort in ("low", "medium", "high"):
pa, mean = pass_all_k(lambda t: run(t, effort=effort), tasks, k=8)
print(f"{effort:<7} pass_all={pa:.2f} mean={mean:.2f}")
注意 mean 上升而 pass_all 下降的情况。那是一个系统平均变好但可靠性变差的情况,如果你只跟踪其中一个,这种变化是看不见的。
- name: reliability
run: |
python -m harness --k 8 --tasks tasks/core.jsonl --out reliability.jsonl
python -m harness.gate --min-pass-all 0.60 --baseline main.jsonl
两条规则让这个东西在我待过的团队里存活下来。用相对上一次运行的回归做 gate,而不是用绝对阈值,因为绝对数字第一次拦住发布时就会被往下调。在 PR 上跑 k=3,而完整 k 每晚跑一次,因为二十分钟的 pre-merge 检查会被关掉。
k=8 是任意的。它足够大,让运气不能再带你过关;又足够小,人们真的会去跑。如果 5 是能完成的数字,那就用 5。
variant 函数编码了你对"同一个请求"的假设,合理的人会有不同意见。这是好事:它把争论推到了代码评审里,而不是事故发生之后。
而且这测的是可靠性,不是正确性。一个八次全挂的任务是完全可靠的,但完全错误。你仍然需要断言。
这些都不是新想法。任何运行过支付系统或数据库的人已经在用"最差请求"而非"平均请求"来思考了。我们停止这样做是因为系统开始听起来很自信。
Sources: arXiv 2603.29231 (31 March 2026, 23,392 episodes); arXiv 2512.08296 (December 2025, 180 configurations); arXiv 2510.11977 (ICLR 2026, 21,730 rollouts).
如果你已经在测量类似的东西,我想知道你的 variant 函数做了什么。这一块还没有 established 的惯例,我猜每个人都悄悄自己发明了一套。