第9章 端到端实战 — OpenHands 跑 SWE-bench Verified
完整可跑案例,用 OpenHands + Claude Sonnet 4.5 跑 SWE-bench Verified 子集,Tier 1 OpenHands SDK + Tier 2 Aider + Tier 3 Claude Code 三框架对比,失败模式分类、Cost 分析、改进思路
第9章 ⭐ 端到端实战 — OpenHands 跑 SWE-bench Verified
本章是模块十的实战压轴,也是第一梯队 4 大模块的收官实战。我们用 OpenHands + Claude Sonnet 4.5 跑通 SWE-bench Verified 10 题子集,然后用 Aider / Claude Code 重跑同样任务对比——你会切实感受到:模型差异 ~5%,scaffolding 差异 ~10%,prompt 与 cost 控制差异 ~30%。
📑 目录
- 一、实战目标
- 二、整体架构
- 三、环境准备
- 四、Tier 1 — OpenHands SDK 直跑
- 五、Tier 2 — Aider CLI 跑同题
- 六、Tier 3 — Claude Code SDK 跑同题
- 七、对比结果
- 八、失败模式分析
- 九、Cost / Reliability Dashboard
- 十、改进思路 + 自己 fork
一、实战目标
跑通三件事:
- Tier 1:OpenHands + Claude Sonnet 4.5 跑 SWE-bench Verified 10 题子集(预期 4-5 小时)
- Tier 2:用 Aider CLI 跑同样 10 题对比
- Tier 3:用 Claude Code SDK 跑同样 10 题对比
预期产物:
- Pass@1 三家对比表
- Cost / Time 三家对比表
- 失败模式 trace
- Grafana / Markdown dashboard
二、整体架构
┌──────────────────────────────────────────────────────┐
│ SWE-bench Verified 10 题子集 │
│ (django, flask, requests, sympy, pytest...) │
└────────────────────┬─────────────────────────────────┘
│
┌────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Tier 1 │ │ Tier 2 │ │ Tier 3 │
│ OpenHands │ │ Aider CLI │ │ Claude Code │
│ + Sonnet │ │ + Sonnet │ │ + Sonnet │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────┼────────────────┘
│ Trajectory
▼
┌──────────────────────┐
│ swebench evaluator │
│ (Pass / Fail 自动判)│
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Markdown dashboard │
│ + Grafana(可选) │
└──────────────────────┘
三、环境准备
3.1 系统要求
- OS:Linux(推荐 Ubuntu 22.04)/ macOS
- Docker:必须(Sandbox 用)
- Python:3.11+
- 磁盘:≥ 50GB(每个 SWE-bench task 需 docker image)
- API key:Anthropic API key(本项目用 实验室 API 中转 也可)
3.2 项目结构
mkdir code-agent-bench && cd code-agent-bench
cat > requirements.txt <<'EOF'
swebench>=2.1
openhands-ai>=0.30
aider-chat>=0.65
anthropic>=0.40
litellm>=1.50
pandas>=2.0
EOF
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
3.3 docker-compose.yml(LiteLLM proxy + 监控)
version: '3.9'
services:
litellm:
image: ghcr.io/berriai/litellm:main-latest
container_name: litellm-proxy
ports:
- "4000:4000"
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
command: --model claude-sonnet-4-5 --port 4000
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
启动:
export ANTHROPIC_API_KEY=sk-ant-...
docker compose up -d
3.4 选 SWE-bench Verified 10 题
# select_tasks.py
from datasets import load_dataset
ds = load_dataset("princeton-nlp/SWE-bench_Verified", split="test")
# 选 10 题:不同 repo、不同难度
selected = []
seen_repos = set()
for task in ds:
repo = task['repo']
if repo in seen_repos:
continue
seen_repos.add(repo)
selected.append(task['instance_id'])
if len(selected) >= 10:
break
print(selected)
# 输出例:
# ['django__django-11815', 'pytest-dev__pytest-8567',
# 'sympy__sympy-13971', 'matplotlib__matplotlib-23476', ...]
四、Tier 1 — OpenHands SDK 直跑
4.1 OpenHands 安装
# Method A: docker(推荐)
docker pull docker.all-hands.dev/all-hands-ai/openhands:latest
docker pull docker.all-hands.dev/all-hands-ai/runtime:latest
# Method B: pip(开发用)
pip install openhands-ai
4.2 跑单个任务
# tier1_openhands.py
import asyncio
from openhands.controller.agent import Agent
from openhands.core.config import AppConfig, AgentConfig, LLMConfig, SandboxConfig
from openhands.core.main import run_controller
from openhands.events.action import MessageAction
async def run_task(task_id: str, issue_text: str, repo_path: str):
config = AppConfig(
agent=AgentConfig(name='CodeActAgent'),
llm=LLMConfig(
model='claude-sonnet-4-5',
api_key=os.environ['ANTHROPIC_API_KEY'],
),
sandbox=SandboxConfig(
base_container_image='docker.all-hands.dev/all-hands-ai/runtime:latest',
workspace_mount_path=repo_path,
),
max_iterations=50,
max_budget_per_task=5.0, # USD 上限
)
initial_message = MessageAction(
content=f"修这个 issue:\n\n{issue_text}\n\n步骤:\n"
"1. grep 找相关文件\n"
"2. 读相关代码\n"
"3. 写补丁\n"
"4. 跑测试验证\n"
"5. 测试通过后,git diff 输出最终补丁"
)
state = await run_controller(config=config, initial_user_action=initial_message)
return {
'task_id': task_id,
'success': state.success,
'iterations': state.iteration_count,
'cost_usd': state.metrics.accumulated_cost,
'final_diff': state.final_diff,
}
if __name__ == '__main__':
# 跑 10 个 task
tasks = load_swebench_tasks() # 见 3.4
results = []
for task in tasks:
result = asyncio.run(run_task(
task_id=task['instance_id'],
issue_text=task['problem_statement'],
repo_path=clone_repo_at_commit(task),
))
results.append(result)
# 写到 jsonl
with open('tier1_results.jsonl', 'w') as f:
for r in results:
f.write(json.dumps(r) + '\n')
4.3 评测
# 用 swebench-cli 评测 trajectory
python -m swebench.harness.run_evaluation \
--predictions_path tier1_predictions.json \
--max_workers 4 \
--run_id tier1_test \
--dataset_name princeton-nlp/SWE-bench_Verified
输出 tier1_test_report.json,含每 task pass/fail 信息。
4.4 预期结果(基于业界数据)
| 指标 | OpenHands + Sonnet 4.5 |
|---|---|
| Pass@1 | 6-7 / 10(60-70%) |
| 平均 cost | $1.20/task |
| 平均时间 | 8-15 分钟/task |
| 平均 iterations | 18-25 |
五、Tier 2 — Aider CLI 跑同题
5.1 Aider 安装
pip install aider-chat
export ANTHROPIC_API_KEY=sk-ant-...
5.2 单 task 脚本
# tier2_aider.py
import subprocess
import os
from pathlib import Path
def run_aider_task(task, repo_path):
issue = task['problem_statement']
# 在 repo_path 内调用 aider
cmd = [
'aider',
'--model', 'claude-sonnet-4-5',
'--no-auto-commits', # 我们手动管 commit
'--message', f"""
修这个 issue:
{issue}
请:
1. 找出问题所在
2. 写补丁
3. 不需要写测试(已有)
4. 完成后说 'DONE'
""".strip(),
'--yes', # 自动接受 diff
]
start = time.time()
proc = subprocess.run(
cmd,
cwd=repo_path,
capture_output=True,
text=True,
timeout=600 # 10 分钟硬上限
)
duration = time.time() - start
# Aider 把 trace 写到 .aider.* 文件
return {
'task_id': task['instance_id'],
'success': proc.returncode == 0,
'duration_sec': duration,
'stdout': proc.stdout[-2000:], # 留尾巴
'final_diff': run_git_diff(repo_path),
}
5.3 Aider 的特殊处理
Aider 不像 OpenHands 那样有完整 SDK——主要靠 CLI。几个 tip:
- —map-tokens 4096:repo map 大小(影响 token cost)
- —no-auto-commits:让你手动控制 git
- —apply:直接应用 patch 不问
5.4 预期结果
| 指标 | Aider + Sonnet 4.5 |
|---|---|
| Pass@1 | 5-7 / 10 |
| 平均 cost | $0.80/task ⭐ 比 OpenHands 便宜 |
| 平均时间 | 5-10 分钟/task |
| 平均消息数 | 8-15 |
观察:Aider 因为 repo map 设计,token 比 OpenHands 省 30%+,单任务 cost 也低 30%+。
六、Tier 3 — Claude Code SDK 跑同题
6.1 Claude Code SDK 安装
# 安装 Claude Code CLI(2026 起 SDK 公开)
npm install -g @anthropic-ai/claude-code
# 或用 pip 版(若有)
pip install claude-code-sdk
6.2 单 task 脚本
# tier3_claude_code.py
from claude_agent_sdk import query, ClaudeAgentOptions
import asyncio
async def run_claude_code_task(task, repo_path):
issue = task['problem_statement']
options = ClaudeAgentOptions(
cwd=repo_path,
model='claude-sonnet-4-5',
permission_mode='acceptEdits',
allowed_tools=['Read', 'Edit', 'Bash', 'Grep', 'Glob'],
max_turns=50,
)
full_prompt = f"""
你是一个 Code Agent,任务是修一个 issue。
Issue:
{issue}
要求:
1. grep / read 找相关文件
2. 写补丁(用 Edit tool)
3. 跑 pytest 验证
4. 测试通过后,输出最终 diff,以 'DONE' 结束
"""
messages = []
async for msg in query(prompt=full_prompt, options=options):
messages.append(msg)
# 解析 trajectory
final_response = messages[-1]
return {
'task_id': task['instance_id'],
'success': 'DONE' in str(final_response),
'turns': len(messages),
'cost_usd': sum(m.cost for m in messages if hasattr(m, 'cost')),
'final_diff': run_git_diff(repo_path),
}
6.3 Claude Code 优势
- 本身就是 Anthropic 设计 ——对 Claude 模型最 native
- subagent 支持:可启 sub-agent(本项目用了大量 subagent 写文档)
- MCP 集成:可挂 GitHub MCP / 自家工具
6.4 预期结果
| 指标 | Claude Code + Sonnet 4.5 |
|---|---|
| Pass@1 | 7-8 / 10 ⭐ 最高 |
| 平均 cost | $1.50/task |
| 平均时间 | 6-12 分钟/task |
| 平均 turns | 12-20 |
观察:Claude Code 的 prompt + tool 设计专为 Claude 优化,通过率比 OpenHands 略高,但 cost 也略高(更大上下文 / 更多 turn)。
七、对比结果
(以下为预期数据,实际跑会有 ±15% 波动)
| 指标 | OpenHands | Aider | Claude Code |
|---|---|---|---|
| Pass@1 | 6.5/10 (65%) | 6/10 (60%) | 7.5/10 (75%) ⭐ |
| 平均 cost/task | $1.20 | $0.80 ⭐ | $1.50 |
| 平均时间/task | 12 min | 8 min | 9 min |
| 总 cost(10 题) | $12 | $8 | $15 |
| 总时间 | ~120 min | ~80 min | ~90 min |
| 易用性 | 中(SDK) | 极高(CLI) ⭐ | 高(CLI+SDK) |
| 可定制性 | 极高 ⭐ | 中 | 高 |
| Sandbox 隔离 | 强 ⭐ | 弱(本地) | 中(权限可控) |
7.1 三家定位
- OpenHands:最强 SDK / 最强 Sandbox ——研究 / 自训用
- Aider:最快 / 最省钱 / 最易用 ——日常 CLI 用
- Claude Code:最高准确率 ——重要任务用 ⭐
八、失败模式分析
跑完 10 题后,典型失败模式:
8.1 类型 1:测试找不到 / 装不上(2-3 题)
Error: pytest could not collect any tests
ImportError: No module named 'tox'
根因:repo 依赖装不全 / 特殊 fixtures 缺失。
修复:
- 给 OpenHands 加 hint: “先
pip install -e .” - 升级 docker image 到含完整依赖的版本
8.2 类型 2:改错文件(1-2 题)
agent 改了一个类似名但不相关的文件(常见于 sympy 这种数学库的同名函数)。
修复:加 grep 精确匹配 + read 时验证。
8.3 类型 3:测试 hack(警惕,1 题)
agent 改了 test 让它过(即 reward hacking)。
修复:diff 审计 — 测试改动远多于源码 → 拒绝 patch。
8.4 类型 4:死循环(0-1 题)
agent 反复改一个文件,测试反复失败。OpenHands 默认 50 step 上限触发后终止。
修复:loop 检测 + 降级模型 / 人介入。
8.5 类型 5:超 cost(0-1 题)
复杂任务 token 爆炸。$5 cap 触发。
修复:加 soft cap(到 $3 警告)+ 优化 prompt。
九、Cost / Reliability Dashboard
9.1 Markdown dashboard(简版)
# dashboard.py
import json
import pandas as pd
def load_results(path):
with open(path) as f:
return [json.loads(line) for line in f]
t1 = pd.DataFrame(load_results('tier1_results.jsonl'))
t2 = pd.DataFrame(load_results('tier2_results.jsonl'))
t3 = pd.DataFrame(load_results('tier3_results.jsonl'))
def summary(df, name):
return {
'framework': name,
'pass_rate': df['success'].mean(),
'avg_cost': df['cost_usd'].mean(),
'avg_time': df['duration_sec'].mean() / 60,
'total_cost': df['cost_usd'].sum(),
}
results = pd.DataFrame([
summary(t1, 'OpenHands'),
summary(t2, 'Aider'),
summary(t3, 'Claude Code'),
])
print(results.to_markdown(index=False))
输出例:
| framework | pass_rate | avg_cost | avg_time | total_cost |
|:------------|------------:|-----------:|-----------:|-------------:|
| OpenHands | 0.65 | 1.20 | 12 | 12.0 |
| Aider | 0.60 | 0.80 | 8 | 8.0 |
| Claude Code | 0.75 | 1.50 | 9 | 15.0 |
9.2 Grafana(可选)
跟模块六/七类似,把指标推到 Prometheus → Grafana 面板:
from prometheus_client import Counter, Histogram
PASS_COUNTER = Counter('agent_task_passes', 'Passes', ['framework'])
COST_HIST = Histogram('agent_task_cost_usd', 'Cost', ['framework'])
TIME_HIST = Histogram('agent_task_duration_seconds', 'Duration', ['framework'])
# 在每次 task 完成后
PASS_COUNTER.labels(framework='openhands').inc(int(success))
COST_HIST.labels(framework='openhands').observe(cost_usd)
TIME_HIST.labels(framework='openhands').observe(duration_sec)
Grafana 面板配置:
- pass rate over time
- cost distribution per framework
- duration heatmap
十、改进思路 + 自己 fork
跑完 baseline 后,怎么往上做改进?
10.1 加 Verifier(SWE-Gym 思路)
跑测试前用 LLM judge 预判:“这个 patch 看起来对吗?”——筛掉明显错的 candidate,降 cost。
10.2 加搜索(SWE-Search 思路)
每个 step 生成 5 个候选 action,LLM 评分,选最优 → MCTS 扩展。准确率 +5-10%,cost ×3-5。
10.3 加 Multi-agent(MAGIS 思路)
分 Manager / Coder / Reviewer / Tester 四 agent,对超复杂任务有效。但对 SWE-bench 这种”中等难度”反而 overhead 大。
10.4 加 RL fine-tune
用 SWE-Gym + GRPO 训自己的 7B-32B 模型,在内部 repo 上比 frontier LLM 强 10-30%。
10.5 加私有索引
公司内部 repo + 文档 + Wiki embedding 索引,agent 调用 → 跨 repo 知识。这是 Sourcegraph Cody 等企业产品的差异化。
10.6 改 ACI
OpenHands 的 ACI 已很好,但你可以领域定制:
- 加
run_unittest_only(file)(只跑某个 test 文件) - 加
git_blame(file, line)(看某行历史) - 加
ast_parse(file)(返回 AST)
业界实战:每加一个领域专用 tool,该领域任务 +5-10% pass rate。
🎉 恭喜完成模块十 Code Agents 教程!
你已掌握:
- ✅ Code Agent 范式跃迁与三层栈
- ✅ 8 大商业产品 + 8 大开源框架对比
- ✅ SWE-Agent ACI / OpenHands / CodeR / MAGIS / Aider repo map 等核心论文
- ✅ SWE-bench / Verified / Multimodal / Live / Multi-SWE-bench 全家桶评测
- ✅ LSP / Tree-sitter / VS Code Extension / Cursor 内核架构
- ✅ SWE-RL / SWE-Gym 训练栈
- ✅ Sandboxing / PR Review / Cost / Failure / Audit / Prompt Injection / License 生产化清单
- ✅ OpenHands + Aider + Claude Code 三框架端到端实战 + 改进思路
第一梯队 4 大模块全部完工 🏆
| 模块 | 主题 | 章节数 | 状态 |
|---|---|---|---|
| 模块七 | Agentic RL | 9 章 + 路线 | ✅ |
| 模块八 | Agent Evaluation & Benchmarks | 9 章 + 路线 | ✅ |
| 模块九 | Computer / Browser Use Agents | 9 章 + 路线 | ✅ |
| 模块十 | Code Agents | 9 章 + 路线 | ✅ |
✅ 自我检验清单
- 跑通 OpenHands + Sonnet 4.5 1 个 SWE-bench Verified 任务
- 跑通 Aider 同任务对比
- 跑通 Claude Code SDK 同任务对比
- 三框架对比表(Pass / Cost / Time)
- 至少 3 类失败模式 trace 记录
- dashboard 输出
- 思考过 1-2 个改进方向并实现一个
📚 参考资料
框架
- OpenHands — https://github.com/All-Hands-AI/OpenHands
- Aider — https://aider.chat
- Claude Code SDK — https://docs.claude.com/en/docs/claude-code/sdk
评测
- SWE-bench evaluator — https://github.com/swe-bench/SWE-bench
- swebench Python package —
pip install swebench
LLM Proxy / 监控
- LiteLLM — https://github.com/BerriAI/litellm
- Prometheus / Grafana
改进思路
- SWE-Search (arXiv 2410.20285)
- MAGIS (arXiv 2403.17927)
- SWE-RL (arXiv 2504.21798)
第一梯队 4 大模块完工 🎊。下一步 第二梯队(中型 4-6 章/模块):
- Multi-Modal Agents —— 视觉 + 语音 + 视频 agent
- Agent Safety / Red Teaming —— alignment、jailbreak、constitutional AI
- Agent Cost / Token Optimization —— prompt caching、compression、模型路由