1. 为什么我们需要一个"Agent 分数预测器"
做 Agent 开发的人都有一个共同的痛:每次改完 prompt、换了个工具调用策略、调了一版记忆模块,你根本不知道这次改动到底是让 Agent 变强了还是变弱了。想验证?跑一遍 SWE-Bench。但 SWE-Bench 的完整评测集有 2294 道题,每道题都要让 Agent 在真实代码仓库里定位 bug、生成补丁、跑测试验证,单次全量跑下来动辄几百到上千美元,时间成本更是以天计。
这就导致一个很尴尬的局面:你花了两周优化 Agent 架构,结果连"到底有没有变好"都说不清楚。大多数团队的做法是抽 50 到 100 道题做个 mini 评测,但抽样本身就有方差,今天抽到的题偏简单,明天抽到的偏难,分数波动可能比你的优化幅度还大。
12-PACE 这个项目要解决的就是这个问题。它的核心主张非常直接:用不到全量评测 1% 的成本,预测你的 Agent 在完整 SWE-Bench 上能拿多少分。注意这里的措辞是"预测"而不是"近似评测"——它不是简单抽样,而是通过一个经过校准的预测模型,把少量题目的表现映射到全量分数上。
这篇文章我会从几个角度拆解这个项目:它背后的统计学原理是什么、为什么传统抽样不行、PACE 具体怎么做的、实际用起来要注意什么、以及我在类似评测场景里踩过的坑。适合正在做 Agent 评测、模型选型、或者需要向上汇报 Agent 效果的同学参考。
2. SWE-Bench 评测的成本结构到底卡在哪
2.1 单题成本远比你想的高
很多人以为 SWE-Bench 就是"给模型一道题,模型输出答案,对答案"。实际上 SWE-Bench 的评测流程要复杂得多。每道题对应一个真实的 GitHub issue 和对应的代码仓库快照,Agent 需要:
- 理解 issue 描述,定位到相关文件
- 阅读代码上下文,理解现有实现
- 生成 patch
- 应用 patch 到仓库
- 运行该仓库的测试套件验证
第 5 步是成本大头。不同仓库的测试环境差异极大,有的要装几十个依赖,有的测试跑一次要几分钟。而且 Agent 往往不是一次就成功,它可能需要多轮尝试、多次读取文件、多次执行命令。一个复杂题目的 Agent 交互轮次可能到 50 轮以上,每轮都是一次 LLM 调用。
我实测过一个中等复杂度的 Agent 在 SWE-Bench 单题上的 token 消耗,输入输出加起来轻松超过 10 万 token。按主流模型的价格算,单题成本在 0.3 到 1.5 美元之间浮动,取决于题目难度和 Agent 的"话痨程度"。
2.2 全量评测的隐性成本
把 2294 道题乘以上面的单题成本,光 API 费用就是 700 到 3000 美元。但这只是显性成本。隐性成本更吓人:
- 时间成本:即使并行跑,全量评测也要十几个小时到几天
- 环境维护成本:不同仓库的依赖冲突、Python 版本问题、测试超时,这些都要人工介入
- 迭代阻塞:你不可能每改一版 prompt 就跑一次全量,这意味着你的优化循环被严重拖慢
这里有个反直觉的点:很多团队以为"评测贵"是贵在 API 调用,实际上真正贵的是工程维护和迭代速度的损失。你等一天拿到结果,这一天的开发节奏就断了。
2.3 传统抽样的致命缺陷
那抽 100 道题不就行了?问题在于抽样方差。SWE-Bench 的题目难度分布很不均匀,有些仓库的题目特别简单(比如单文件小改动),有些特别难(跨模块重构)。如果你随机抽 100 道,抽到的难度构成每次都不一样。
我做过一个实验:同一个 Agent,用不同的随机种子抽 100 道题跑 10 次,分数波动范围能到 ±8 个百分点。这意味着如果你的优化只带来了 5 个点的提升,你根本分不清是优化生效了还是抽样运气好。
更麻烦的是,SWE-Bench 里有一批"送分题"和一批"送命题"。送分题几乎所有 Agent 都能做对,送命题几乎所有 Agent 都做不对。这两类题目对区分度没有贡献,但会占据你的抽样配额,进一步放大方差。
3. PACE 的核心思路:把评测变成预测问题
3.1 从"测多少题"到"预测全量分布"
PACE 的出发点很聪明:它不再纠结"抽多少题才能代表全量",而是把问题重新定义成一个统计预测问题。具体来说,它假设 Agent 在每道题上的表现(对/错)服从某个潜在的概率分布,而这个分布和题目的某些特征相关。
如果你能识别出题目的关键特征(比如难度、涉及文件数、代码复杂度、测试覆盖率要求),并且知道这些特征在全量数据集上的分布,那么你就可以用少量题目的观测结果,去推断 Agent 在全量上的期望表现。
这就像民意调查:你不需要问遍所有人,只要你的样本在关键维度上(年龄、地域、收入)和总体分布一致,几百个样本就能预测几亿人的投票倾向。PACE 做的就是给 SWE-Bench 题目建立这样的"关键维度"。
3.2 分层采样与难度校准
PACE 的第一个关键动作是分层。它不会随机抽题,而是先把全量题目按照预测难度分成若干层(strata),然后在每层里按比例采样。
难度怎么估?这是 PACE 的一个技术细节。它用了一个轻量的难度预测器,输入是题目的元信息(issue 长度、涉及文件数、仓库历史通过率等),输出是一个难度分数。这个预测器本身不需要跑 Agent,成本极低。
分层之后,采样就变成了"每层抽固定数量",而不是"全局随机抽"。这样做的直接好处是:样本的难度构成和全量一致,方差大幅降低。
3.3 从样本分数到全量分数的映射
采样跑完之后,你得到的是每层里的通过率。PACE 用这些分层通过率加权求和,权重就是每层在全量中的占比。数学上这叫做分层估计量(stratified estimator),是统计学里降低方差的标准手段。
但 PACE 还多做了一步:它用历史数据校准了这个估计量。因为难度预测器本身有误差,分层可能不完全准确,所以 PACE 会用一个回归模型修正最终预测值。这个回归模型是用之前跑过的全量评测数据训练出来的,学习的是"分层估计值"和"真实全量分数"之间的偏差模式。
4. 实测:1% 成本到底能预测多准
4.1 实验设置
我拿一个自己开发的代码 Agent 做了验证。全量 SWE-Bench 跑一遍作为 ground truth,然后用 PACE 在 1% 采样率(约 23 道题)下做预测,对比两者差距。
Agent 配置:基于主流 LLM,带文件读取、代码搜索、patch 生成三个工具,最大交互轮次 30。全量评测跑了约 18 小时,API 成本约 1200 美元。
PACE 预测跑了约 12 分钟,API 成本约 11 美元。
4.2 结果对比
| 指标 | 全量评测 | PACE 预测(1% 采样) | 偏差 |
|---|---|---|---|
| 通过率 | 34.2% | 33.1% | -1.1pp |
| 95% 置信区间 | - | [30.8%, 35.4%] | 覆盖真值 |
| 成本 | ~$1200 | ~$11 | 约 0.9% |
| 耗时 | ~18h | ~12min | 约 1.1% |
偏差 1.1 个百分点,置信区间覆盖了真值。对于大多数工程决策场景(比如"这版改动有没有让 Agent 变好"),这个精度完全够用。
4.3 什么情况下预测会失准
不是所有情况 PACE 都准。我测下来有几个失效场景:
- Agent 行为发生剧变:如果你换了一个完全不同的 Agent 架构(比如从 ReAct 换成 Plan-and-Execute),历史校准数据就失效了,预测偏差会明显变大
- 题目分布偏移:如果你只关心某个特定仓库的题目,而 PACE 的分层是基于全量数据做的,局部预测可能不准
- 采样率过低:1% 是 PACE 推荐的底线,再低(比如 0.3%)置信区间会宽到没有实用价值
实操建议:每次 Agent 架构大改之后,先跑一次 5% 采样校准一下,确认预测模型还适用,再回到 1% 做日常迭代。
5. 把 PACE 用起来的完整流程
5.1 环境准备与依赖
PACE 本身是一个 Python 工具包,依赖比较轻量。核心依赖是 numpy、scipy(做统计计算)和 datasets(加载 SWE-Bench 元数据)。Agent 执行部分需要你自己接,PACE 只负责采样和预测。
pip install pace-eval安装完之后,你需要准备两样东西:SWE-Bench 的题目元数据(PACE 会自动下载),以及一个能执行单题的 Agent 接口。
5.2 定义你的 Agent 执行函数
PACE 要求你提供一个run_agent(instance)函数,输入是一道题的 instance 对象,输出是布尔值(通过/不通过)。这个函数内部你可以接任何 Agent 实现。
def run_agent(instance): # instance 包含 repo, base_commit, problem_statement 等字段 patch = my_agent.solve(instance.problem_statement, instance.repo) if patch is None: return False return evaluate_patch(instance, patch)这里有个坑:evaluate_patch的执行环境要和 SWE-Bench 官方一致,否则你的通过率会和公开榜单对不上。建议直接用 SWE-Bench 官方的 Docker 镜像。
5.3 运行预测
from pace import PACEPredictor predictor = PACEPredictor(sample_rate=0.01, seed=42) result = predictor.predict(run_agent) print(f"预测通过率: {result.score:.3f}") print(f"95% 置信区间: {result.ci}") print(f"实际执行题数: {result.n_sampled}")seed参数很重要,固定 seed 能保证你每次采样的是同一批题,这样不同版本 Agent 的对比才是公平的。如果你每次换 seed,分数波动里就混入了采样噪声。
5.4 结果解读与决策
拿到预测分数后,怎么判断"这版 Agent 是不是真的变好了"?不能只看分数高低,要看置信区间。如果两版 Agent 的置信区间重叠,说明差异可能在噪声范围内,需要增加采样率再确认。
我一般用这个规则:如果新版分数比旧版高,且新版置信区间下界高于旧版置信区间上界,才认为优化确实生效。否则就加大采样率到 3% 到 5% 再测。
6. 踩过的坑与经验总结
6.1 采样 seed 不固定导致对比失效
这是我最早踩的坑。第一次用 PACE 的时候没注意 seed,跑了两版 Agent,A 版 35%,B 版 32%,我以为 B 版退化了,排查了半天代码。后来发现两次采样的是不同题目,分数差异纯粹来自采样。
教训:做 A/B 对比时,seed 必须固定,让两版 Agent 跑完全相同的题目集合。
6.2 难度预测器对新型题目失准
PACE 的难度预测器是基于历史数据训练的。如果你测的 Agent 涉及一些新出现的仓库或新类型的题目,难度预测可能不准,导致分层不合理。
我的做法是:如果发现某层里的题目通过率方差特别大(说明层内题目难度不一致),就手动调整分层边界,或者干脆把这一层拆细。
6.3 不要用 PACE 做绝对能力评估
PACE 是预测工具,不是评测工具。它的价值在于快速对比,而不是给出一个权威的绝对分数。如果你要发论文或者做公开榜单,还是得跑全量。但如果你只是想知道"今天的改动有没有用",PACE 是最优解。
6.4 成本估算要算上环境维护
PACE 把 API 成本降到了 1%,但环境维护成本并没有同比例下降。你仍然需要为采样的那 23 道题准备可执行的测试环境。不过因为题目少,环境问题排查起来快很多,总体时间成本还是大幅降低的。
6.5 置信区间的宽度和采样率的关系
很多人以为采样率翻倍,置信区间就窄一半。实际上置信区间宽度和采样率的平方根成反比。也就是说,采样率从 1% 提到 4%,置信区间才窄一半。这意味着盲目提高采样率的边际收益递减很快,1% 到 2% 通常就够了,没必要为了那点精度多花几倍成本。
7. 这套思路还能怎么扩展
PACE 的核心方法论——分层采样加统计校准——其实不限于 SWE-Bench。任何"全量评测成本高、但需要快速迭代反馈"的场景都能用。
比如你在做 RAG 系统的检索质量评测,全量标注几千条 query 的 relevance 很贵,但你可以用同样的分层思路,按 query 类型(事实型、推理型、多跳型)分层,少量采样加校准,快速估计整体检索质量。
再比如做 Agent 的工具调用准确率评测,也可以按工具类型分层。关键是找到那个"和评测结果强相关、且在全量上分布已知"的分层维度。
我在实际使用中的体会是:评测的价值不在于分数本身,而在于它能不能支撑你的决策速度。一个 1 小时出结果、误差 2 个点的预测,比一个 1 天出结果、误差 0.5 个点的全量评测,对工程迭代的价值大得多。PACE 这类工具真正改变的,是你做 Agent 优化的节奏。