APEX-SWE 深度解剖:50 个真实软件工程任务的评测基准——从源码到设计决策
深入 APEX-SWE 评测框架的源码级分析:25 个多服务集成任务 + 25 个生产故障调试任务,Docker Compose 编排、MCP 工具服务、两套完全不同的 Agent 交互模式、F2P/P2P 评分机制,以及与 APEX-Agents/SWE-bench 的关键差异
引言
APEX-SWE(arXiv 2601.08806)是 Mercor 发布的软件工程 Agent 评测基准,与 APEX-Agents 构成”双子星”体系。如果说 APEX-Agents 评测的是”AI 能不能当投行分析师”,APEX-SWE 评测的是”AI 能不能当软件工程师”。
本报告基于 HuggingFace 数据集(mercor/APEX-SWE,2.08 GB)和 GitHub 评测框架(Mercor-Intelligence/apex-swe)的完整源码分析,逐层拆解其架构。
第一章 · 数据集全景
1.1 基本数据
| 维度 | 值 |
|---|---|
| 总任务数 | 50 |
| 集成任务(Integration) | 25 |
| 可观测性任务(Observability) | 25 |
| 数据集大小 | 2.08 GB |
| 许可证 | CC-BY 4.0(仅限评测,禁止训练) |
| 评测框架 | github.com/Mercor-Intelligence/apex-swe |
| Leaderboard | mercor.com/apex/apex-swe-leaderboard/ |
1.2 两大任务类型
APEX-SWE 的核心设计是将软件工程能力分为两个正交维度:
Integration(集成):Agent 面对一个多服务环境(LocalStack、Plane、Zammad、EspoCRM、Medusa、MailHog、Mattermost),需要理解服务间的关系、编写代码实现跨服务数据编排。这考察的是”从零构建”的能力。
Observability(可观测性):Agent 面对一个有 Bug 的真实开源项目(含 Grafana + Loki + Mattermost + Plane 的完整可观测性栈),需要通过日志、团队讨论、Issue 追踪来诊断并修复 Bug。这考察的是”诊断修复”的能力。
| 对比 | Integration | Observability |
|---|---|---|
| 核心能力 | 多服务 API 编排 | 生产故障诊断 + Bug 修复 |
| 环境 | 运行中的真实服务(LocalStack/Zammad/…) | 有 Bug 的开源代码库 + 可观测性栈 |
| Agent 输出 | Python 脚本(/app/solution.py) | Git patch(代码修改) |
| 评分方式 | Pytest 三维评分(正确性/功能性/健壮性) | F2P/P2P(Fail-to-Pass + Pass-to-Pass) |
| Agent 框架 | 自研 Harness(multi_step_runner.py) | Inspect AI(inspect_eval) |
| 交互方式 | XML + keystrokes 格式 | Function Calling(原生工具调用) |
| 任务来源 | 人工设计的集成场景 | 真实开源项目的真实 Bug |
1.3 Leaderboard
| 排名 | 模型 | 总 Pass@1 | Integration | Observability |
|---|---|---|---|---|
| 1 | GPT 5.3 Codex (High) | 41.5% ± 6.3% | — | 33.3% |
| 2 | Opus 4.7 (Max) | 41.3% ± 6.3% | 52.0% | 30.7% |
| 3 | Opus 4.6 (High) | 40.5% ± 6.3% | — | 31.7% |
| 4 | Opus 4.5 (High) | 38.7% ± 6.3% | 50.7% | — |
| 5 | GPT 5.4 (High) | 36.5% ± 6.3% | 50.7% | — |
关键发现:没有模型能”通吃”两类任务——Integration 榜首和 Observability 榜首是不同的模型,说明这两类能力有本质差异。
第二章 · Integration 任务架构
2.1 任务目录结构
每个 Integration 任务是一个完整的 Docker Compose 项目:
<task-id>/
├── task.yaml # 指令、超时、测试脚本引用
├── docker-compose.yaml # 服务编排(LocalStack + Plane + Zammad + ...)
├── Dockerfile # 客户端容器(Agent 运行环境)
├── docker-entrypoint.sh # 容器初始化(PostgreSQL、环境变量)
├── data/
│ ├── issues.json # Plane 看板(主任务 + 干扰项)
│ ├── connection-info.md # 所有服务凭据和连接字符串
│ ├── init-aws.sh # LocalStack 引导(S3 桶、SQS 队列、DynamoDB 表)
│ └── tool_code_api_docs/ # 每个服务的 API 文档
├── rubric/
│ └── rubric.json # 评分标准(正确性/功能性/健壮性)
├── tests/
│ ├── test_outputs.py # Pytest 测试用例
│ └── setup-uv-pytest.sh # 测试环境安装
└── solution.py # 参考解决方案(不展示给 Agent)
2.2 服务生态
| 服务 | 角色 | Docker 镜像 |
|---|---|---|
| PostgreSQL | 关系数据库(容器内运行) | — |
| LocalStack | AWS 服务模拟(S3/SQS/DynamoDB/IAM/Step Functions) | localstack |
| Plane | 项目管理看板(issues、迭代、模块) | 自建 ECR 镜像 |
| Zammad | 工单/客服系统(工单、Webhook、SLA) | 自建 ECR 镜像 |
| EspoCRM | CRM 系统(联系人、账户、营销活动) | 自建 ECR 镜像 |
| Medusa | 电商后端(产品、订单、购物车) | 自建 ECR 镜像 |
| MailHog | SMTP 邮件捕获 | mailhog |
| Mattermost | 团队消息平台 | 自建 ECR 镜像 |
所有服务镜像托管在 AWS ECR public.ecr.aws/k4t1e3r5/apex-code 仓库下。
2.3 干扰项设计
data/issues.json 中,Plane 看板会包含一个主任务 issue和多个干扰 issue——模拟真实项目看板上充满无关任务的场景。Agent 必须识别出哪个才是自己需要解决的。
2.4 MCP 服务器(Integration)
Integration 任务的 MCP 服务器全部基于 TypeScript(不是 APEX-Agents 的 Python FastMCP):
| MCP Server | 语言 | 工具数 |
|---|---|---|
| Plane | TypeScript | 46+ |
| Zammad | Python(FastMCP) | 20+(含 search/get/create/update/add_article/tags 等) |
| EspoCRM | TypeScript | — |
| Medusa | TypeScript | — |
| Mattermost | TypeScript | — |
Zammad 是唯一用 Python 写的 MCP Server。从源码看,它基于 zammad_py 库封装了完整的工单 CRUD + 用户/组织查询 + 附件下载 + 标签管理功能。
第三章 · Observability 任务架构
3.1 任务目录结构
<task-name>/
├── task.yaml # 任务配置
├── compose.yaml # Docker Compose(Grafana + Loki + Mattermost + Plane + App)
├── Dockerfile # 容器构建
├── problem_statement.md # Bug 描述(给 Agent 看)
├── prompt_statement.md # 扩展上下文
├── interface.md # 接口规格
├── golden.patch # 参考修复(Agent 看不到)
├── test.patch # 需要通过的失败测试
├── test_metadata.json # 测试元数据(F2P/P2P)
├── requirements.json # 修复需求清单
├── repo/ # 含 Bug 的真实开源项目完整克隆
├── data/
│ ├── loki/ # 预导出的应用日志
│ ├── mattermost/ # 导出的团队聊天记录
│ └── plane/ # Issue + PR 快照
└── observability/ # Grafana + Loki + Promtail 配置
3.2 任务来源:真实开源项目的真实 Bug
| 项目 | 语言 | 领域 |
|---|---|---|
| 0xPolygon/bor | Go | 区块链 |
| ChainSafe/gossamer | Go | 区块链 |
| containers/podman-compose | Python | 容器编排 |
| ethereum-optimism/op-geth | Go | 区块链 |
| git-bug/git-bug | Go | 开发工具 |
| paperless-ngx/paperless-ngx | Python | 文档管理 |
每个任务对应一个真实的 GitHub Issue + PR,Bug 是真实的,修复是真实的。
3.3 可观测性栈
| 服务 | 作用 |
|---|---|
| Grafana | 仪表板可视化(admin/admin) |
| Loki | 日志聚合(LogQL 查询) |
| Promtail | 日志收集器(将 repo 日志发送到 Loki) |
| Mattermost | 团队讨论上下文(关于 Bug 的对话) |
| Plane | Issue 和 PR 上下文 |
3.4 MCP 服务器(Observability)
Observability 的 MCP 服务器通过 JSON-RPC over stdin/stdout 交互:
| MCP Server | 核心工具 |
|---|---|
| Grafana-Loki | query_loki(LogQL)、get_loki_labels、get_loki_label_values、get_datasources |
| Mattermost | mattermost_channels、mattermost_fetch(推荐)、mattermost_search |
| Plane | get_projects、list_issues、search_issues、get_issue_comments |
Grafana-Loki MCP Server 基于 Python FastMCP,支持 Grafana 相对时间格式(now-1h)和 LogQL 全部语法。
第四章 · 两套完全不同的 Agent 交互模式
这是 APEX-SWE 最有趣的设计——两种任务使用完全不同的 Agent 框架和交互协议。
4.1 Integration:自研 Harness + XML keystrokes
框架:multi_step_runner.py——自研的多步交互循环。
System Prompt 要求 Agent 输出 XML 结构:
<response>
<analysis>分析当前状态</analysis>
<plan>下一步计划</plan>
<commands>
<keystrokes duration="0.1">ls -la</keystrokes>
<keystrokes duration="0.1">cd /app && find . -name '*.py'</keystrokes>
</commands>
<task_complete>false</task_complete>
</response>
工具:只有 3 个——terminal(tmux 会话内执行命令)、file(8 种文件操作)、todo(可选的任务管理)。
终止条件:<task_complete>true</task_complete> / 超时 / 达到 max_steps / token 接近上限(90%)。
关键约束:严禁 heredoc 语法(cat << EOF)——因为它会导致 tmux 终端挂起。推荐用 python3 -c、printf、echo、tee、sed 替代。
4.2 Observability:Inspect AI + Function Calling
框架:UK AI Safety Institute 的 inspect_ai 库——标准的 react() Agent。
System Prompt(324 行)定义了完整的 Observability 工作流:
- 查询 Loki 日志获取错误堆栈
- 搜索 Mattermost 获取团队讨论上下文
- 查看 Plane issues 获取 PR 信息
- 创建计划(
update_plan) - 搜索代码(
search_files) - 读取代码(
read_file) - 应用修复(
apply_patch) - 提交(
submit)
工具:5 个标准 Function Calling 工具——bash、apply_patch、read_file、search_files、update_plan。
MCP 交互:Agent 通过 bash 工具执行 JSON-RPC 命令与 MCP Server 通信:
# 查询 Loki 日志
{
echo '{"jsonrpc":"2.0","id":1,"method":"initialize",...}';
echo '{"jsonrpc":"2.0","method":"notifications/initialized",...}';
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"query_loki",...}}';
} | mcp-loki
4.3 为什么用两套不同的框架
| 维度 | Integration(自研 Harness) | Observability(Inspect AI) |
|---|---|---|
| 交互粒度 | 终端命令级(keystrokes) | 工具调用级(Function Calling) |
| 环境持久性 | 有状态的 tmux 会话 | 每次工具调用独立 |
| 适合场景 | 需要长时间交互的多服务编排 | 需要精确代码修改的 Bug 修复 |
| 评分需求 | 需要检查运行中服务的状态 | 需要对比 git diff |
| 社区兼容性 | Mercor 自研,不兼容其他框架 | 兼容 SWE-bench 生态 |
第五章 · 评分机制
5.1 Integration:Pytest 三维评分
评分由 TaskEvaluator 执行(源码 evaluator.py),流程:
- 在 Docker 容器内查找测试脚本(
run-tests.sh/test.sh/verify.sh) - 将测试文件 base64 编码传入容器
- 执行测试并捕获输出
- 解析输出——支持三种格式:
- 结构化格式:
results starts here→PASSED/FAILED→results ends here - Pytest 原生:
N passed in X.XXs - 正则匹配:
=+ FAILED =+
- 结构化格式:
评分维度由 rubric/rubric.json 定义:正确性(输出是否正确)、功能性(功能是否完整)、健壮性(边界情况处理)。
5.2 Observability:F2P/P2P 评分
F2P(Fail-to-Pass):在基线代码上失败,但在应用 golden patch 后通过的测试——Agent 需要让这些测试通过。
P2P(Pass-to-Pass):在基线和修复后都应通过的测试——Agent 的修复不能引入回归。
生成流程(源码 parser/evaluator.py):
1. 运行 test.patch(基线测试) → 记录每个测试结果
2. 运行 test.patch + golden.patch(参考修复) → 记录每个测试结果
3. F2P = 基线 FAIL + 修复后 PASS 的测试 + 修复后新增且 PASS 的测试
4. P2P = 基线 PASS + 修复后 PASS 的测试
Agent 评分:
1. 应用 Agent 的 git diff
2. 应用 test.patch(重置测试文件到已知状态)
3. 执行测试命令
4. 解析输出,与 F2P/P2P 对比
5. 通过条件:所有 F2P 测试 PASS + 所有 P2P 测试 PASS
F2P 结果缓存到 f2p_cache/<task_id>.json,包含 golden.patch 的 SHA-256 hash 用于缓存失效。
第六章 · 执行流程源码级解剖
6.1 Integration 执行流程
multi_step_runner.py 的 run_single_trial() 分 6 个阶段:
Phase 1 — Docker 启动:
- 从
docker-compose.yaml启动所有服务 - 等待所有 healthcheck 通过(最长 800 秒)
- 注入默认 healthcheck(LocalStack 用
awslocal s3 ls,EspoCRM 用 wget)
Phase 2 — Git 基线 + MCP 配置:
- 在
/app初始化 git,创建基线 commit - 如果有 MCP 服务,等待 MCP config 就绪(最长 20 分钟)
- 写入
/config/mcp-required.txt声明所需 MCP 依赖
Phase 3 — 工具初始化:
- 创建
ToolExecutor(file + terminal + todo) - 创建
TerminalSessionManager(tmux 会话管理) - 构建 initial prompt
Phase 4 — Agent 主循环:
while True:
# 检查超时
if elapsed > max_timeout: break
# 检查步数限制
if step_num > max_steps: break
# 检查 token 上限(90%)
if current_tokens > max_tokens * 0.9: raise ConversationTooLongError
# 调用 LLM
response = llm.call(current_prompt)
# 执行工具(解析 keystrokes/tool_use/JSON/bash 格式)
tool_results = tool_executor.parse_and_execute_tools(response)
# 构建下一轮 prompt(注入终端当前状态)
current_prompt = build_episode_prompt(terminal_content)
# 检查完成标记
if "<task_complete>true</task_complete>" in response: break
Phase 5 — 构建结果
Phase 6 — 评估:
git diff --cached HEAD捕获 agent.patch- 执行
TaskEvaluator运行测试
6.2 Observability 执行流程
eval_runner/runner.py 的流程更简洁(基于 Inspect AI):
# Phase 1: 构建 Agent
tools = [apply_patch(), bash(), read_file(), search_files(), update_plan()]
agent = react(prompt=AgentPrompt(instructions=system_prompt), tools=tools)
# Phase 2: 创建 Inspect AI Task
task = Task(
dataset=MemoryDataset([sample]),
solver=agent,
scorer=unified_scorer(),
sandbox=("docker", compose_path),
time_limit=3600,
message_limit=250,
)
# Phase 3: 执行(Inspect AI 管理 Docker 沙箱生命周期)
eval_results = inspect_eval(tasks=[task], model=model_name)
# Phase 4: 读取 agent.patch + scoring metadata
Inspect AI 负责 Docker Compose 的启动/停止、Agent 循环、工具执行、沙箱隔离——评测框架只需定义 tools 和 scorer。
第七章 · 关键设计决策分析
7.1 为什么 Integration 不用 Inspect AI
Integration 需要持久的终端会话——Agent 可能先 cd /app,然后 pip install requests,再 python3 solution.py,每个命令的效果要在同一个 shell 中累积。Inspect AI 的 bash 工具每次调用是独立的,不保持状态。
自研 Harness 使用 tmux session 解决了这个问题——所有命令在同一个 tmux 窗口中执行,Agent 下一轮能看到完整的终端状态(包括前几步命令的输出)。
7.2 为什么严禁 heredoc
System prompt 中有大段警告:
⚠️⚠️⚠️ CRITICAL - FILE WRITING ⚠️⚠️⚠️ NEVER use heredoc syntax (cat << EOF, cat <<‘EOF’…) as it WILL cause terminal hangs and timeouts!
原因是 tmux 的 send_keys + 阻塞等待模式无法正确处理 heredoc 的多行输入——send_keys("Enter") 会让 tmux 认为命令已执行完毕,但实际上 heredoc 还在等待 EOF 结束符。这会导致终端永久挂起。
7.3 为什么 Observability 用 apply_patch 而不是直接编辑文件
SWE-bench 生态的标准做法是生成 unified diff patch。好处:
- 原子性:一个 patch 可以同时修改多个文件
- 可追溯:patch 本身就是 diff,不需要额外的 git diff 步骤
- 兼容 F2P/P2P:评分系统只需要
git apply agent.patch→ 运行测试 - LLM 友好:生成 diff 比生成完整文件更节省 token
7.4 干扰项(Distractor Issues)的设计意义
Integration 任务的 Plane 看板中有干扰 issue。这不是为了增加难度,而是模拟真实工作场景中的信息噪声——真实的项目管理工具上永远有无关的 issue,Agent 需要自己判断哪个才是当前任务。
这是 APEX-SWE 相比 SWE-bench 的一个显著改进——SWE-bench 直接把 issue 内容喂给 Agent,没有噪声。
7.5 为什么支持 20+ 模型
从源码 data_models.py 的 ModelType 枚举可以看到,APEX-SWE 支持:
- Anthropic:Opus 4/4.1/4.5/4.6、Sonnet 4/4.5
- OpenAI:GPT-4o、GPT-5 系列(5/5.1/5.2/5.3/5.4 + Codex 变体)
- Google:Gemini 2.5 Pro/Flash、3 Pro、3.1 Pro
- xAI:Grok 4
- Meta:Llama 4 Maverick
- Qwen:Qwen3 Coder 480B
- DeepSeek:V3P2
- Kimi:K2/K2P5
通过 LiteLLM 统一接口 + 按模型自动配置 reasoning effort(Anthropic 用 thinking budget,OpenAI/xAI 用 reasoning_effort,Google 用 thinking budget)。
第八章 · 与 SWE-bench / APEX-Agents 的对比
| 维度 | APEX-SWE | SWE-bench | APEX-Agents |
|---|---|---|---|
| 任务数 | 50 | 2,294 (SWE-bench Verified: 500) | 480 |
| 领域 | 软件工程 | 开源项目 Bug 修复 | 投行/咨询/法律 |
| 环境 | Docker Compose 多服务 | 单容器 | Docker + MCP Gateway |
| 任务来源 | 真实开源 Bug + 人工设计集成 | 真实 GitHub Issue/PR | 真实 Google Takeout + 人工设计任务 |
| Agent 工具 | tmux 终端 + 文件 / Function Calling + Bash | Bash + 文件编辑 | MCP 工具(9-18 个) |
| 评分 | Pytest + F2P/P2P | F2P/P2P | LLM Rubric |
| 可观测性 | ✅ Grafana + Loki + Mattermost | ❌ | ❌ |
| 干扰项 | ✅ Plane 看板噪声 | ❌ | ❌ |
| 多服务编排 | ✅(LocalStack/Zammad/CRM/电商/邮件) | ❌ | ✅(但是 MCP 模拟层) |
| 完全开源 | ✅(50 个任务全部可复现) | ✅ | ⚠️(452/480 可复现) |
| 最强 Pass@1 | 41.5% | ~49% (Verified) | 24% |
关键差异
APEX-SWE vs SWE-bench:APEX-SWE 增加了 Integration 任务(SWE-bench 只有 Bug 修复)和可观测性栈(SWE-bench 没有日志/监控),但任务数少得多。SWE-bench 的统计力更强(2,294 vs 50),APEX-SWE 的环境复杂度更高。
APEX-SWE vs APEX-Agents:同一个团队的两套基准,但技术栈完全不同。APEX-Agents 用 Archipelago 框架 + Python MCP Server + S3 数据注入,APEX-SWE 用 Docker Compose + 混合语言 MCP Server + 本地文件。APEX-Agents 的 Leaderboard 分数更低(24% vs 41.5%),说明专业服务任务可能比软件工程任务更难。
第九章 · 100% 可复现性
与 APEX-Agents 不同(有 28 个任务因缺少非公开的 FMP/EDGAR Server 无法执行),APEX-SWE 的全部 50 个任务都可以在开源环境中完整复现。原因:
- 没有外部 API 依赖:所有服务都是本地 Docker 容器(LocalStack 模拟 AWS,不需要真实 AWS 账号)
- 代码库预置:Observability 任务的
repo/目录包含完整的开源项目克隆 - 数据预导出:Loki 日志、Mattermost 消息、Plane issues 都是预导出的静态数据
- Docker 镜像公开:ECR 镜像
public.ecr.aws/k4t1e3r5/apex-code可直接拉取
唯一需要的外部依赖是 LLM API Key(用于调用被评测的模型)。
第十章 · 数据合成与环境构建启示
10.1 Integration 任务的构建方法论
- 选择服务组合:从 8 个可用服务中选取 2-5 个,设计跨服务的数据流
- 编写种子数据:
issues.json、connection-info.md、API 文档 - 实现参考解决方案:
solution.py - 编写 Pytest 测试:三维评分(正确性/功能性/健壮性)
- 添加干扰项:在 Plane 看板中放入无关 issue
10.2 Observability 任务的构建方法论
- 选择真实 Bug:从 GitHub 找已修复的 Issue/PR
- 导出可观测性数据:重放 Bug 场景,导出 Loki 日志、模拟 Mattermost 讨论
- 提取 golden.patch:从 PR 中提取修复 diff
- 编写 test.patch:确保测试能检测 Bug 的存在和修复
- 计算 F2P/P2P:运行基线测试 + golden 测试,自动生成
10.3 MCP 作为工具接口标准
APEX-SWE 的 Integration 和 Observability 都使用 MCP 作为 Agent-Service 交互协议,但方式不同:
- Integration:MCP Server 在容器内运行,通过
/config/mcp-config.txt配置 - Observability:Agent 通过
bash工具手动构造 JSON-RPC 请求发给 MCP Server
这说明 MCP 协议的灵活性——既可以被框架自动集成,也可以被 Agent 手动调用。
附录 · 支持的模型完整列表
Integration Harness
| 模型 | Provider | context window |
|---|---|---|
| claude-opus-4-6 | Anthropic | 1M |
| claude-opus-4-5-20251101 | Anthropic | 200K |
| claude-sonnet-4-5-20250929 | Anthropic | 1M |
| claude-sonnet-4-20250514 | Anthropic | 1M |
| gpt-5.4 | OpenAI | 272K |
| gpt-5.3 / gpt-5.3-codex | OpenAI | 400K |
| gpt-5.2 / gpt-5.2-codex | OpenAI | 400K |
| gpt-5.1-codex | OpenAI | 272K |
| gemini-3.1-pro-preview | 1M | |
| gemini-3-pro-preview | 1M | |
| xai/grok-4 | xAI | 256K |
| qwen3-coder-480b | Fireworks | 262K |
| deepseek-v3p2 | Fireworks | 164K |
| kimi-k2 / kimi-k2p5 | Fireworks | 128K |
Observability Harness
支持相同的模型列表,通过 eval_runner/config.py 的 MODELS 字典配置。默认模型为 claude-opus-4-5。
参考资源
| 资源 | 链接 |
|---|---|
| 论文 | arXiv 2601.08806 |
| 数据集 | huggingface.co/datasets/mercor/APEX-SWE |
| 评测框架 | github.com/Mercor-Intelligence/apex-swe |
| Leaderboard | mercor.com/apex/apex-swe-leaderboard |
| 博客 | mercor.com/blog/introducing-apex-swe |