门户首页
教学网站 · 领域基础

SWE-bench 怎么用:评测流程与本仓 S1-S7

理解 SWE-bench(SWE = Software Engineering 软件工程 + bench = benchmark 基准测试)的评测契约(F2P/P2P)后,下一步是:这条契约怎么落地到本仓? 这一页把5 步评测流程(拉 base → 跑 pre-fix → apply patch → 跑 post-fix → 判分)讲清,再讲3 层 Docker 镜像机制(base / env / instance 的内容哈希缓存),最后落到本仓 S1-S7 流水线是怎么把这个流程工程化的——S4_solve 跑 agent,S6_score 跑 F2P/P2P 评测,读完你就能"自己跑一遍 SWE-bench 评测"。

生成时间:2026-09-02 · 版本 v0.2 · 生成 Agent:MiniMax Code (LLM: MiniMax-M3) · 载体:agentsoft-research-platform teaching-web-platform

概览

5
评测步骤
3
Docker 镜像层
7
S1-S7 stage
5
agent adapter
项目说明
本卡定位SWE-bench 评测流程 · 1.0 领域基础 第 3 张
前置swe-bench-intro.html(F2P/P2P 范式) + swe-bench-data-schema.html(数据 schema)
读完会什么能讲清 SWE-bench 评测的 5 步流程 + 3 层 Docker 镜像;能读懂本仓 S1-S7 每个 stage 在做什么;能用 CLI 跑一遍评测
姊妹agent-harness-loop.html(S4_solve 的 harness 怎么写)
本仓核心模块experiment_modules/scoring/answer_evaluator/ + experiment_modules/orchestration/

§ 1 5 步评测流程

SWE-bench 评测可以抽象成 5 步——本仓 answer_evaluator 严格按这 5 步实现。

