Skip to content
传衡博客
返回

【二】SWE-bench 评测与 Docker 测评环境构建

参考资料
  1. SWE-bench: Can Language Models Resolve Real-World GitHub Issues?
  2. SWE-bench Verified — Leaderboard
  3. TraceForge — GitHub

在 SWE-bench Verified 的 100 个真实 GitHub issue 上跑评测,baseline 解决率 71%(71/100)。这篇文章不讲 Agent 怎么解题,讲评测基建怎么搭:Docker 环境管理、并发 runner、调用图采集、诊断与修复的两级评测,以及 9 个 Docker 环境踩坑。

评测管道总览

一次评测从 SWE-bench 实例到最终结果,经过 5 个阶段:

阶段输入输出关键组件
环境准备instance_id可运行的 Docker 容器镜像查找 + smoke check + pip install
调用图采集failing test + tracer调用边 + 结构化错误pytest hook + sys.settrace
Agent 诊断错误信息 + 调用图 + 100 步预算patch 或 no_patchReAct 循环 + debug_subagent
Patch 验证Agent 产出的 diffpass/fail在同一容器内 re-run test
结果归档轨迹 + patch + 状态JSON manifestpreds.json + case_manifest

并发执行用 ThreadPoolExecutor。 10 个 worker 同时跑 10 个实例,每个 worker 独立持有 LLMClient 和 Docker 容器。结果写入用 threading.Lock 保护,避免 JSON 文件竞争。

Docker 环境:最多踩坑的地方

SWE-bench 为每个 instance 预构建了 Docker 镜像(sweb.eval.x86_64.{instance_id}:latest),里面包含对应版本的 Python、项目代码和依赖。但从”镜像存在”到”Agent 能在里面跑 PDB”,中间有大量细节。

镜像查找的命名兼容

SWE-bench 的镜像命名经历过一次格式变更:旧版 sweb.eval.{instance_id},新版 sweb.eval.x86_64.{instance_id}。启动容器时需要先查新格式,fallback 到旧格式。

Volume Mount 会破坏预装环境

最初用 -v {host_repo}:/testbed 把宿主机代码挂载进容器,方便 tracer 注入。但挂载后 /testbed 变成纯源码副本,丢失了镜像构建时的 pip install -e . 产物。结果 import astropy 直接失败,调用图采集拿到 0 条边。

修复: 挂载后自动执行 pip install -e /testbed,前后各一次 smoke check(pytest --version)。

环境变量最小透传

早期把宿主机的全量环境变量传进容器。结果宿主机的 HOME 覆盖了容器内的 HOME,改变了 Python 的 user-site 路径,导致容器里装好的 pytest 找不到了。

修复: Docker 环境只传必需变量:DJANGO_SETTINGS_MODULE + PYTHONPATH=/testbed/tests。不传 HOME、不传 PATH

Python 解释器版本

容器里可能有多个 Python:/opt/miniconda3/envs/testbed/bin/python(项目需要的版本)和 PATH 上的 /usr/bin/python3(系统版本)。两者版本可能不同(3.9 vs 3.11)。

修复: 优先使用 testbed 环境的解释器,按 /opt/miniconda3/envs/testbed/bin/pythonpython3python 的顺序查找。

调用图采集

在 Agent 开始诊断之前,先跑一次 failing test,采集动态调用图。调用图告诉 Agent”哪条执行路径崩溃了”和”哪些函数被调用了几次”。

pytest hook 精准注入

旧方案用 sys.settrace 覆盖整个进程,框架代码噪声超过 60%。新方案用 pytest 的 hook 系统,只在测试函数体执行期间开启 tracer:

class _TraceForgePlugin:
    @pytest.hookimpl(tryfirst=True, hookwrapper=True)
    def pytest_runtest_call(self, item):
        tracer = _TracerEngine()
        tracer.start()
        outcome = yield       # 测试函数在这里执行
        tracer.stop()
        save_edges(tracer.edges)

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_setup(self, item):
        tracer = _TracerEngine()
        tracer.start()
        outcome = yield       # setup 也 trace(防止 setup 失败的盲区)
        tracer.stop()
        save_edges(tracer.edges)benchmarks/swebench/tracer_wrapper.py

