参考资料
在 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_patch | ReAct 循环 + debug_subagent |
| Patch 验证 | Agent 产出的 diff | pass/fail | 在同一容器内 re-run test |
| 结果归档 | 轨迹 + patch + 状态 | JSON manifest | preds.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/python → python3 → python 的顺序查找。
调用图采集
在 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% |
| v2 | function calling: apply_fix({before, after}) | 结构化输入,解析失败率 0% |
v2 只返回修复片段(约 60 行),不返回完整文件。 这降低了 API 超时风险,也减少了 LLM 在长文件中”走神”的概率。
提交率 vs 解决率
| 指标 | 值 | 说明 |
|---|---|---|
| Submitted(有 patch) | 86/100 | Agent 在 100 步内产出了 diff |
| Resolved(patch 正确) | 71/100 | patch 通过了测试验证 |
| Resolved / Submitted | 75.6% | 提交了的大部分能过 |
| No patch | 13/100 | 步数用完或 Agent 放弃 |
瓶颈不在诊断,在提交收敛。 13 个 no_patch 中,相当一部分是 Agent 诊断正确但因为保守不敢提交,或者在 PDB 里过度验证修复假设导致步数耗尽。
模型选择与并发策略
| 场景 | 模型 | RPM / TPM | 并发 workers | 理由 |
|---|---|---|---|---|
| 单实例调试 | MiniMax-M2.5 | 60 RPM | 1 | 性价比最好,快速迭代 |
| 批量评测 | qwen3.5-plus | 30000 RPM / 5M TPM | 10 | 最强并发,挂钟时间从 80min 降到 10min |
| 配额兜底 | GLM-4.7 / GLM-5 | 低 | 1-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 的收敛性和提交决策的置信度。