Issue 生成、巧妙之处与边界
验证后的 bug 已经是合格练习题,但还缺一样东西:题面——一段像真人报的 GitHub issue。本章讲怎么用 LLM 反写 issue,然后收束全项目的精华、边界与横向对比。
1. Issue 生成:给 bug 配一段「报错描述」
1.1 要解决的小问题
SWE-agent 训练时,agent 看到的是「一段 issue 文字」,要据此定位并修 bug。但 SWE-smith 的 bug 是机器造的,没有自带 issue。所以要反过来:已知 bug 和它弄挂的测试,让 LLM 写出一段听起来像用户/开发者报的 bug 描述。
1.2 思路与输入
issue_gen/generate.py 的 IssueGen.generate_issue(:307)给模型三类材料:
- system prompt + few-shot 示范:从 SWE-bench Verified 真实 issue 里随机抽几条当范例(
get_demo_issues,:296),让生成的 issue 风格逼真。 - 失败测试的输出:从验证日志里截出测试报错(
get_test_output,:249),并用maybe_shorten(:145)把超长文本掐头去尾压进 token 预算。 - 相关测试的源码:
get_test_functions(:278)随机挑 F2P 测试的源码,帮模型写出「合理的复现步骤」。
模型产出 n_instructions 段候选 issue,存进每实例的 <instance_id>.json,最后合并回数据集成为 problem_statement 字段(:502-525)。
1.3 工程细节
- 可恢复:已生成的实例会跳过(
_should_do_instance,:230),中断后能续跑。 - 双后端:支持 litellm 直连,也支持 Portkey 网关(
PortkeyModel,:81,带指数退避重试)。 - 预 clone 防竞争:并发前先把所有需要的仓库 clone 好,因为
RepoProfile.clone不是线程安全的(run里:453-465注释明说)。
配置模板见 configs/issue_gen/ig_v2.yaml 等;get_from_tests.py/get_static.py 提供不依赖 LLM 的替代出题方式。
2. 巧妙之处(可借鉴的技术)
① 「挖空重写」造 bug 比「故意搞破坏」更高明。 让模型重新实现一个挖空的函数(LLM-rewrite,01 章 §5),产出的偏差更接近真实开发者的错误,而不是刻意的乱改。挖空靠 CodeEntity.stub(adapters/python.py:115)。
② 用「代码属性标签」把变异器和目标精准配对。 先给每个函数打 HAS_LOOP/HAS_BINARY_OP 等标签(constants.py:47),变异器声明所需标签,can_change 做门禁(procedural/base.py:34)——避免大量「想改却无处可改」的空转。
③ 验证用「对照实验」而非「绝对判定」。 不问「测试是否通 过」,而问「相对基线,哪些测试从绿变红」(get_valid_report,grading.py:40),天然排除了那些本来就失败的测试,信号干净。
④ 纯内存 difflib 生成补丁,绕开 git 子进程。 generate_patch_fast(bug_gen/utils.py:58)直接算 unified diff,procedural 这条高吞吐路径因此快很多,不必每个 bug 都 git add/diff/reset。
⑤ 「一个 bug 一个分支」。 gather.py 把每个有效 bug 推成 mirror 仓库的独立分支,加载时 git checkout <instance_id> 即还原(profiles/base.py:493)——数据集的可复现性落在 git 这个最稳的基础设施上。
⑥ 单例 profile + 双键注册表。 让几百个仓库各自只是一个三行子类,却能共享缓存与统一接口(profiles/base.py:70、:680)。
3. 边界与局限(诚实)
- 平台:强依赖 Docker,README 明说不支持 Windows/macOS,在 Ubuntu 开发测试。
- bug 的「真实性」上限:procedural bug 本质是语法层变异,可能不如真实 bug 那样涉及深层逻辑/跨模块交互;项目用 LLM-rewrite、PR-mirror、combine 来补这块,但仍是合成数据。
- 测试覆盖决定一切:被改代码若没有测试覆盖,验证阶段永远测不出来,直接被丢弃——所以高质量 bug 数量受限于上游仓库的测试质量。
- flaky 测试可能污染 F2P 判定(见 02 章 §6)。
- min_testing 是启发式:靠文件命名约定猜相关测试(
profiles/base.py:564),猜错会漏跑或误判。 - issue 由 LLM 编写:可能与真实用户报告的分布有偏差,且有成本。
4. 横向对比(同 shelf 兄弟)
- vs SWE-bench:SWE-bench 是评测基准(收集真实 PR 当测试题),SWE-smith 是数据工厂(合成无限训练题)。前者重「真实但稀缺」,后者重「合成但可规模化」,互补——SWE-smith 还直接复用了
swebench.harness的常量与评分原语(grading.py顶部 import)。 - vs SWE-agent:SWE-agent 是消费方(用 SWE-smith 数据训练/运行的 agent)。SWE-smith 产出的容器和数据集就是喂给它的。
- 设计取舍:相比「靠人工标注/挖真 issue」,SWE-smith 押注「造 bug 比找 bug 便宜,只要验证闸门够硬,合成数据的规模优势能盖过真实性损失」——5.2 万任务 + SWE-agent-LM-32B 在 SWE-bench Verified 上 +32% 的结果是其论据。
5. 全项目代码地图(总索引)
| 子系统 | 入口/核心文件 | 关键符号 |
|---|---|---|
| 全局常量与数据结构 | swesmith/constants.py | CodeEntity、CodeProperty、BugRewrite、GIT_APPLY_CMDS |
| 仓库档案 + 注册表 | swesmith/profiles/base.py、python.py | RepoProfile、Registry、registry、PythonProfile |
| 实体抽取 | swesmith/bug_gen/adapters/ | get_entities_from_file、PythonEntity |
| 造 bug:procedural | swesmith/bug_gen/procedural/ | ProceduralModifier、CommonPMs、MAP_EXT_TO_MODIFIERS |
| 造 bug:LLM | swesmith/bug_gen/llm/ | gen_bug_from_code_lm(modify)、main(rewrite) |
| 造 bug:PR mirror | swesmith/bug_gen/mirror/generate.py | recover_sweb_inst |
| 造 bug:合并 | swesmith/bug_gen/combine/ | same_file.main、same_module |
| 汇总补丁 | swesmith/bug_gen/collect_patches.py | main |
| 验证闸门 | swesmith/harness/valid.py、grading.py | run_validation、get_valid_report |
| 组装数据集 | swesmith/harness/gather.py | process_instance |
| 出题面 | swesmith/issue_gen/generate.py | IssueGen、generate_issue |
| 训练 | swesmith/train/ | traj_mgr/、run/ft_* |
| 建镜像 | swesmith/build_repo/ | create_images.py |
6. 一条端到端命令 路径(把全书串起来)
# 示意,改编自各模块 __main__ docstring —— 从健康仓库到带 issue 的数据集
# ② 造 bug(procedural)
python -m swesmith.bug_gen.procedural.generate <repo> --max_bugs 1000 -i
# 汇总成一个 JSON
python -m swesmith.bug_gen.collect_patches logs/bug_gen/<repo>
# ③ 验证:跑测试,筛出弄挂 1+ 测试的
python -m swesmith.harness.valid logs/bug_gen/<repo>_all_patches.json -w 8
# 组装:有效 bug 推成 mirror 分支 + 任务列表
python -m swesmith.harness.gather logs/run_validation/<repo>
# ④ 出题面: 给每条任务反写 issue
python swesmith/issue_gen/generate.py -d logs/task_insts/<repo>.json -c configs/issue_gen/ig_v2.yaml
读到这里,你应该能讲清 SWE-smith「是什么、怎么转、每个工位的原理」了。要深挖某一段,回对应章节的代码地图按符号名 grep 即可。