[基模杂谈]SWE 环境构建与长程轨迹挖掘
Jasaxion / 2026-09-12
现在 Coding 已经逐渐变成基座模型的一项基础能力。继续往上做,绕不开数据:预训练阶段有代码仓库、技术文档和 Stack Overflow,后训练阶段则需要能真实执行、持续交互、自动验收的 Agent 轨迹。
SWE 数据难做,不是因为代码少,而是因为“任务、环境、过程、结果”很难同时闭合。只有问题没有环境,模型无法试错;只有环境没有可靠测试,轨迹又无法判断好坏。
这篇主要记录两件事:一个真实的软件工程任务,怎样被还原成可执行、可验证的训练环境;Agent 在环境中产生的长程轨迹,又怎样被采集、清洗并变成训练数据。
SWE-Gym 给出了较早的一套任务契约和训练样例,后续的重点已经转向自动环境构建、确定性验证和集群化生产。
一、先来看看经典的 SWE-Gym
SWE-Gym 沿用了 SWE-bench 的基本思路,把真实 Issue / PR 拆成一个可以反复运行的任务:
| |
Agent 拿到的是问题描述和修复前的仓库。人类补丁只用于证明问题在历史上有解,并帮助构造验收信号,不应暴露给求解 Agent。
SWE-Gym 从 358 个仓库抽取了 64,689 个原始任务,最后只在 11 个 Python 仓库上做出 2,438 个可执行实例。环境补齐大约投入了 200 小时人工、10,000 CPU core hours,预构建镜像约 6 TB。这些数字真正说明的是:从 GitHub 抽到一个 PR 很便宜,把它恢复成可靠的历史运行现场很贵。
它还有一个重要结果。作者用 GPT-4o 和 Claude 3.5 Sonnet 采到 491 条成功轨迹,平均约 19 轮、19k Token。少量经过执行验证的轨迹就能改善模型的工具使用和修复能力,说明这类数据值得做。不过,同一论文里的自我改进实验也出现过性能下降,说明“采到成功轨迹再混回训练集”并不天然有效,数据分布和训练方法仍然重要。
所以 SWE-Gym 更适合作为一个起点:它说明了什么叫可执行任务,也暴露了人工维护环境的规模上限。
二、工业场景中,谁来构建环境
真实工业流水线里,环境自然尽量由 Agent 自动构建。不过需要区分两个角色:
| |
通常不会让 Solve Agent 在每一次 rollout 开头都从裸机重搭环境。这样成本太高,也会把“环境没装好”和“问题没修好”混成同一种失败。更常见的做法是离线批量生成环境,验收后固定镜像 digest 和测试入口,再供后面的 SFT、RL 或评测重复使用。
因此,Build Agent 不是整套系统本身,只是环境工厂中的一个非确定性工人。它擅长读取 README、依赖文件、CI 配置和错误日志,提出安装与修复动作;容器调度、快照回滚、缓存、超时、网络隔离和最终验收,仍然应由确定性程序控制。
三、一条比较完整的环境工厂
| |
SWE-Hub 把这个思路做成了生产系统:底层是共享的执行基座,负责固定镜像、统一 verifier 接口和产物;上层再生产不同类型、不同长度的软件工程任务。这个分层很有工程价值,因为环境、验证器和任务生成不再绑死在某个 benchmark 上。
图:SWE-Hub architecture。它把 Env Agent、确定性执行基座和多条任务生产线分开。来源:SWE-Hub。
落到存储层,至少要保留这些东西:
- 原始 Issue / PR、base commit、gold patch 和 test patch;
- Dockerfile 或安装配方、镜像 digest、构建日志;
- 标准测试入口、F2P / P2P 列表和验证器版本;
- 运行所需的 CPU、内存、磁盘、网络和超时;
- 数据生成器、Build Agent、模型和 prompt 的版本。
否则几个月后重跑失败,很难判断是代码变了、依赖消失了,还是生成管线悄悄变了。
四、Build Agent 实际在做什么
环境构建不是让模型读完 README 后一次性写 Dockerfile,而是一个有执行反馈的搜索过程:
- 查看目录、依赖文件、CI 和历史安装说明;
- 选择基础镜像,安装系统库和语言依赖;
- 找到真实测试命令,运行一小部分测试;
- 根据编译、导入、版本冲突和服务错误继续修正;
- 成功后把有效动作压缩成可重放的构建配方;
- 从空白状态重新构建一次,确认不是偶然跑通。
Repo2Run 的设计比较直观。Agent 在内部容器里安装依赖、查文件和跑测试,外部环境负责更换基础镜像、保存快照和回滚。失败命令可能已经改坏包、文件或缓存,所以不能只看退出码后继续试;需要先回到确定状态。最终 Dockerfile 也不是让模型凭记忆重写,而是从成功动作序列中合成。
图:Repo2Run workflow。上半部分负责交互探索,下半部分负责隔离、回滚和配方生成。来源:Repo2Run。
论文在自己的 420 个 Python 仓库基准上报告了 86.0% 的环境构建成功率。这个结果证明专用 Build Agent 比“让通用 Coding Agent 顺手搭环境”可靠,但它不能直接外推到所有仓库。 复杂服务、私有依赖、硬件要求、多语言构建和已经损坏的历史版本,仍然会失败。
后续系统开始把单 Agent 再拆开。daVinci-Env 让不同 Agent 分别做仓库探索、Dockerfile 构建、评测脚本构建和测试分析,并用本地 Git 镜像、基础镜像缓存和集群调度降低成本。 论文报告在 64 个计算节点上约两周构造了 45,320 个验证环境,覆盖约 12.8k 个仓库。

