数据截至 (上游 commit 7a21e0577295)
第 4 章 · 巧妙之处、边界与代码地图
前三章讲了主线。本章收拢「值得带走的精华」、诚实的局限,以及给人/agent 用的跳转表。
4.1 巧妙之处(可借鉴的技术)
4.1.1 防数据泄漏:把 base_commit 之后的历史从仓库里剪掉
如果容器里的仓库还能看到「未来」的提交和 tag,模型 agent 就可能偷看到答案。这套清理由 git_clone_timesafe(swebench/image_builder/docker_utils.py:58-78)在镜像构建期完成(重构后它从评测时挪到了建镜像时):
git remote remove origin——断开远程,模型拿不到新提交(:69)。- 按
base_commit的时间戳,删掉所有指向更晚提交的 tag(:71)。 git reflog expire+git gc --prune=now --aggressive抹掉悬空对象(:72-73)。- 校验:统计 base 时间戳之后的提交数,若不为 0 直接
exit 1(:74-76)。
妙在哪:把「不许偷看未来」做成了构建期硬校验,而不是口头约定。
4.1.2 clean diff:跑测试前先把工作树扫干净
安装/执行步骤可能顺手改动仓库文件,导致后面 git diff 把环境改动也算进去。新版的做法简单粗暴:跑 eval.sh 之前先 git checkout -- . ; git clean -fd(run_evaluation.py:306)——把容器里的工作树强制扫回基线,之后跑出来的 diff 就只反映模型补丁带来的改动。
4.1.3 镜像复用:从「内容哈希缓存键」到「预建镜像注册表」(见第 2 章 2.3)
旧版靠「环境脚本内容的 sha256 当镜像 tag」做本机复用。2026 年中重构后,镜像按题扁平命名(sweb.eval.<arch>.<instance_id>,见 image_builder/image_spec.py:37-44),默认直接从 DockerHub 拉官方预建镜像——复用从「本机跨次跑」升级成「全网共享预建镜像」,内容寻址的复杂度随之退役。
4.1.4 多级 patch fallback(见第 2 章 2.4)
GIT_APPLY_CMDS(run_evaluation.py:54-58)从严到宽三连:git apply → git apply --reject → patch --fuzz=5。容忍模型补丁的轻微行号偏移,同时保留「全失败即判失败」的底线。
4.1.5 测试还原逻辑搬到了数据侧
旧版 eval 脚本由 harness 现场生成,还原测试时对已存在文件用 git checkout base_commit <file>、对新增文 件用 rm -f(修过 issue #518:无文件参数的 checkout 会把整个工作树 reset 掉)。2026 年中重构后 eval 脚本由数据集自带(eval_script 字段),这套区分逻辑内嵌在数据侧生成的脚本里,harness 不再现场拼装。
4.2 inference 子系统:模型怎么拿到题、怎么交补丁
虽然评测不强制用本仓库跑模型,但 inference/ 提供了完整链路:
- 构造输入:
PROMPT_FUNCTIONS(swebench/inference/make_datasets/create_instance.py:296)把 issue + 仓库代码 + 「请输出一个能git apply的补丁」拼成 prompt(如prompt_style_2,:165-190)。 - 检索:仓库往往太大塞不进上下文,
bm25_retrieval.py用 Pyserini/Lucene 建索引(make_index,:196),按 BM25 召回最相关的文件再喂给模型。 - 跑模型:
run_api.py走 OpenAI/Anthropic API(MODEL_LIMITS里登记各模型上下文上限,:32-45),run_llama.py跑本地权重;都把模型回复里的补丁抽出来(extract_diff)写成 predictions。
4.3 多语言扩展点
SWE-bench 已不止 Python。支持的语言各有专属日志解析器:c / go / java / javascript / php / python / ruby / rust(harness/log_parsers/<lang>.py)。2026 年中重构后,「安装/测试配方表」与「脚本/Dockerfile 模板」两层随现场脚本生成体系一起退役——加一门语言,现在的主战场是给它的数据集构建出镜像与 eval 脚本(数据侧),再给 harness 补一个日志解析器。
| 要补什么 | 在哪 |
|---|---|
日志解析器 MAP_REPO_TO_PARSER_<LANG> | harness/log_parsers/<lang>.py |
| 该语言数据集的镜像与 eval 脚本 | 数据侧(collect/、task/) |
4.4 边界与局限(诚实)
- 强依赖 Docker 与算力:README 建议 x86_64、≥120GB 磁盘、≥16GB 内存;ARM/Mac 需本地构建镜像(慢)。这不是轻量评测。
- 判分依赖日志格式:解析器是按框架/仓库手写的正则。测试框架升级、输出格式变了,解析可能失准(源码里多处特例注释,如
log_parsers/python.py:111、:144的 Django 特例)。 - Multimodal test 不可本地评测:被刻意私有化以防刷分,只能走 sb-cli 云端提交(
run_evaluation.py:719)。 - 「resolved」不等于「写法和人一样好」:只要 F2P/P2P 满足即算解决,不评估补丁的可读性/最优性——它测的是「修对 了吗」,不是「修得漂亮吗」。
- 数据可能随时间偏差:题来自历史 PR,新模型的训练数据可能已包含这些仓库的后续提交,存在潜在记忆/泄漏风险(这也是 4.1.1 那套构建期防护存在的原因,但只能防容器内偷看,防不了训练集污染)。
4.5 横向对比(同 shelf 视角)
SWE-bench 属于 evals-observability + coding-agents 交叉地带,与「跑模型的 agent」是上下游关系:
- vs 编码 agent(如 SWE-agent):agent 负责「生成补丁」,SWE-bench 负责「给补丁判分」。SWE-agent 正是为刷 SWE-bench 而生的兄弟项目(README News)。本仓库
inference/是一个最简 baseline 式的「生成器」。 - 判分哲学:相比「LLM 当裁判」或「文本相似度」的评测,SWE-bench 走的是**可执行裁判(真测试)**路线——客观、抗刷分,代价是工程复杂、跑得慢。
4.6 代码地图(导航索引)
| 主题 | 文件路径 | 关键符号 |
|---|---|---|
| 题目数据结构 | swebench/types.py | SWEbenchInstance, TestSpec |
| 评测常量 | swebench/harness/constants/__init__.py | FAIL_TO_PASS, TestStatus, ResolvedStatus, START_TEST_OUTPUT, FAIL_ONLY_REPOS |
| 评测顶层入口 | swebench/harness/run_evaluation.py | main, get_dataset_from_preds, run_instance, GIT_APPLY_CMDS |
| 读 TestSpec | swebench/harness/utils.py | make_test_spec, parse_eval_script, get_predictions_from_file |
| 镜像规格/命名 | swebench/image_builder/image_spec.py | ImageSpec, name, is_remote_image |
| 本地镜像构建 | swebench/image_builder/docker_build.py | build_instance_images, build_instance_image, build_image |
| 判分内核 | swebench/harness/grading.py | get_logs_eval, get_eval_tests_report, compute_fail_to_pass, get_resolution_status, get_eval_report |
| 日志解析器(按语言) | swebench/harness/log_parsers/<lang>.py | parse_log_pytest, parse_log_django, MAP_REPO_TO_PARSER_* |
| 最终汇总报告 | swebench/harness/reporting.py | make_run_report |
| 任务包格式 | swebench/task/repo.py | eval_script → eval.sh 映射 |
| 数据采集 | swebench/collect/build_dataset.py | create_instance, is_valid_pull, is_valid_instance, has_test_patch |
| inference:输入/检索/跑模型 | swebench/inference/make_datasets/create_instance.py, bm25_retrieval.py, swebench/inference/run_api.py | PROMPT_FUNCTIONS, prompt_style_2, make_index, MODEL_LIMITS |