pass@1 不等于代码可用,benchmark 高分不等于实际能干活
现有评测的版图
按任务类型划分,代码相关的 benchmark 大致可以分成这几类:
函数级代码生成
| Benchmark | 规模 | 特点 |
|---|---|---|
| HumanEval | 164 题 | OpenAI 出品,函数补全 |
| MBPP | 974 题 | Google 出品,入门级 Python |
| HumanEval+ | 扩展测试 | 在 HumanEval 上加更多测试用例 |
| LiveCodeBench | 持续更新 | 用最新的竞赛题,避免训练数据污染 |
主要衡量:单个函数的实现正确性。
竞赛级代码生成
| Benchmark | 来源 | 特点 |
|---|---|---|
| CodeContests | Codeforces / CodeChef / AtCoder | 算法竞赛题 |
| APPS | LeetCode 等 | 难度分级 |
| USACO | 美国信息学奥林匹克 | 偏算法 |
主要衡量:复杂算法的实现能力。
软件工程级任务
| Benchmark | 任务 | 特点 |
|---|---|---|
| SWE-bench | 修复真实 GitHub Issue | 涉及多文件、大代码库 |
| SWE-bench Lite | SWE-bench 子集 | 任务更聚焦,更容易 |
| SWE-bench Verified | SWE-bench 子集 | 过滤了模糊或质量低的 Issue |
| RepoBench | 跨仓库的代码补全 | 关注上下文检索 |
主要衡量:在真实代码库环境里完成开发任务的能力。
交互式编程
| Benchmark | 环境 | 特点 |
|---|---|---|
| InterCode-SQL | 数据库 | 通过查询交互完成任务 |
| InterCode-Bash | shell | 通过命令完成系统操作 |
| MINT | 多个 | 多轮工具使用 |
主要衡量:在交互式反馈中改进的能力。
现有评测的几个共同问题
1. 训练数据污染
很多老 benchmark(特别是 HumanEval、MBPP)的题目早就被各家模型纳入训练数据。模型可能不是在"解题",而是在"回忆答案"。
应对:
- LiveCodeBench 这类持续更新的 benchmark
- 用模型训练 cutoff 之后的题目评测
- 但完全避免污染很难,特别是对开源数据
2. pass@1 不等于"代码质量"
测试通过只能说明功能基本对,无法衡量:
- 时间复杂度是否合理(暴力解能过小数据,但生产中用不了)
- 代码可读性
- 边界处理是否完备(测试覆盖不到的边界,可能就是隐藏 bug)
- 是否符合项目的代码风格和惯例
- 是否引入了安全漏洞
# 这两份代码 pass@1 可能都通过,但质量差很多
# 实现 A:O(n²) 嵌套循环
def find_duplicates(nums):
result = []
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] == nums[j] and nums[i] not in result:
result.append(nums[i])
return result
# 实现 B:O(n) 哈希计数
def find_duplicates(nums):
seen = set()
duplicates = set()
for n in nums:
if n in seen:
duplicates.add(n)
else:
seen.add(n)
return list(duplicates)
3. 任务边界太清晰
benchmark 的题目都有明确的输入输出规范。真实开发里,需求经常是模糊的:
- "让这个页面加载得快一点"——快多少算够?
- "把这段代码重构得更易读"——什么是更易读?
- "修复一个偶现的 bug"——bug 复现条件不明确
这类任务现有 benchmark 几乎不涉及。
4. 不衡量长任务
大多数 benchmark 的任务是分钟级的(解一道题、修一个 bug)。但真实工程任务往往是小时到天级的:
- 实现一个新功能涉及多个模块
- 重构涉及十几个文件
- 调研性任务需要先理解大量代码
这类长任务上的表现,和短任务上的表现不一定一致。
5. 不评测"知道自己不知道"
Agent 应该在不确定时主动询问,而不是瞎编。但现有 benchmark 都期望 Agent 给出答案,主动提问反而会被记为"未完成"。
这导致评测高分的模型在实际使用中可能很激进,明明不该确定也强行输出。
一个更接近真实的评测应该考虑什么
如果要设计一个更全面的 Code Agent 评测,下面这些维度值得纳入:
任务复杂度的分层
L1: 函数级补全(HumanEval 这类)
L2: 文件级修改(修一个 bug,改一个函数)
L3: 模块级修改(涉及 3-5 个相关文件)
L4: 仓库级任务(设计新功能,涉及多个模块)
L5: 跨仓库任务(多个 service 协同改动)
每一级用不同的评测指标,不能用同一套 pass@1 衡量所有任务。
多维度评分
不只看"是否通过测试",还看:
| 维度 | 衡量方式 |
|---|---|
| 功能正确性 | 测试通过率 |
| 代码质量 | 静态分析工具(pylint、ruff) |
| 性能 | 运行时间、内存使用 |
| 风格一致性 | 和项目现有代码的相似度 |
| 修改最小性 | diff 的大小(同等效果下越小越好) |
| 副作用 | 是否引入新的 lint warning |
主动询问能力
设计一些故意模糊的任务,看 Agent 会不会问澄清问题:
任务:"给我加一个用户登录功能"
好的 Agent 应该问:
- 用什么认证方式?(密码 / OAuth / Magic Link)
- 用户表的 schema 是怎样的?
- 现有项目有没有 session 管理?
差的 Agent 直接编一个实现交差。
失败恢复
任务故意安排几个会失败的中间步骤,看 Agent 怎么处理:
- 代码报了 ImportError,Agent 是装包还是改导入?
- 测试运行超时,Agent 是优化算法还是改测试?
- 修改后破坏了其他测试,Agent 是回滚还是修正?
安全性
让 Agent 处理含有恶意指令的输入,看是否被诱导执行危险操作。
真实评测的几个困难
理想的评测设计上面已经列了,但实际做起来很难:
1. 主观维度难自动化:代码可读性、风格一致性这些只能靠人评,成本高。
2. 复杂任务的标准答案难定:一个 feature 可能有十种合理实现,怎么判定 Agent 的实现"够好"?
3. 长任务评测周期长:一个任务跑半小时,跑 200 个 episode 就要一周,迭代周期太慢。
4. 真实场景采样困难:好的真实任务样本需要从实际项目里采集 + 标注,成本远高于构造测试题。
这也是为什么主流 benchmark 还是聚焦在函数级、文件级的可自动化评测上——不是不知道更全面的评测好,而是做不出来或者做不起。
实际选用 benchmark 的几点参考
如果你要评估一个 Code Agent 在你的场景下能不能用:
先看任务复杂度匹配
如果你的场景是写小工具函数,HumanEval 的成绩有参考价值;如果是改公司的生产代码库,SWE-bench Verified 更接近。
关注模型 cutoff 后的成绩
LiveCodeBench 这类持续更新的 benchmark,反映的是模型真正的能力,而不是记忆。
自己设计内部测试集
从你自己的代码库里挑 10-20 个真实的小任务,让候选 Agent 都跑一遍,看具体表现。这种内部评测比任何公开 benchmark 都更有参考价值。
关注失败模式而不只是平均分
90% 通过率的 Agent 看起来比 70% 的好,但如果那 10% 失败是悄无声息地输出错误结果(而不是报错),它在生产里比 70% 但失败时会显式承认的 Agent 更危险。
小结
Code Agent 的评测目前还远不成熟。主流 benchmark 给了我们一些可比较的数字,但这些数字和"在真实开发场景里有多大用"之间,仍然有不小的距离。
对实际项目来说,自己的代码库 + 自己的真实任务比任何公开 benchmark 都更能告诉你一个 Agent 适不适合你。公开 benchmark 用来筛选候选,内部评测用来做最终决策。
未来几年值得关注的方向:长任务评测、多维度评分(不只 pass@1)、主动询问能力的衡量、安全性评测。这些方向上有进展时,对实际工程的指导意义会显著超过现在的 benchmark。
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:17. 代码 Agent 评测方法的设计反思
本文链接:https://www.sshipanoo.com/blog/ai/code-agent-harness/17-代码Agent评测的设计反思/
本文最后一次更新为 天前,文章中的某些内容可能已过时!