想象你是一家米其林餐厅的神秘评审员。你不会给厨师出一道虚构的“如果顾客点了这道菜会怎样”的假设题,而是直接拿来上周真实顾客的投诉单——“牛排煎得过熟”“上菜等了四十分钟”——让厨师现场重做,再用顾客满意的回访记录来打分。SWE-bench(软件工程基准测试)干的就是这件事:它不属于AI编程的“模拟考”,而是从全球开发者每天真实提交的 GitHub 代码修复记录(Pull Request,简称PR)中取材,把真实世界里发生过的 bug 修复过程,变成一道一道可复现、可评分的考题,用来检验 AI 智能体(Agent)到底能不能像人类程序员一样把代码改对。真实、具体、有标准答案,这正是它成为 RAG(检索增强生成)与 Agent 评测领域标杆的核心原因。
掌握 SWE-bench 的构建逻辑,你就能设计出公平、可复现的 AI 编程评测方案,让你的智能体在真实代码任务上的表现变得可以被度量、被信任。
可视化演示
演示SWE-bench从真实GitHub PR构建评测实例:PR筛选、issue提取、代码变更与测试用例生成,以及模型自主修复的评测机制。
本节配有交互动效(进入视口后自动加载,约 3KB)。
模式1:PR筛选 从真实仓库挖掘PR 筛选条件:解决issue、含测试 PR→instance 将真实开发转化为评测任务
数据渊源:题源从哪来
米其林评审委员会在选题时有个铁律:考题必须来自真实顾客的投诉记录,而不是评审员自己编造的假设场景。SWE-bench 遵循同样的哲学——它的每一道题,都源于 GitHub 上真实发生过的代码修复事件。GitHub 是全世界程序员共同维护代码的平台,每天都有成千上万的 Pull Request(简称 PR,即“代码修改请求”)被提交。一个开发者发现 bug、写好修复代码、提交 PR,维护者审核通过后把这个 PR 合并进项目主干,整个过程就像顾客投诉、厨师改进、主厨验收一样真实完整。
SWE-bench 团队走了一条“取材于真实”的路线:他们从 GitHub 上筛选出大量已合并的 PR,这些 PR 必须明确指向某个问题修复——也就是说,PR 的描述里要清楚地写着“这个改动修了哪个 bug”。举个例子,一个 PR 写着 “Fixes #1234:修复列表索引越界”,这就把一次代码改动和一次具体故障牢牢绑定。团队把这样的“故障-修复”配对记录下来,作为构建评测题目的原始素材。
与此同时,第一版 SWE-bench 聚焦 Python 语言的开源项目。为什么?因为 Python 生态拥有成熟统一的测试框架(如 pytest),测试用例可以标准化运行;而且 Python 的开源社区活跃,真实 bug 修复记录丰富。这相当于评审委员会只从菜品记录最完整、回访机制最成熟的餐厅取材——来源可靠,后续的验证才有说服力。
回到比喻:真实世界的投诉单哪怕不完美,也比虚构的考题更能看出厨师的真实水平。SWE-bench 坚持用真实 PR 做题库,正是为了让 AI 智能体面对的不是“温室里的习题”,而是开发者真正踩过的坑。
筛选标准:四道关卡
评审委员会收到海量投诉单后,不能全盘照收,必须经过严格的筛选。一道投诉要成为考题,得满足四个条件:顾客确实投诉过、投诉内容有据可查、能还原当时的场景、还得确认这个投诉不是偶发误会。SWE-bench 对 GitHub 上的 PR 也设置了类似的四道关卡。
第一道关卡是“合并状态”。一个 PR 只有被项目维护者正式合并进主干,才说明它的修复方案得到了人类专家的认可——这相当于一份被主厨签了字的处理记录。被关闭但未合并的 PR(比如方案被否了或者作者自己撤了),一律不采用。第二道关卡是“语义关联”。PR 必须在描述中明确引用对应的 issue 编号(如 "Fixes #1234"),确保这次代码改动和某个具体问题之间有清晰的因果关系,而不是顺手的无关重构。
第三道关卡是“可复现性”。每个候选 PR 必须包含配套的测试代码补丁——也就是 PR 作者在修复 bug 的同时写下的验证程序。没有测试,就无从判断修复是否真的有效,这类 PR 直接淘汰。第四道关卡是“高采样验证”。评测团队会在不同随机种子下反复运行测试,确认这些测试不是那种时好时坏的“运气测试”(即 flaky 测试)。这就像评审员要多次重现顾客说的“菜太咸”,确认不是那天厨师手抖的偶然事故。
这四道关卡依次过滤,把成千上万的 PR 压缩成几百个可靠的评测实例。看似严苛,却保证了基准测试的公信力——每一道题都经得起推敲,每一次评分都有据可依。
测试提取:双清单验收
投诉单被选中后,质检员要设计一套验收标准:怎么算改好了?怎么算没改坏?SWE-bench 的做法是从 PR 附带的测试补丁(test_patch)入手,把测试分成两组,对应两条验收标准。test_patch 就是 PR 作者在修复 bug 时写下的测试代码,这些测试像“探针”一样,专门检测那个 bug 是否还存在。
第一组叫 FAIL_TO_PASS,直译是“从失败到通过”。这些是在修复前代码上运行会失败、而应用了修复补丁后必须通过的测试。它们精确对应顾客投诉的痛点——如果修复后这组测试仍然失败,说明 bug 根本没修好。第二组叫 PASS_TO_PASS,直译是“从通过到保持通过”。这些是在修复前就正常通过、修复后也不允许被改坏的测试。它们守护的是既有功能——修复一个 bug 不能顺手弄坏另一个功能,就像厨师加盐补救一道菜,不能把别的菜也搞咸了。
分类方法说来直观:先把 test_patch 里的测试分别运行在“修复前代码”和“修复后代码”两份快照上,观察每个测试的状态变化。在修复前失败、修复后通过的,归入 FAIL_TO_PASS;在修复前通过、修复后依然通过的,归入 PASS_TO_PASS。这个双向验证的思路,构成了 SWE-bench 评测的核心机制。
回到米其林的场景:FAIL_TO_PASS 是“顾客抱怨的那道菜必须变好吃”,PASS_TO_PASS 是“菜单上其他菜必须保持原味”。两套清单同时核对,才敢给这次修复打上“通过”的印章。
任务构建:密封的考卷
筛选完素材、提取完测试,接下来要把这一切封装成一份标准化的“考卷”——也就是 SWE-bench 的一个评测实例(instance)。每个实例就像评审团递给厨师的一个密封信封,里面装好了全部材料,不许讨价还价。
信封里有什么?第一项是问题描述(problem statement),直接取自 GitHub issue 的原文,例如“当用户输入空列表时程序崩溃,期望返回空结果”。这是唯一会展示给 AI 智能体的信息——相当于顾客的原话投诉,Agent 必须自己读懂问题、自己定位代码。第二项是代码库快照(base commit 对应的仓库状态),也就是 bug 发生时仓库的完整代码。这是“后厨的现场还原”:食材、工具、半成品都摆在 bug 发生的那一刻。第三项是测试补丁和标准修复(gold patch)——注意,标准修复是评分时供对照的答案,绝不会提前交给智能体。提交后的验证方式,是把 Agent 生成的修复补丁应用在快照上,然后运行两组测试,用统一公式判定是否通过。
判定公式可以写成:
这就像评审团最后亮分:菜必须变好(F2P 全通过),别的菜不能出问题(P2P 全通过),任何一项不达标,整场修复都不算数。标准统一、过程透明,这就是 SWE-bench 能成为行业标尺的原因。
- 实例编号 i下标 i 表示第 i 个评测实例,N 是实例总数。
- FAIL_TO_PASS 子集判定$\text{F2P}_i \subseteq \text{Test}^{\text{pass}}_i$ 表示第 i 个实例中所有“必须修复后才能通过”的测试,都出现在 Agent 修复后实际通过的测试集合里——一个都不能少。
- PASS_TO_PASS 子集判定$\text{P2P}_i \subseteq \text{Test}^{\text{pass}}_i$ 表示所有“原本通过、修复后也不能坏”的测试,也全部保持通过——回归一个都不允许。
- 逻辑与运算符号 $\land$ 表示两个条件必须同时成立。只修好 bug 却破坏了原有功能,仍然算失败;原有功能完好但 bug 没修好,更算失败。
- 指示函数与平均$\mathbb{I}[\cdot]$ 是“指示函数”,条件为真记 1、为假记 0;$\frac{1}{N} \sum_{i=1}^{N}$ 把所有实例的结果加起来求平均,得到最终通过率。
质量保障:守住底线
有了考卷和评分标准,还差最后一环:防止作弊和意外。米其林评审团最怕两件事——厨师提前拿到考题,或者抽到一道根本没法复现的“幽灵投诉”。SWE-bench 的质量保障就是冲着这两件事去的。
第一道防线是数据泄漏防护。AI 模型训练时可能会“背”过 GitHub 上的代码,如果评测用的 PR 恰好也在训练数据里,就相当于考生提前看过答案。SWE-bench 的处理方式是时间切分:按提交时间严格划分,保证评测实例的“修复提交时间”晚于模型训练数据的截止时间,从源头切断“背答案”的可能。第二道防线是高采样机制。前面提到的高采样不只是筛选用——在正式发布前,团队还会对每个实例进行多次重复运行,剔除 flaky 测试,确保“失败”不是因为偶发环境抖动,而是真的没修好。
第三道防线是可复现性机制。评测环境被固定在标准化的容器(如 Docker)中,依赖版本、系统环境全部锁定,保证同一个修复补丁在任何机器上跑出的结果一致。第四道防线是人工复核,标注者会逐个检查实例的问题描述是否清晰、测试分类是否合理、修复目标是否明确,把机器筛选的漏网之鱼再捞一遍。
这四道防线层层设卡,共同守护一个目标:公平。只有公平的考题,才能让不同团队、不同模型之间的分数有可比性;只有可复现的结果,才能让学术研究和工业落地的结论真正站得住脚。
应用价值:行业试金石
当一套评测体系足够真实、公平且可复现,它就会成为行业公认的试金石。正如米其林星级一旦被厨师界广泛接受,就变成了整个行业追逐的荣誉。SWE-bench 在 RAG 与 Agent 评测领域的地位正是如此。
在 RAG(检索增强生成)评测中,研究者希望知道“检索到的代码片段和文档,到底有没有帮智能体更好地定位和修复 bug”。SWE-bench 恰好提供了这样的实验场:Agent 先检索仓库信息、再生成修复补丁,用最终通过率倒推检索质量。在 Agent 评测中,SWE-bench 更是标准动作——几乎每一篇关于编程智能体的论文,都会报告模型在 SWE-bench 上的通过率,用它和其他模型横向对比。OpenAI、Anthropic、Meta 等机构的研发团队也在内部用它衡量模型的代码修复能力,并在技术报告中公开分数。
当然,SWE-bench 也有局限:它目前主要覆盖 Python 项目,聚焦“修复 bug”这一种任务形态,无法完全代表真实软件工程的全部场景。正因如此,社区陆续推出了多语言变体、多任务形态的新基准,但无论如何演进,SWE-bench 确立的“用真实 PR 构建评测实例”这一方法论始终是它们的基石。就像米其林标准也在变,但“由真实顾客的真实体验出发”这一根本原则从未动摇。
AI 应用场景
场景一:RAG 系统的效果评估
阶段:模型评测与调优
解决的问题:RAG 系统检索出的文档是否真的有助于代码修复?传统的人工翻阅检索结果打分效率低且主观。借助 SWE-bench 实例,可以自动把“检索质量”转化为“修复通过率”——检索内容有用,Agent 修复成功率就高。这种端到端评估方式让 RAG 调优有了明确的优化目标。
具体案例:某团队开发一个代码问答 RAG 工具,他们选取 SWE-bench 中的 100 个实例,将问题描述输入 RAG 检索器,再让 Agent 基于检索结果生成修复补丁。通过对比不同检索策略下的通过率,他们发现检索器返回“相关测试文件”比返回“相关文档页面”更能提升修复成功率,于是调整了检索权重配置。
场景二:Agent 开发迭代的回归测试
阶段:模型开发与迭代
解决的问题:每次更新 Agent 的提示词或工具调用逻辑后,如何确认能力没有退化?SWE-bench 是一个天然的回归测试集:固定一组评测实例,每次改动后跑一遍通过率,分数下降就说明改动引入了问题。这避免了“凭感觉调参,上线翻车”的困境。
具体案例:一家公司的 AI 编程助手团队把 SWE-bench 的 300 个实例接入了内部 CI 系统。每次发布新版本前,自动运行评测并生成通过率报告。某次他们把 Agent 的“文件搜索工具”替换成新的语义检索工具后,发现通过率从 22% 掉到 17%,立即定位到新工具有超时问题,及时回滚修复。
场景三:代码模型发布前的能力验证
阶段:模型发布与合规
解决的问题:大模型发布前需要一个权威、中立的指标来向用户和监管方证明其代码能力。完全自建评测集既耗时又缺乏公信力。SWE-bench 作为公开基准,让不同公司、不同模型在同一组真实任务上公平比较。
具体案例:一家模型厂商在发布新版代码大模型前,在官方技术报告中披露了 SWE-bench 通过率从 18% 提升到 31%。客户看到这一指标后,决定将模型接入其内部缺陷修复流水线,用于自动生成补丁建议,由资深工程师人工确认后合入代码库。
Python 演示
"""从真实GitHub PR构建SWE-bench评测实例并评估修复是否通过。""" class SWEBenchInstance: def __init__(self, pr_number, problem, base_commit, fail_to_pass, pass_to_pass): self.pr_number = pr_number self.problem = problem self.base_commit = base_commit self.fail_to_pass = set(fail_to_pass) self.pass_to_pass = set(pass_to_pass) def is_solved(self, passed_tests): return self.fail_to_pass.issubset(passed_tests) and self.pass_to_pass.issubset(passed_tests) class SWEBenchEvaluator: def __init__(self): self.instances = [] self.solution_count = 0 def add_instance(self, instance): self.instances.append(instance) def run_one(self, instance, model_patch, run_tests): passed_tests = run_tests(instance.base_commit, model_patch) return instance.is_solved(passed_tests) def run_suite(self, model_patch, run_tests): self.solution_count = sum( 1 for inst in self.instances if self.run_one(inst, model_patch, run_tests) ) return self.solution_count / len(self.instances) def demo_run_tests(base_commit, model_patch): """模拟在某个提交上运行测试,返回通过的测试名集合。""" passed = set() if "fix" in model_patch: passed.add("test_list_handle::test_no_crash") passed.add("test_list_handle::test_original_ok") return passed if __name__ == "__main__": evaluator = SWEBenchEvaluator() instance = SWEBenchInstance( pr_number=8825, problem="列表越界访问导致崩溃,需要增加边界判断。", base_commit="a1b2c3d", fail_to_pass={"test_list_handle::test_no_crash"}, pass_to_pass={"test_list_handle::test_original_ok"}, ) evaluator.add_instance(instance) score = evaluator.run_suite("add boundary check: fix", demo_run_tests) print("评测通过率:", score) print("评测实例数:", len(evaluator.instances))
self.fail_to_pass = set(fail_to_pass)把测试名列表转成集合,方便后续做“子集”判断。return self.fail_to_pass.issubset(passed_tests) and self.pass_to_pass.issubset(passed_tests)这就是判定公式的实现:两个集合条件同时满足才返回 True。passed_tests = run_tests(instance.base_commit, model_patch)把修复补丁应用在 base_commit 对应的代码快照上运行测试,模拟真实提交验证。if "fix" in model_patch简化版模拟器:只有当模型补丁里包含 fix 相关改动时,测试才通过,用于演示而无需真实代码库。score = evaluator.run_suite("add boundary check: fix", demo_run_tests)一次性跑完所有实例,得到最终通过率。
常见误区
误区刚开始接触 SWE-bench 时,我以为是直接把 PR 的完整代码给 AI,让它照葫芦画瓢写一遍。既然题目来自真实 PR,那 PR 的 diff(修复补丁)肯定就是 agent 的输入。
正解实际上 Agent 只能看到问题描述(problem statement)和 bug 发生时的代码快照(base commit),标准修复补丁(gold patch)被严格密封,仅用于评分时做结果对比。这就像考试时考生只能看到试卷,标准答案锁在阅卷老师抽屉里。如果让 Agent 看到修复 diff,评测就变成了“抄写测试”而不是“修复测试”。
为何常见:因为“PR 数据”给人的第一印象就是“一段完整的改动记录”,容易误以为整个改动都是输入;只有理解了评测设计的公平性目标,才能分清哪些字段公开、哪些字段保密。
误区我觉得一个评测实例里 FAIL_TO_PASS 测试越多越好,这样能更全面地考察 Agent 的修复能力,测试多总比测试少更严谨。
正解测试数量不是关键,测试和 bug 的相关性才是关键。SWE-bench 要求这些测试精准命中 PR 要修复的那个问题——它们是从真实 PR 的 test_patch 中提取的,与 bug 一一对应。如果堆砌大量无关测试,反而可能引入 flaky 噪音,让评测结果不稳定。就像检查一道菜是否修好了,关键在于尝这一道菜,而不是把整本菜单都重新做一遍。
为何常见:人们习惯认为“更多的测试 = 更好的质量”,但评测基准追求的是每个测试都有明确因果指向,宁缺毋滥。
误区我以为高采样只是把测试重复运行几次,如果每次都通过,就说明测试稳定。这不过是多花一点算力的事。
正解SWE-bench 中的高采样(high sampling)远不止“多跑几遍”。它是通过多次采样排除 flaky 测试,并验证“修复前失败、修复后通过”这一状态切换的稳定性。每个实例都需要在多种条件下反复确认,这一过程成本很高,也是为什么 SWE-bench 实例数量被控制在一定规模的原因。单纯重复跑测试既不能排除环境依赖,也不足以证明测试与 bug 的相关性。
为何常见:因为“采样”这个词会让人联想到统计里的重复抽样,而忽略了它在数据筛选阶段承担的质量验证职责。
误区GitHub 上每天有那么多 PR,SWE-bench 做几百个实例是不是太少了?感觉可以轻松扩展到几万个,覆盖更多场景。
正解真实 PR 虽多,但要同时满足“已合并、明确关联 issue、包含有效 test_patch、通过高采样验证、不在训练数据泄漏范围、经人工复核”这多重条件,符合条件的比例极低。每一个合格实例的背后都是大量被淘汰的候选 PR。而且人工复核成本高,时间切分又不断压缩可选范围——这就像米其林评审不会因为全城餐厅多,就随便发星;每颗星都得经过层层实地考察。
为何常见:只看到 GitHub 的 PR 总量大,没看到从“原始数据”到“可用考题”之间极低的转化率和昂贵的质量成本。
面试题
Q1. SWE-bench 的题目素材从哪里来?
- A.虚构的编程练习题
- B.真实的GitHub合并PR← 正确答案
- C.招聘平台的简历数据
- D.开源社区的技术博客
答案:B。SWE-bench 的核心创新就是使用真实 GitHub 仓库中已合并的 PR 作为题源。虚构习题缺乏真实性,简历数据和技术博客都不包含可验证的代码修复闭环。只有真实合并 PR 才具备“问题—修复—测试”的完整链路,能支撑可靠的评测。
Q2. FAIL_TO_PASS 测试的含义是什么?
- A.修复前失败、修复后必须通过← 正确答案
- B.修复前通过、修复后仍须通过
- C.修复前后都失败、无需关注
- D.修复前后都通过、属于回归
答案:A。FAIL_TO_PASS 直译就是“从失败到通过”,它精确对应 bug 本身:修复前代码上有这个 bug,测试失败;修复后 bug 被消除,测试必须通过。B 选项描述的是 PASS_TO_PASS;C 和 D 描述的场景都不是有效的修复验收测试。
Q3. SWE-bench 为什么只选择已合并进主干的 PR?
- A.合并代表修复方案得到社区认可← 正确答案
- B.合并的PR代码量一定更加庞大
- C.合并的PR必定不包含测试代码
- D.合并的PR一定修复多个问题
答案:A。PR 被合并意味着维护者审核并接受了这次修复,相当于“标准答案”经过了人类专家验证,可靠性高。代码量大小、是否含测试、修复问题数量都与“是否合并”没有必然关系,因此不是选择依据。
Q4. SWE-bench 的一个评测实例包含哪些要素?
- A.原始问题描述的文本内容← 正确答案
- B.修复前代码仓库快照← 正确答案
- C.社交媒体的热门话题
- D.修复前后的测试运行环境← 正确答案
答案:ABD。实例的核心四要素是:问题描述(issue 原文)、代码快照(base commit 现场)、测试补丁(test_patch)、以及可复现的运行环境。社交媒体话题与评测无关,属于干扰项。环境配置是保证评测可复现性的重要组成部分。
Q5. PASS_TO_PASS 测试的主要作用是什么?
- A.防止修复过程中引入新的回归← 正确答案
- B.增加评测任务运行的时间
- C.给智能体提供额外提示信息
- D.检查提交代码的格式规范
答案:A。PASS_TO_PASS 验证的是“修复 bug 的同时没有弄坏原有功能”,它守住的是回归底线。它不提供提示、不检查格式、也不是为了拖慢评测,而是与 FAIL_TO_PASS 形成“一进一守”的双保险。
Q6. 下列哪项是 SWE-bench 防止数据泄漏的关键手段?
- A.按提交时间切分训练与评测数据← 正确答案
- B.随机打乱所有PR不做任何区分
- C.只选用热度最高的开源仓库
- D.允许智能体访问外部搜索引擎
答案:A。数据泄漏的根源是模型可能背过评测答案。按提交时间切分后,评测实例的修复提交时间晚于训练数据截止时间,模型无法提前见过答案。随机打乱反而会加剧泄漏;热度筛选不解决时间问题;允许搜索引擎更是主动泄漏。
Q7. 一个 SWE-bench 评测实例被判定通过,必须满足哪些条件?
- A.所有FAIL_TO_PASS测试全部通过← 正确答案
- B.所有PASS_TO_PASS测试保持通过← 正确答案
- C.整个仓库总测试通过率超过八成
- D.智能体成功编译代码不报语法错
答案:AB。判定公式要求两个集合条件同时成立:FAIL_TO_PASS 全部通过(bug 修好了)且 PASS_TO_PASS 全部保持(没引入回归)。总通过率超过八成或仅编译成功都不够严格,无法精确衡量这个具体 bug 是否被修复。
Q8. SWE-bench 中的 test_patch 测试补丁从哪里获取?
- A.从PR作者提交的测试代码中提取← 正确答案
- B.由评测团队事后凭空编写生成
- C.从其他不相关仓库复制拷贝
- D.由随机算法自动生成测试用例
答案:A。test_patch 来自 PR 作者在修复 bug 时配套提交的测试代码,它天然与 bug 强相关。评测团队事后编写或随机生成都会引入主观性,拷贝无关测试更无法命中具体问题。这种“原汤化原食”的做法保证了测试与修复目标精确对齐。
Q9. SWE-bench 的质量保障措施包括哪些?
- A.高采样排除不稳定偶发测试← 正确答案
- B.人工复核每个实例的合理性← 正确答案
- C.固定依赖版本与容器运行环境← 正确答案
- D.预先给智能体展示标准修复答案
答案:ABC。高采样用来排除 flaky 测试,人工复核保证实例质量,容器化环境保证可复现性,这三者共同构成质量防线。预先展示标准答案属于数据泄漏,是评测体系严防的行为,绝不属于质量保障措施。
Q10. SWE-bench 第一版聚焦评测什么类型的代码仓库?
- A.Python开源仓库← 正确答案
- B.JavaScript仓库
- C.C++仓库
- D.Rust系统仓库
答案:A。SWE-bench 第一版只聚焦 Python 开源项目,原因是 Python 生态测试框架成熟统一(如 pytest)、社区活跃且真实 PR 丰富,便于构建标准化可复现的评测流程。其他语言是后续变体(如 SWE-bench Multimodal)扩展的方向。