图:OpenSWE framework。右侧几个 Agent 分工生成环境并闭环检查,左侧和中间负责材料去重、缓存与分布式执行。来源:daVinci-Env。
这里的关键不是 Agent 数量,而是把不同失败归给不同模块。依赖没装好、测试入口写错、题面与补丁不一致、仓库本身不可运行,不能最后都算成一次模糊的“构建失败”。
五、构建成功不等于环境有效
docker build 返回 0,只能证明镜像能生成。测试命令能启动,也只说明仓库大概可运行。一个 Issue 任务至少要做双态验证:
| |
第一遍证明问题确实存在,第二遍证明参考修复能让目标测试变绿且没有破坏原有测试。每遍还应从干净快照开始,重复运行并过滤 flaky case。
生产环境里还要防几类假正样本,常见的几种 Hacking 现象:
- Agent 删除测试、改断言、跳过用例或硬编码答案;
- 测试只覆盖表面行为,对真正的 Issue 没有区分力;
- 网络、时间、随机数或外部服务让结果偶然通过;
- gold patch、未来 commit、凭据或隐藏测试泄漏进沙箱;
- 上一次 rollout 留下缓存、进程或文件,污染下一次执行。
所以 verifier 应尽量小而确定:固定入口、明确退出码、结构化测试明细、只读任务材料、有限资源和默认断网。Agent 可以生成 verifier 候选,但不能自己宣布验收通过。
SWE-Factory 在 671 个跨语言 Issue 中得到 269 个有效任务,约 40.1%;其自动 F2P 判断报告了 0.92 precision 和 1.0 recall。这个漏斗比“生成了多少 Dockerfile”更接近真实产量,因为最终有用的是可区分、可复现的任务,而不是容器数量。
六、传统的 SWE-Gym 方法是否过时?
如果把它理解成“今天搭建工业数据管线的完整方案”,确实已经不够了。它只有 11 个 Python 仓库,环境构建包含较多人工,镜像体量大,也没有覆盖现代的多语言、集群调度和自动 verifier 生产。
如果把它理解成一种数据契约,它仍然没有过时。base commit、gold patch、test patch、F2P / P2P 和隔离执行,至今仍是许多系统的共同基础。后续工作主要是在替换它最贵的部分:
- Repo2Run、SetUpAgent、RepoLaunch:把环境搭建变成专门的 Agent 任务;
- SWE-smith:共享仓库环境,再主动注入可验证 Bug;
- SWE-rebench / V2:持续从更多仓库和语言中构造可复现任务;
- SWE-Factory、daVinci-Env:把任务、测试和环境生成做成多 Agent 生产线;
- SWE-Hub:把执行基座、验证接口和不同任务产品线统一起来;
- SWE-Next:按 repo-quarter 复用环境画像,摊薄历史环境的构建成本。
规模也已经发生变化。SWE-rebench V2 报告了 32k+ 容器化任务、3.6k+ 仓库和 20 种语言;GLM-5 技术报告提到 RepoLaunch 管线生成了 10k+ 可验证环境,覆盖 9 种语言,并支撑千级并发 rollout。这说明自动化环境工厂已经不是设想,而是当前训练基础设施的一部分。
不过,不同论文的成功率不能横着比较。Repo2Run 的 86.0% 来自 420 个 Python 仓库;SetupBench 从裸 Linux 出发,包含数据库和外部服务,最好结果为 62.4%;Multi-Docker-Eval 覆盖 9 种语言并要求 F2P,最高为 37.7%;EnvBench 还主动排除了容易仓库,Python 最好结果只有 6.69%。口径越接近复杂工业仓库,数字通常越低。
因此比较 Build Agent 时,至少要一起看:输入是不是裸环境、是否允许网络、覆盖多少语言、只要求测试能启动还是必须通过、是否检查 F2P、失败后能否人工接管,以及构建结果能否在另一台机器重放。
七、环境轨迹和解题轨迹是两种数据
自动搭环境以后,会自然产生两类长程轨迹。
第一类是环境构建轨迹。 它记录 Agent 如何读 CI、选择版本、解决依赖冲突、发现测试入口、处理失败命令并生成 Dockerfile。这类轨迹适合训练 Build Agent,也适合做错误分类和环境记忆库。
第二类是 Issue 求解轨迹。 它记录 Agent 如何理解题面、搜索代码、形成假设、修改文件、运行测试和检查最终 diff。这类轨迹才直接用于训练 Coding Agent。
两者不要混在同一种成功率里。环境失败意味着这次任务不一定给 Solve Agent 提供了公平机会;求解失败则说明在环境有效的前提下,策略没有找到正确补丁。
一条可回放的轨迹至少要保存:
| |
尤其要区分“模型做的事”和“harness 替模型做的事” 。自动截断日志、补全命令、重试工具、恢复快照、调用子 Agent,都可能改变结果。如果只保存一份整理过的聊天记录,后面就无法准确训练,也无法解释线上行为为什么复现不了。
八、长程轨迹怎样变成训练数据
一个朴素的采样流程是:
| |
成功轨迹适合做 SFT,但仍要清理空补丁、动作循环、无关大改和测试欺骗。失败轨迹不应该直接做行为克隆,可以用于训练 verifier / critic、构造同题偏好对,或者总结常见错误。对于 RL,环境奖励比文本打分可靠,但终局奖励稀疏,rollout 又很慢,需要单独处理吞吐和信用分配。
近期系统在这件事上有几个朴素的方向:
- GLM-5 使用 token-in-token-out 网关保存模型实际收发的 token 与元数据,并过滤环境崩溃和过旧的 off-policy 轨迹;
- KLong 用带重叠的轨迹切分做 SFT,再逐步拉长 RL 的时限,避免一开始就处理几百步交互;
- SWE-MeM 让模型学习何时压缩上下文、保留哪些状态,而不是只依赖固定长度摘要;
- Open-SWE-Traces 一类工作开始系统保存大规模软件工程交互,而不只发布最终 patch。
长轨迹压缩时,至少要留下当前假设、已读文件、关键符号、失败原因、未完成事项、执行过的命令和当前 diff。只保留一段自然语言总结,很容易在后半程重复搜索或把已经排除的方向重新走一遍。
九、如果自己搭一条最小流水线
我会先做四个相互独立的模块:
| |
第一阶段只选少量仓库,先把二次构建成功率和 verifier 精度做稳。第二阶段再接入 Build Agent,允许失败任务进入待修队列,不要为了追求自动化率放松验收。第三阶段才扩语言、扩仓库、扩集群,并加入环境配方记忆和镜像缓存。最后再根据训练目标采 Solve Agent 轨迹。
监控指标也要分开看:
- 候选任务数、环境首建和二次重建成功率;
- 基线可运行率、gold patch 通过率、F2P 有效率和 flaky rate;
- Build Agent 的平均尝试次数、人工接管率和单环境成本;
- Solve Agent 的有效 diff 比例、成功率、循环率和测试欺骗率;
- 各语言、仓库、任务类型、难度和时间段的数据分布;
- 训练集与评测集在仓库、时间和补丁层面的重合。
在工程上,40% 的自动有效率并不一定差。只要候选池足够大、失败可观测、验证严格,而且成功环境能够缓存复用,它仍然可以成为高吞吐的数据生产线。真正危险的是把构建成功、测试启动和任务有效混成一个数字。
十、Takeway
SWE-Gym 没有过时,但它代表的是第一代可执行 SWE 数据:少量仓库、较多人工、严格验证。现在更值得关注的是第二代环境工厂:Build Agent 自动探索配方,确定性基础设施负责隔离和验收,集群系统负责批量生产,最终再为 Solve Agent 提供稳定环境。
工业系统也不是“让一个更强的 Agent 从头包办一切”。更现实的组合是:
| |
最后仍然要记住这几个不等号:
| |
从工程角度看,长期价值最大的不是某一种生成 prompt,而是可重建的环境、可信的 verifier 和忠实记录的轨迹。它们决定后面的 SFT、Verifier、RL 和推理时扩展,究竟是在学习真实的软件工程过程,还是在放大数据管线里的噪声。
参考资料
- SWE-bench: https://arxiv.org/abs/2310.06770
- SWE-Gym: https://arxiv.org/abs/2412.21139
- Repo2Run: https://arxiv.org/abs/2502.13681
- EnvBench: https://arxiv.org/abs/2503.14443
- SetUpAgent: https://arxiv.org/abs/2503.07701
- SWE-smith: https://arxiv.org/abs/2504.21798
- SWE-rebench: https://arxiv.org/abs/2505.20411
- SWE-Factory: https://arxiv.org/abs/2506.10954
- SetupBench: https://arxiv.org/abs/2507.09063
- Multi-Docker-Eval: https://arxiv.org/abs/2512.06915
- SWE-Master: https://arxiv.org/abs/2602.03411
- GLM-5: https://arxiv.org/abs/2602.15763
- KLong: https://arxiv.org/abs/2602.17547
- SWE-rebench V2: https://arxiv.org/abs/2602.23866
- RepoLaunch: https://arxiv.org/abs/2603.05026
- SWE-Hub: https://arxiv.org/abs/2603.00575
- daVinci-Env / OpenSWE: https://arxiv.org/abs/2603.13023
- SWE-Next: https://arxiv.org/abs/2603.20691
- Open-SWE-Traces: https://arxiv.org/abs/2606.16038
- SWE-MeM: https://arxiv.org/abs/2606.28434
- 工程讨论:如何将 harness 变成经验:https://zhuanlan.zhihu.com/p/2063590880087372715
- 工程讨论:从开源仓库到无回溯 RLVR 轨迹采样:https://zhuanlan.zhihu.com/p/2076754448140054598