pytest_runtest_setup 是后加的。 最初只 trace call 阶段,结果 Django 实例在 setup 阶段就失败了,tracer 完全没开启,输出 0 条边。加上 setup hook 后覆盖率明显提升。

错误信息直接从 pytest 获取

旧方案从 stderr 文本解析 traceback,正则匹配不稳定。新方案在 pytest_runtest_makereport hook 里直接拿 call.excinfo(pytest 的原生异常对象),转成结构化 JSON。

评测的两级结构

Tier 1:诊断

Agent 的 PDB Debug SubAgent(第一篇) 做运行时诊断:设断点、检查变量、遍历调用栈。诊断结论是结构化的 Question/Answer/Evidence/Locations。

诊断正确率实测 80%。 10 个成功诊断的 case 中 8 个结论完全正确。诊断能力不是瓶颈。

Tier 2:修复

诊断完成后,Agent 生成 patch。修复管道经历过一次重构:

版本方案问题
v1自由文本 + regex 提取 <<<BEFORE>>>/<<<AFTER>>>解析失败率 ~15%
v2function calling: apply_fix({before, after})结构化输入,解析失败率 0%

v2 只返回修复片段(约 60 行),不返回完整文件。 这降低了 API 超时风险,也减少了 LLM 在长文件中”走神”的概率。

提交率 vs 解决率

指标说明
Submitted(有 patch)86/100Agent 在 100 步内产出了 diff
Resolved(patch 正确)71/100patch 通过了测试验证
Resolved / Submitted75.6%提交了的大部分能过
No patch13/100步数用完或 Agent 放弃

瓶颈不在诊断,在提交收敛。 13 个 no_patch 中,相当一部分是 Agent 诊断正确但因为保守不敢提交,或者在 PDB 里过度验证修复假设导致步数耗尽。

模型选择与并发策略

场景模型RPM / TPM并发 workers理由
单实例调试MiniMax-M2.560 RPM1性价比最好,快速迭代
批量评测qwen3.5-plus30000 RPM / 5M TPM10最强并发,挂钟时间从 80min 降到 10min
配额兜底GLM-4.7 / GLM-51-3阿里云限流时手动切换

不做自动模型切换。 阿里云出现小时配额限流时,先提醒用户确认再手动 unset ALIYUN_API 切到 GLM。自动轮询切换在评测中容易引入不可控变量。

结果归档体系

每次跑完必须更新三个文件:

docs/swebench-cases/{instance_id}.md — 单实例的所有运行历史、诊断分析、关键观察。

docs/swebench-cases/README.md — 总览表,一行一个实例,快速查进度。

docs/swebench-eval.md — 全局分析,系统性失败模式和改进方向。

这套体系保证每次评测的经验都沉淀下来,不会因为跑了太多次而丢失历史上下文。

失败模式与改进方向

100 题跑完后的失败模式分析:

步数耗尽(LimitsExceeded): Agent 诊断正确,但在 PDB 里做了过多验证。简单题用 10-25 步就够了,100 步预算更多是为复杂题准备的。改进方向是动态调用策略:简单题跳过 PDB 直接提交。

诊断后不提交: Agent 有正确答案但因为不确定不敢调用 apply_fix。改进方向是降低提交门控,或者在 system prompt 里强化”宁可提交一个不完美的 patch 也不要放弃”。

多文件修复不完整: Agent 只改了一个文件,但 bug 涉及两个文件的联动修改。当前 apply_fix 是单文件工具,需要扩展为多文件版本。

小结

SWE-bench 100 题评测的核心工程量不在 Agent 逻辑,在评测基建:Docker 环境的稳定性(9 个坑)、调用图的采集覆盖率、并发 runner 的线程安全、结果的结构化归档。Agent 的诊断正确率已经达到 80%,下一步的杠杆在 fix 的收敛性和提交决策的置信度。



Previous Post
【三】动态调用图的实现与压缩
Next Post
【一】Debug Agent 的设计与踩坑