跳到主要内容

SWE-smith — 架构与原理

30 秒导读: SWE-smith 是一个「软件工程训练数据工厂」。给它一个 GitHub 仓库,它能在这个仓库里自动制造海量 bug(改坏代码)、自动验证哪些 bug 真的弄坏了测试、再为每个 bug 反写一段 GitHub issue——最终产出 SWE-bench 风格的任务,用来训练能修 bug 的 AI agent(SWE-agent)。论文 NeurIPS 2025 Spotlight,公开数据集有 5.2 万个任务。

1. 这是什么(零基础也能懂)

一句话定义: SWE-smith 是一套把「正常仓库」批量加工成「带 bug 的编程练习题」的工具链。

它解决谁的什么问题。 要训练一个会修 bug 的 AI agent,你需要大量「这里有个 bug + 这是它的 issue 描述 + 这是会失败的测试」的样本。这种数据真实世界里很稀缺:真 PR 数量有限、收集成本高、还很难复现环境。SWE-smith 反过来想:既然真 bug 难找,那就自己造——拿一个能跑测试的健康仓库,故意把代码改坏,只要它弄挂了原本通过的测试,就是一道合格的练习题。

它能做什么:

  • 把任意 GitHub 仓库变成可复现的执行环境(Docker 镜像)。
  • 在该仓库里用 4 种策略无限量生成 bug patch。
  • 自动验证:跑测试,只保留「让 1+ 个原本通过的测试变红」的 bug。
  • 为每个保留下来的 bug 用 LLM 反写一段 GitHub issue 文本。
  • 打包成 SWE-bench 风格数据集,直接喂给 SWE-agent 训练。

用起来什么样。 加载已发布的数据集,每条任务都能拿到一个初始化好的 Docker 容器:

# 示意,改编自 README
from swesmith.profiles import registry
from datasets import load_dataset

ds = load_dataset("SWE-bench/SWE-smith", split="train") # 5.2 万条任务
for task in ds:
rp = registry.get_from_inst(task) # 拿到这条任务所属仓库的「档案」(RepoProfile)
container = rp.get_container(task) # 返回一个已 checkout 到 bug 分支的 Docker 容器
# 接下来:让 agent 在容器里读 issue、改代码、跑测试……

一句话直觉/类比。 把它想成**「考试出题机」:健康仓库是「标准答案版试卷」,SWE-smith 把答案涂掉几处(造 bug),然后亲自做一遍**(跑测试),凡是涂改后真的导致「原本能做对的题现在做错了」的,就收进题库,并附上一段题面(issue)。AI agent 的任务就是「把试卷改回能全做对」。

2. 顶层全景(它大概怎么转)

整条流水线是一条单向传送带,五个工位首尾相接。怎么读下面这张图:从上到下是数据流向,每个工位吃上一个工位的产物。

健康仓库 (GitHub repo @ 某 commit)


┌─────────────────────┐
│ ① 建环境 build_repo │ 把仓库 + 依赖装进 Docker 镜像,镜像里测试能跑通
└─────────────────────┘
│ 可复现的执行环境

┌─────────────────────┐
│ ② 造 bug bug_gen │ 4 种策略改坏代码 → 一堆 .diff 补丁(此刻还不知道好坏)
└─────────────────────┘
│ 候选 bug patches

┌─────────────────────┐
│ ③ 验证 harness │ 在容器里跑测试:对比改前/改后,挑出「弄挂 1+ 测试」的
└─────────────────────┘
│ 有效 bug(带 FAIL_TO_PASS / PASS_TO_PASS 清单)

┌─────────────────────┐
│ ④ 出题面 issue_gen │ LLM 看着 bug + 失败测试,反写一段 GitHub issue
└─────────────────────┘


SWE-bench 风格数据集 → ⑤ 训练 SWE-agent (train/)

各工位一句话职责:

工位干什么关键模块
① 建环境仓库+依赖打成 Docker 镜像,测试可跑swesmith/build_repo/profiles/*.build_image
② 造 bug4 种策略生成候选 bug patchswesmith/bug_gen/
③ 验证跑测试、对比 pass/fail、筛有效 bug、入库swesmith/harness/valid.pygrading.pygather.py
④ 出题面LLM 给每个 bug 反写 issue 文本swesmith/issue_gen/generate.py
⑤ 训练用产出的轨迹/数据微调模型swesmith/train/
贯穿全局仓库「档案」:装/测/解析日志的规格swesmith/profiles/

主线走一遍(高层,不进代码): 给定 owner/repo@commit → 先 create_mirror 在 swesmith 组织下建一份冻结快照、build_image 装环境 → bug_gen 抽出仓库里所有函数/类,逐个改坏,落一堆 bug__*.diffcollect_patches 把补丁汇总成一个 JSON → harness.valid 在容器里逐个 apply、跑测试、和「未改前」对比,写出每个 bug 的 FAIL_TO_PASS 清单 → harness.gather 把验证通过的 bug 推成 mirror 仓库上的一个个分支,拼成数据集 → issue_gen 给每条反写 issue → 数据集发到 HuggingFace,供训练。

两个核心数据结构(贯穿全程,先记住):

  • CodeEntity(swesmith/constants.py:88)——一个被抽出来的「函数/类」,带文件路径、起止行、AST 节点、以及一组代码属性标签(有没有循环、有没有二元运算……)。造 bug 就是改它。
  • RepoProfile(swesmith/profiles/base.py:80)——一个仓库的「档案」:怎么 clone、怎么装、用什么命令跑测试、怎么解析测试日志。整条流水线都靠它把语言差异抹平。

3. 阅读地图(建议顺序)

这是个多子系统项目,按下面顺序读最顺:

  1. 01-bug-generation.md — 项目的灵魂:4 种造 bug 策略。先读这个,你就懂「数据从哪来」。重点是 procedural(基于 LibCST/tree-sitter 的确定性变异)和 LLM-rewrite(挖空让模型重写)。
  2. 02-validation-harness.md — 造出来的 bug 怎么被「筛真」:跑测试 + diff pass/fail 状态。理解 FAIL_TO_PASS 这个核心信号。
  3. 03-profiles-and-entities.md — 支撑层:RepoProfile 单例注册表 + tree-sitter/AST 实体抽取,怎么让一套代码吃下 11 种语言。
  4. 04-issue-gen-and-cleverness.md — 收尾:LLM 反写 issue,以及全项目的巧妙之处、边界、横向对比、完整代码地图。

如果你只想快速判断「这项目跟我的任务相关吗」:看完本页的 §1、§2 即可。要动手改造 bug 生成 → 跳 01;要复现/调验证 → 跳 02。