SWE-bench Lite Scale-20 实测报告(phase-barrier 门禁 vs 无门禁)¶
结论一句话:在官方 SWE-bench 评测容器内,同模型同预算下,加门禁的 gated 组 20/20 resolved(100%),无门禁的 baseline 组 18/20(90%);门禁累计拦截 78 次, 把 2 个 baseline 失败的实例救了回来,且没有拖累任何一个成功实例。代价是平均墙钟耗时 约 1.8 倍。n=20,只用于同条件相对对比,不构成排行榜结论。
原始数据与复算脚本都在仓库里,本文每个数字都能一条命令重算,不需要重跑 Agent。
一、实验设置¶
| 维度 | 取值 |
|---|---|
| 数据集 | SWE-bench/SWE-bench_Lite,test 分片(canonical,含 eval_script) |
| 实例数 | 20(分层抽样 + must-repo 配额:django 4 / sympy 4 / astropy 2 / matplotlib 2,其余 8 个覆盖 seaborn、flask、requests、xarray、pylint、pytest、scikit-learn、sphinx) |
| 组别 | baseline(无门禁)/ gated(AntiShortcutSkill 阶段门禁),同实例配对 |
| 模型 | deepseek-v4-flash(同一 API、同一温度与提示词) |
| 预算 | 每组每实例最多 60 轮工具调用 |
| 运行环境 | 官方镜像 swebench/sweb.eval.x86_64.*,Agent 在容器内运行;评分在宿主用官方 swebench==5.0.2 harness 跑 /eval.sh |
| 并发 | 3 |
| 运行日期 | Agent 2026-09-10;gated 组在 §4 的修复后于 2026-09-12 重跑 |
复现命令(需要 Docker、已缓存对应官方镜像、宿主评分 venv、DEEPSEEK_API_KEY):
python scripts/select_swe_tasks.py --dataset .pytest_tmp/bench_data/lite/dataset.json \
--count 20 --must-repo django/django sympy/sympy --per-repo 2 --seed 20260910 \
--out .pytest_tmp/bench_data/lite/tasks_scale20.json
python scripts/run_swebench_batch_container.py \
--tasks .pytest_tmp/bench_data/lite/tasks_scale20.json \
--dataset .pytest_tmp/bench_data/lite/dataset.json \
--grade-python .pytest_tmp/sweb_venv/Scripts/python.exe \
--results benchmarks/swebench/results/scale20_lite_container.csv \
--log-dir .pytest_tmp/bench_data/container_logs \
--modes baseline,gated --max-turns 60 --concurrency 3
二、结果¶
数据文件:benchmarks/swebench/results/scale20_lite_container.csv(40 行,note 全为 graded)。
| 组别 | n | resolved | resolve 率 | Wilson 95% 区间 | 门禁拦截 | 走到阶段 6 | 交付全绿 | 空补丁 | 平均轮数 | 平均/中位/P90 耗时 |
|---|---|---|---|---|---|---|---|---|---|---|
| baseline | 20 | 18 | 90% | [69.9%, 97.2%] | 0 | — | — | 0 | 43.1 | 262s / 256s / 576s |
| gated | 20 | 20 | 100% | [83.9%, 100.0%] | 78 | 14 | 14 | 0 | 49.8 | 462s / 349s / 927s |
「交付全绿」= State.delivery_clean():阶段 6 + 最近一次测试全绿 + 晚于最后一次源码变更。
一行复算:
python benchmarks/swebench/analyze_results.py --results benchmarks/swebench/results/scale20_lite_container.csv
baseline n= 20 resolved= 18 (90%) wilson95=[69.9%,97.2%] intercepts=0 stage6=0 clean=0 empty=0 turns=43.1 sec=262/256/576
gated n= 20 resolved= 20 (100%) wilson95=[83.9%,100.0%] intercepts=78 stage6=14 clean=14 empty=0 turns=49.8 sec=462/349/927
rescued=['matplotlib__matplotlib-22711', 'sympy__sympy-11400'] regressed=[]
三、关键发现¶
- 门禁没有降低解决率,反而把 2 个失败实例救了回来,且 0 例拖累。
配对比较:
matplotlib__matplotlib-22711、sympy__sympy-11400在 baseline 未通过, 在 gated 通过(两者都走到阶段 6 且交付全绿);没有任何实例出现反向翻转。 - 78 次拦截全部被 Agent 合规修复。 gated 组平均每实例 3.9 次拦截, 分布为 0/2/4/5/6/7 次;拦截原因集中在「未写测试就想写实现」「没跑测试就想交付」。
- 代价是耗时:平均 262s -> 462s(约 1.8x),中位 256s -> 349s(约 1.4x)。 P90 从 576s 涨到 927s。轮数只从 43.1 涨到 49.8(+16%),说明增加的主要是 「按 SOP 补证据 + 重跑测试」的墙钟时间,不是 API 轮次。
- 统计显著性:n=20 不足以下强结论。 两组 Wilson 区间有重叠(90% 的下界 69.9% 低于 100% 的上界),因此不能声称「门禁显著提升解决率」;但「不降低、且方向为正」 在 20 个配对实例上是一致的。这也是继续做 Scale-50 / Verified 复核的动机。
- 6 个 gated 实例在阶段 3/4 结束(60 轮预算耗尽),但补丁仍通过官方评测。
它们没有触发
delivery_clean:门禁没有放行交付,但评测只看补丁。 这说明「门禁拦住流程」与「官方评测判定 resolved」是两件事,报告中不应混为一谈。
四、根因分析:gated 从 65% 到 100%¶
首轮 gated 只有 13/20(65%),且失败形态高度一致:6 个实例永久卡在阶段 2,
Agent 反复重试也无法推进(本地原始数据 .pytest_tmp/bench_data/results_scale20/results.csv)。
两个根因都在门禁侧:
- 语言误判:语言探测按「标志文件先到先得」,django / sphinx 这类仓库根目录有
package.json(前端或文档工具链),于是 Python 仓库被判成javascript, 用 JS 启发式去校验.py测试 → 报「断言关键字不足(0 < 1)」。 修复:多标志命中时按源文件数消歧(跳过node_modules/.venv/build等), 无法消歧再回退原优先级(anti_shortcut/languages/__init__.py)。 - 存量测试白嫖:
validate_tests扫描整个存量仓库(几十年历史夹具), Agent 不写新测试也能「通过」。修复:新增stage2_test_scope: changed(默认), 只校验相对 HEAD 新增/修改的测试文件;非 Git 仓库或工作区干净时自动回退 (anti_shortcut/validators.py、anti_shortcut/paths.py、anti_shortcut/config.py)。
修复后同一批量重跑:6 个卡死实例 resolved 0 -> 1,gated 组 13/20 -> 20/20。
回归测试 tests/test_stage2_scope.py(13 项)用 django / sphinx 的真实目录布局复现,
并覆盖「拿存量测试蒙混」的绕过用例。
五、harness 陷阱(实测踩到,已修复)¶
这两个坑会让整批数据失真,做任何 Agent 评测都值得对照检查:
- 陈旧补丁被当作本轮结果评分。 Agent 容器内 import 失败秒退时,上一轮的
model_patch.diff还在挂载目录里,驱动会拿它当本次结果——本轮 20 行里一度有 14 行 是上一轮的假数据。修复:运行前清空同名 label 目录,并用patch_is_fresh()校验补丁 mtime 晚于本轮开始时间(scripts/run_swebench_batch_container.py)。 - 并行写坏共享依赖卷。 Docker Desktop 卷挂载下
mkdir锁不互斥, 并发pip install --target会把pb_gate_deps写坏(实测缺typing_extensions, Agent 直接 import 失败)。修复:bootstrap 改为「rm -rf-> 安装 ->import pydantic, yaml, structlog校验 -> 才落.ready」。
另外两个已修的坑:Windows 写出的 eval.sh 若带 CRLF 会让 set -e / conda activate
静默失败(grade.py 强制 LF 写入);官方 harness 的 report.json 按
run_id/model/instance 缓存,复用 run_id 会直接返回旧结论(现按任务 + 提示词 sha256 前 12 位取 run_id)。
六、Verified 分片复核¶
把已产出的补丁换到 SWE-bench/SWE-bench_Verified 分片重新评分(不重跑 Agent),
4 个实例 × 2 组 = 8 份判定:8/8 与 Lite 一致,无翻转。
数据:benchmarks/swebench/results/verified_regrade.csv。
| 实例 | baseline Lite -> Verified | gated Lite -> Verified | Verified F2P / P2P |
|---|---|---|---|
astropy__astropy-12907 |
1 -> 1 | 1 -> 1 | 2 / 13 |
astropy__astropy-14182 |
1 -> 1 | 1 -> 1 | 1 / 9 |
django__django-10914 |
1 -> 1 | 1 -> 1 | 1 / 98 |
scikit-learn__scikit-learn-10297 |
1 -> 1 | 1 -> 1 | 1 / 28 |
python benchmarks/swebench/regrade_cross_shard.py \
--results benchmarks/swebench/results/scale20_lite_container.csv \
--target-dataset .pytest_tmp/bench_data/verified/dataset.json \
--agent-runs .pytest_tmp/bench_data/agent_runs \
--grade-python .pytest_tmp/sweb_venv/Scripts/python.exe \
--out-dir .pytest_tmp/bench_data/eval_runs_verified \
--out-csv benchmarks/swebench/results/verified_regrade.csv
七、已知限制¶
- n=20,非排行榜结论;Wilson 区间有重叠,方向性结论不等于统计显著。
- 单一模型、单一框架(DeepSeek 工具循环),未验证跨模型可迁移性。
- gated 组
seconds是容器内 Agent 墙钟耗时;宿主休眠会同时拉长它与看门狗, 这类行已按container_timeout剔除后重跑,入库行note全为graded。 - 门禁的价值体现在「流程合规 + 交付前测试全绿」,官方评测只考察补丁正确性; 两者不等价(见 §三.5)。
八、下一步¶
- 扩到 Scale-50(Verified 采样 30 + 现有 20),补统计检验与被门禁救回实例的逐例分析。
- 用
benchmarks/swebench/analyze_results.py统一出表,避免手抄数字。 - 把本报告的 baseline/gated 对照纳入对外材料(README、博客、知乎 / Dev.to / HN)。