5 步流程图
┌─────────────────────────────────────────────────────────────────┐
│  Step 1: 拉 base_commit                                            │
│  →  git clone https://github.com/<repo>.git                      │
│  →  git checkout <base_commit>                                  │
│  →  状态:干净的 issue 时刻仓库代码                                │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Step 2: 跑 pre-fix 测试(不 apply model_patch)                    │
│  →  apply test_patch(让 F2P 测试在当前状态 fail)                │
│  →  pytest run(test_ids = fail_to_pass + pass_to_pass)             │
│  →  记录 pre[test_id] = pass / fail                                │
│  →  期望:fail_to_pass 的测试全 fail,pass_to_pass 的测试全 pass   │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Step 3: apply model_patch(agent 产出的 patch)                   │
│  →  git apply model_patch.diff(3 段回退:直接 apply / --reject /    │
│     patch -p1)                                                    │
│  →  如果都失败 → 判 resolve=False(agent patch 格式错)            │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Step 4: 跑 post-fix 测试(已 apply model_patch)                   │
│  →  pytest run(test_ids = fail_to_pass + pass_to_pass)             │
│  →  记录 post[test_id] = pass / fail                               │
│  →  期望:fail_to_pass 全 pass,pass_to_pass 仍全 pass              │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Step 5: 判分                                                        │
│  →  resolved = (∀F2P: pre=fail ∧ post=pass) ∧                      │
│              (∀P2P: pre=pass ∧ post=pass)                          │
│  →  写 report.json / run_report.json                                │
└─────────────────────────────────────────────────────────────────┘
flowchart TD S1["Step 1 · 拉 base_commit
git clone + checkout,得到干净的 issue 时刻仓库"] S2["Step 2 · 跑 pre-fix 测试
期望:F2P 全 fail / P2P 全 pass"] S3["Step 3 · apply model_patch
3 段回退:git apply / --reject / patch -p1"] S4["Step 4 · 跑 post-fix 测试
期望:F2P 全 pass / P2P 仍全 pass"] S5["Step 5 · 判分
resolved = F2P 全过 ∧ P2P 全过"] BAD["题目数据有误
F2P 在 pre-fix 就意外通过 → 回退检查数据"] S1 --> S2 S2 -->|pre-fix 符合预期| S3 S2 -.->|F2P 意外通过| BAD S3 --> S4 S4 --> S5 classDef bad fill:#fdecec,stroke:#d54f4f,color:#7a1f1f; class BAD bad;
图 1 · 5 步评测流程:拉 base → pre-fix → apply patch → post-fix → 判分
单实例伪代码(Python)
def run_instance(test_spec, pred, ...):
    container = build_container(test_spec, ...).start()
    write_to_container(container, "/tmp/patch.diff", pred.model_patch)

    # Step 3: 三段回退 apply patch
    applied = try_apply_patch(container, GIT_APPLY_CMDS)
    if not applied:
        return {"completed": False, "resolved": False}

    # Step 4: 跑测试
    write_to_container(container, "/eval.sh", test_spec.eval_script)
    log = exec_run_with_timeout(container, "bash /eval.sh", timeout=1800)

    # Step 5: 判分
    return grading.get_eval_report(test_spec, pred, log_path)
关键设计:测试必须在 Docker 容器里跑——每个 instance 拉 base_commit → 装依赖 → 跑 pytest,整个过程隔离、可复现、并行安全。没有容器隔离,你没法在同一个环境同时跑 300 道题(不同题要不同 base_commit + 不同 Python 版本)。

§ 2 评分公式详解

从单 instance 的 F2P/P2P 判分,到整个数据集的 %Resolved 指标——有 4 个层级。

4 层判分公式

第 1 层:单测试判定

概念判定
PASSEDpytest 报告 PASSED / XFAIL
FAILEDpytest 报告 FAILED / ERROR

第 2 层:单 instance 判定(4 个状态)

状态含义
FULL(resolved)∀F2P: pre=fail ∧ post=pass
∀P2P: pre=pass ∧ post=pass
PARTIAL0 < F2P 通过率 < 1
且 ∀P2P: still pass
NO其他情况(含 F2P 全 fail / P2P 有 fail)
FAIL_ONLY 状态特殊 repo(FAIL_ONLY_REPOS 列表)只检查 F2P

第 3 层:单 instance 评分

def get_resolution_status(test_spec, pred, log):
    # 1. 解析 pytest 日志
    test_results = parse_log(log)
    # → {test_id: PASSED / FAILED}

    # 2. 计算 F2P / P2P 状态
    f2p_passed = all(test_results[t] == "PASSED" for t in test_spec.fail_to_pass)
    p2p_passed = all(test_results[t] == "PASSED" for t in test_spec.pass_to_pass)

    # 3. 4 个状态
    if test_spec.eval_type == EvalType.FAIL_ONLY:
        # 特殊 repo:只检查 F2P
        if f2p_passed: return "FULL"
        elif any(...): return "PARTIAL"
        else: return "NO"
    else:
        # 标准 repo
        if f2p_passed and p2p_passed: return "FULL"
        elif (0 < f2p_pass_rate < 1) and p2p_passed: return "PARTIAL"
        else: return "NO"

第 4 层:整个数据集的主指标

%Resolved = count(instances where status == "FULL") / count(instances) * 100%
主指标为什么是 %Resolved(FULL):这是论文原版定义。PARTIAL 不算 resolved——要么修好(FULL),要么没修好(PARTIAL / NO)。
部分子评测还看 PARTIAL 占比(如 Lite 子集常报 "FULL: 12 / PARTIAL: 3 / NO: 5"),用于分析 agent 离"修好"还差多远。但主指标只有 %Resolved(FULL 占比)。

§ 3 Docker 3 层镜像机制(内容哈希缓存)

评测要跑大量测试,需要隔离环境。SWE-bench 用3 层 Docker 镜像构建环境,每层用内容哈希做缓存——重复 instance 跑 100 次也只构建 1 次。

3 层镜像表
镜像标签规则何时重建本仓文件
basesweb.base.<ext>.<arch>:<tag>docker_specs 变化时harness/dockerfiles/
envsweb.env.<ext>.<arch>.<sha256[:22]>:<tag>env_script_list 变化时构建脚本
instancesweb.eval.<arch>.<instance_id>:<tag>每个 instance 一份评测时构建
3 层职责(自下而上)
┌────────────────────────────────────────────────────┐
│  base 镜像(操作系统 + Python 解释器)                │
│  →  OS(Ubuntu 22.04 等)+ Python 3.10/3.11 + Conda │
│  →  内容:Dockerfile 模板 + 系统包 + pip             │
│  →  缓存键:docker_specs 哈希                        │
└────────────────────────────────────────────────────┘
                          ↓
┌────────────────────────────────────────────────────┐
│  env 镜像(拉仓库 + 装依赖)                          │
│  →  git clone <repo> → git checkout <env_commit>   │
│  →  pip install -e .(装仓库依赖)                  │
│  →  内容:完整仓库 + 已装依赖                       │
│  →  缓存键:env_script_list + repo + version 哈希   │
└────────────────────────────────────────────────────┘
                          ↓
┌────────────────────────────────────────────────────┐
│  instance 镜像(checkout base_commit + apply test)  │
│  →  在 env 之上 git checkout <base_commit>          │
│  →  apply test_patch                                  │
│  →  准备 eval.sh(跑测试的 shell 脚本)             │
│  →  内容:可立即跑 pytest 的环境                    │
│  →  缓存键:base_commit + test_patch 哈希           │
└────────────────────────────────────────────────────┘
flowchart TB B["sweb.base 镜像
基础 OS + Python + Conda
缓存键 = docker_specs 哈希"] E["sweb.env 镜像
拉仓库 + 装依赖(pip install -e .)
缓存键 = 环境哈希(env_script_list + repo + version)"] I["sweb.eval 镜像(instance 级)
checkout base_commit + apply test_patch + 备 eval.sh
缓存键 = base_commit + 补丁哈希"] HIT["内容哈希命中即跳过重建
300 道 Lite 仅 ~12 个 env 镜像"] B --> E E --> I E -.-> HIT I -.-> HIT
图 2 · Docker 3 层镜像:base → env → instance,内容哈希缓存命中即跳过重建
3 段回退 apply patch(为什么需要 3 段)
try:
    git apply /tmp/patch.diff
    return True
except:
    try:
        git apply --reject /tmp/patch.diff
        return True
    except:
        try:
            patch -p1 < /tmp/patch.diff
            return True
        except:
            return False
为什么 3 层:① base 镜像 = 系统级,跨 instance 共享(一个 Python 版本一个 base)② env 镜像 = 仓库级,跨 instance 共享(django/django 所有 instance 共享一个 env)③ instance 镜像 = 评测级,每 instance 一份(base_commit + test_patch 决定)。
缓存命中效果:300 道 Lite 任务实际只构建 ~12 个 env(每个 repo 1 个)+ 300 个 instance。首次构建 ~30 分钟,后续 instance 增量 ~30 秒。

§ 4 本仓 S1-S7 pipeline:评测流程的工程化

本仓把 SWE-bench 5 步评测流程工程化为 7 个 stage(S1-S7),用 experiment_modules/orchestration/ 统一调度。

7 个 stage 与 5 步流程的对应
Stage职责对应 SWE-bench 5 步本仓模块
S1_build出题:拉取 instance 数据Step 0(准备)stages/s1_build.py
S2_prepare环境:拉 Docker 镜像(env 层)Step 0(镜像准备)stages/s2_env.py
S3_baseline空 patch 基线:跑一次 default patch 确认环境能跑通Step 2 的预演stages/s3_baseline.py
S4_solve作答:跑 agent 产 model_patch—(不是 SWE-bench 原生步骤)stages/s4_solve.py + solving/
S5_patch从 trajectory 抽 model_patchStep 3 前置stages/s5_patch.py
S6_score评测:跑 F2P/P2P 判分Step 1-5 全套stages/s6_score.py + scoring/answer_evaluator/
S7_record写 result.json + experiments.dbStep 5 后置stages/s7_record.py
S1-S7 流水线时间线(典型实例)
S1 (0.1s)  →  S2 (17s)  →  S3 (5s)  →  S4 (420s)  →  S5 (0.01s)  →  S6 (162s)  →  S7 (0.1s)
出题         拉镜像       跑基线     跑 agent     抽 patch      跑 F2P/P2P    写库
                                            (model 输出)                (F2P/P2P)
                                            
                                    ─────── 不是 SWE-bench 原生 ────────
                                            
───────────────────────────────────── SWE-bench 5 步在这里 ────────────
                                            Step 1-2    Step 3    Step 4-5
                                            
合计 ~10 分钟/instance(Lite 子集 300 题 ≈ 50 小时,但 S4/S6 可并行多 instance)
flowchart LR S1["S1_build 出题
0.1s"] --> S2["S2_prepare 拉镜像
17s"] S2 --> S3["S3_baseline 跑基线
5s"] S3 --> S4["S4_solve 跑 agent
420s · 最贵"] S4 --> S5["S5_patch 抽 patch
0.01s"] S5 --> S6["S6_score 跑 F2P/P2P
162s · 次贵"] S6 --> S7["S7_record 写库
0.1s"] classDef hot fill:#fdecec,stroke:#d54f4f,color:#7a1f1f; class S4,S6 hot;
图 3 · 本仓 S1-S7 流水线耗时分布:S4(agent 作答)与 S6(F2P/P2P 评测)占绝对大头
S4_solve 不是 SWE-bench 原生步骤——这是 harness 与 SWE-bench 的分界:SWE-bench 评测的"输入"是 model_patch,"输出"是 resolved 布尔。本仓的 S4_solve 是"生产"这个 model_patch 的环节(agent 跑出 patch),不在 SWE-bench 评测流程里。S4 之前的阶段(S1-S3)准备环境、S4 跑 agent、S5-S7 评测并记录——这才是完整的"agent + 评测"流水线。

§ 5 agent_runtime 5 种 adapter(S4_solve 的可选选手)

S4_solve 阶段可以选不同 agent 跑——本仓 experiment_modules/solving/agent_runtime/ 提供 5 种 adapter,按需选。

5 种 adapter 对比
Adapter运行方式适合场景CLI 命令
kimi-agent调用 Kimi CLI(多轮工具调用)云端强模型 + 标准 tool_callkimi --yolo -p "<prompt>"
qwen-agent调用 Qwen CLI(多轮工具调用)云端强模型 + 标准 tool_callqwen --yolo -p "<prompt>"
mimo-agent调用 MiMo CLI(多轮工具调用)云端强模型 + 标准 tool_callmimo --yolo -p "<prompt>"
opencode-agent调用 OpenCode CLI(多轮工具调用)云端强模型 + 标准 tool_callopencode -p "<prompt>"
ollama-*(3 个变体)调本地 Ollama(无 tools 字段)本地弱模型 + 纯文本 bash 协议本地 HTTP 调 Ollama API(Application Programming Interface,应用程序接口)
注册表(registry.py)
# experiment_modules/solving/agent_runtime/registry.py
RUNNERS = {
    "kimi-agent":        KimiAgentRunner,         # 云端 + tool_call
    "kimi-fast":         KimiOneShotRunner,       # 云端 one-shot
    "qwen-agent":        QwenAgentRunner,         # 云端 + tool_call
    "qwen-one-shot":     QwenOneShotRunner,       # 云端 one-shot
    "mimo-agent":        MiMoAgentRunner,         # 云端 + tool_call
    "opencode-agent":    OpenCodeAgentRunner,     # 云端 + tool_call
    "codebuddy-agent":   CodeBuddyAgentRunner,    # 云端 + tool_call
    "ollama-one-shot":   OllamaOneShotRunner,     # 本地 one-shot
    "ollama-pipeline":   OllamaPipelineRunner,    # 本地多候选
    "ollama-shell":      OllamaShellRunner,       # 本地 + 纯文本 bash
    "replay-agent":      ReplayAgentRunner,       # 重放历史轨迹
}
选 adapter 的实操心法:① 跑快速验证用 kimi-fast / qwen-one-shot(one-shot 模式,不调工具,快)② 跑真实 SWE-bench 用 kimi-agent / qwen-agent(标准 tool_call 循环)③ 本地弱模型调试用 ollama-shell(纯文本 bash 协议)④ 重放历史用 replay-agent(不真调 API)。

§ 6 完整实战示例:跑一次 Lite 评测

从 CLI 命令到结果文件——一次 Lite 子集评测的完整流程。

前置准备
# 1. 确保 SWE-bench Lite 数据集已下载
ls -la swe_bench_warehouse/raw/swe-bench-lite.jsonl
# -rw-r--r-- 1 user user 50M Sep  2 12:00 swe-bench-lite.jsonl

# 2. 确认 API key 已设
export KIMI_API_KEY="sk-..."
# 或 OPENAI_API_KEY(如果用 openai 兼容的云端 API)

# 3. 确认 Docker 可用
docker ps
单次评测命令(推荐起点)
python -m answer_evaluator.harness.run_evaluation \
    --dataset_name princeton-nlp/SWE-bench_Lite \
    --predictions_path ./output/predictions.jsonl \
    --max_workers 4 \
    --run_id my-lite-run \
    --timeout 1800 \
    --cache_level env      \
    --clean false         \
    --namespace swebench
完整参数说明
参数说明典型值
--dataset_name数据集标识(HuggingFace 名)princeton-nlp/SWE-bench_Lite
--predictions_path预测文件路径(含 model_patch)./output/preds.jsonl
--max_workers并行数4-8(推荐 0.75 × CPU 数)
--run_id运行 ID(用于产物目录)my-lite-run-20260902
--timeout单 instance 测试超时(秒)1800(30 分钟)
--cache_levelDocker 缓存层(none/base/env/instance)env(推荐)
--namespace远端镜像命名空间("" = 本地 build)swebench(官方远端镜像)
--clean评测后清理容器false(保留以便 debug)
预测文件格式(predictions.jsonl)
# predictions.jsonl 格式(SWE-agent / Kimi / 本仓 orchestrator 都用此格式)
{"instance_id": "astropy__astropy-12907", "model_name_or_path": "kimi-k2-0905", "model_patch": "diff --git a/..."}
{"instance_id": "django__django-10914", "model_name_or_path": "kimi-k2-0905", "model_patch": "diff --git a/..."}
...
(每行一条,含 instance_id + model_name + model_patch)
结果文件(运行后生成)
output/my-lite-run-20260902/
├── report.json                    # 单 instance 报告(每个 instance 一行)
├── run_report.json                # 汇总报告(%Resolved 等主指标)
├── evaluation_results/
│   ├── astropy__astropy-12907.json   # 单 instance 详细结果
│   ├── django__django-10914.json
│   └── ...
└── s4_worker.log                  # agent 跑题日志(如果有)
典型 run_report.json 结构
{
  "instance_id": null,             // 汇总报告 instance_id 为 null
  "run_id": "my-lite-run-20260902",
  "model": "kimi-k2-0905",
  "dataset": "princeton-nlp/SWE-bench_Lite",
  "split": "test",
  "resolved": true,                // 整个 run 是否跑成功
  "resolved_pct": 23.33,          // ★ 主指标:%Resolved
  "outcome": "resolved",           // "resolved" / "partial" / "no"
  "soft_failed_count": 2,
  "killed_by_timeout_count": 1,
  "adapter_attempts": [...],
  "stages": ["S1_build", "S2_prepare", "S4_solve", "S5_patch", "S6_score", "S7_record"],
  "stage_timings": {
    "S1_build": 0.1, "S2_prepare": 17.2,
    "S4_solve": 420.5,             // ★ 420s ≈ 7 分钟
    "S6_score": 162.3             // ★ 162s ≈ 2.7 分钟
  },
  "generated_at": "2026-09-02T19:30:00+08:00"
}
典型 %Resolved 数字(2024-2025):① 强模型(GPT-4 / Claude Sonnet 4)配标准 tool_call:20-50%② 强模型 one-shot:5-15%③ 本地弱模型(27B coding):< 5%(需要 ollama-shell 等效实现才能跑)。
看到 resolved_pct: 23.33 不必惊讶——SWE-bench Lite 23% 已经是接近 SOTA的水平。

§ 7 资源与硬件需求

跑一次 Lite 评测的最小配置
资源最低推荐
磁盘120 GB200 GB(含镜像缓存)
内存16 GB32 GB
CPU8 核16 核(max_workers 推荐 0.75 × CPU)
网络能拉 Docker 镜像稳定上行(拉镜像 1-2 GB)
架构x86_64x86_64(Apple Silicon 需本地 build)
Apple Silicon(ARM)特别注意
踩坑提醒:本仓 orchestrator 对空 namespace会兜底覆写为 swebench,实际走"拉官方 amd64 镜像 + Docker Desktop Rosetta 2 转译"。要走本地 build(--namespace "")需先处理该覆写逻辑,且部分 repo 的 docker_specs 未覆盖 arm64 依赖。

引用与配套资料

来源链接 / 路径说明
本仓核心模块experiment_modules/scoring/answer_evaluator/评测 harness(来自 SWE-bench v4.1.0)
本仓核心模块experiment_modules/orchestration/S1-S7 编排器
本仓核心模块experiment_modules/solving/agent_runtime/5 种 agent adapter
本仓姊妹讲义swe-bench-intro.html背景与任务定义
本仓姊妹讲义swe-bench-data-schema.html数据 schema
本仓姊妹讲义agent-harness-loop.htmlS4_solve 的 harness 怎么写
本仓 wikiwiki/09-swe-bench.mdanswer_evaluator 详解
本仓 wikiwiki/50-swe-bench-paper.md论文 wiki 索引
上游 SWE-benchgithub.com/SWE-bench/SWE-bench官方评测工具
Lite 论文引用arXiv:2310.06770Jimenez et al. ICLR 2024