Terminal-Universe:轨迹回炉成环境,追不上没跑过的领域

轨迹堆积如山,后训练为什么还是缺数据?

如果把终端 agent 的每次工作都录下来,录像带已经堆成山了。一个 agent 在终端里跑任务,敲什么命令、读哪个文件、改哪几行、调什么工具,全被记成一条条轨迹。Qwen 团队这次用来做实验的公共轨迹池里有 359,593 条,够拍几十年的连续剧。可论文一开头就泼了盆冷水:数据多,不等于训练原料够。agent 后训练真正缺的,是环境(environment)。

一条轨迹只是单次冻结的演示(frozen demonstration)。它忠实记录了"某个 agent 当时是怎么做的",但仅此而已。它不能重放成新任务,不能在你解错时告诉你错在哪,更没法检验"另一种解法行不行"。环境恰恰相反。一个可执行环境是一台可以反复出题的机器:往里丢不同的任务,让它跑,用测试自动判对错,拿执行反馈当训练信号。同一条轨迹只能教一次,同一个环境能养出无数条高质量轨迹。下面是两者的对比:

维度轨迹环境
本质单次执行的冻结演示可反复运行的 workspace 加测试
复用性一次性,看过就废可再生,反复查询出新任务
反馈无,只能模仿执行反馈,可自动验证
对后训练的价值低,质量受制于产出它的模型高,能支撑验证驱动的训练

为什么这个区别现在才成为问题?因为终端 agent 的评测基准把"可执行环境"变成了硬通货。Terminal-Bench 2.1 的 89 个任务,每个都配齐 Docker 容器、人工写的指令和可执行测试,评分只看最终状态过不过测试。Terminal-Bench 2.1 的协议细节见 Terminal-Bench。EvoCode-Bench v2 则更进一步,26 个任务铺开成 227 轮多轮对话,工作区全程保留、验证器逐轮累计,考的是 agent 在需求不断演化时能不能不崩,协议见 EvoCode-Bench。这些基准全都在说同一件事:想让 agent 变强,就得有成批可验证的环境当训练场。

于是问题来了:环境这么好,为什么大家不去造?因为从零造一个环境贵得离谱。同样在给智能体生产训练环境的 SWE-Gym,为了 2,438 个实例花了约 200 人工小时外加一万 CPU 小时,见 SWE-Gym。手工配依赖、写测试、保证可复现,每一步都烧人力,这条路很难铺到十万级规模。

那有没有更便宜的路子?Terminal-Universe 的答案是:别从零造,去回收。海量轨迹里其实藏着一批环境的"底片",把它们冲洗出来就行。这就是论文的核心反转,全部内容见 Terminal-Universe。

轨迹是环境的底片:工具调用历史为什么能反推环境?

想想 agent 在终端里干活时都留下了什么。它要完成一个任务,几乎必然要读文件、写文件、编辑文件。读的时候,文件当前内容进了它的上下文;写和编辑的时候,改动前后的状态都被记录。换个角度看,这些工具调用其实就是环境的"反向投影":环境长什么样,决定了 agent 能读到什么、改到什么。既然投影是可逆的,那从轨迹反推环境就有了解。

论文最关键的观察就在这里:File Read、Write、Edit 这类工具调用,本身就暴露了它运行所在工作区的文件结构与内容。agent 不会凭空想象一个文件,它读到的每一行、改掉的每一处,都是环境真实存在的证据。所以重建不需要从零生成(generation),只需要把操作历史当成证据来重建(reconstruction)。前者是凭空造出一个世界,后者是根据线索还原一个已经存在过的世界,两者的工作量完全不是一个量级。

论文把这件事讲得很漂亮:一条轨迹和一个环境,是同一个 episode(回合)的两种视图。传统流程是先有环境,再让 agent 在里面跑,rollout(采样)出一条轨迹,这是从环境到轨迹。Terminal-Universe 把箭头掉了个头:从轨迹出发,recover(恢复)出它曾经运行过的那个环境。左边那条路是前人走的路,右边是这篇论文要走的路。

Terminal-Universe 总览

图注:论文总览图。左侧是两条方向相反的箭头:传统路线(Environment → Trajectory)先从环境采样出轨迹,本文路线(Trajectory → Environment)从轨迹恢复环境;中间是重建流水线的简化示意;右侧示意恢复出的环境可被三种方式重新查询。出处见 Terminal-Universe。

这个思路有个贴切的类比:轨迹是底片,环境是照片。底片不是照片本身,它只是记录光线分布的化学层;但只要有正确的冲洗工艺,底片就能还原出照片。轨迹也不是工作区本身,它只记录文件系统在某段时间里被怎么碰过;但只要有正确的重建工艺,就能把工作区冲洗出来。底片能还原出什么,取决于镜头拍到了什么;轨迹能重建出什么,取决于 agent 当时访问过什么。这正是后面所有步骤的边界所在。

可问题紧接着就来了:底片上只有镜头拍到的部分。agent 跑一个任务,通常只碰它需要改的那几个文件,项目里其余几十个文件它看都没看过。光靠轨迹,能冲洗出一个完整可用的工作区吗?论文的答案是:能,但不能只靠一步。

顺便说一句,这套"冲洗工艺"有个容易被忽略的前提:补全和判定这些精细活,都交给了另一个 LLM 去流水线化完成。也就是说,它不是一套纯手写的规则系统,而是"以模型补模型"的工业化装配线。

三步把底片冲洗成工作区:回放、补全、过滤

冲洗分三步走:确定性回放(deterministic replay)、智能体补全(agentic completion)、充分性过滤(sufficiency filter)。

第一步是回放。拿到一条轨迹,按时间顺序处理里面的文件操作,把每个被访问过的文件恢复到 agent 改动前的状态,把 agent 自己新建的文件排除掉,同时保留它的修改记录,因为这些修改之后要用来验证任务。这一步是确定性的,同一条轨迹永远得到同一个结果。但它只能还原 agent 碰过的那一小片世界,残缺是注定的。举个例子:假设 agent 在修一个 Python 项目的 bug,全程只改了 utils.py 和 config.py,回放就只能恢复出这两个文件改动前的版本,项目其余三四十个文件它碰都没碰过,自然也无从还原。

Terminal-Universe 框架

图注:论文整体框架。左侧是重建流水线:记录下的轨迹经 replay 和 completion 变成可执行 workspace,只有通过 sufficiency filter 的才会被保留;中间的 recovered workspace 是所有下游任务的共享底座;右侧是 Intent Recovery、Single-WS、Cross-WS、Multi-Round 四种重查询机制。出处见 Terminal-Universe。

残缺到什么程度,论文给了清点数字。只回放不补全时,Terminal 池里 38,294 个重建环境只有 40.2% 算得上 task-sufficient,也就是"够格支撑原任务";SWE 池的 1,900 个仓库更惨,只有 20.1%。换句话说,纯回放出来的工作区,六成以上根本没法用。这也解释了为什么必须有第二步。

第二步是补全。一个补全 agent 上场,把缺失的文件、残缺的部分、没配好的依赖补齐,让工作区从"能看"变成"能跑"。但这里有一条红线:补全可以补上下文,绝不许泄露答案。补全 agent 的任务是补足项目结构和依赖,让任务变得可解,而不是替未来的 solver 把答案写出来。如果补全顺手把解法也补上了,那这些数据训练出来的模型,学的就不是"如何解题",而是"如何背答案"。

补全的效果立竿见影:Terminal 池的 sufficient 比例从 40.2% 跳到 93.5%,SWE 池从 20.1% 跳到 77.1%。工作区的体量也说明问题,见下图:

补全前后工作区规模

图注:补全前后工作区规模对比。Terminal 池(左)的 mean files 从 2.9 涨到 22.4,文本行数从 mean 90 涨到 5,761;SWE 池(右)同构,mean files 从 5.6 涨到 37.9。出处见 Terminal-Universe。回放只能给出 agent 碰过的零星文件,补全才把工作区撑成能跑的项目。

第三步是过滤。补全过的环境也不是都能用,需要一个 agentic judge 用只读工具检查每个工作区,判定它是否 task-sufficient。只有通过检查的环境才进入下游。整个漏斗走到这里,从最初的轨迹里重建出的 68,263 个环境,最终剩下 37,273 个够格的。这三步拼起来,就是把"底片"真正冲洗成可用"照片"的工艺。

环境有了,下一步自然是:怎么让每个环境生出尽可能多的任务?

一个环境能变出多少任务:四种重查询与两条缩放轴

回顾上一章的框架图:中间那条 recovered workspace 总线,是所有下游任务的起点。论文在它上面挂了四种重查询(re-querying)机制,沿着两条互补的轴扩展:广度上跨工作区合成,深度上做多轮对话。

最基础的一种叫 Intent Recovery(意图恢复),它不做新题,而是把轨迹里那个原始任务"找回来"。单轮轨迹通常只有一个实质请求,直接归一化成一个自含任务;多轮轨迹则取首个请求定主题,把后续澄清、约束、扩展的请求合并进来,无关请求剔除。这一步的意义在于:它产出的任务描述是干净的、自足的,而不是散落在对话里的碎片。更重要的是,论文会在重建好的环境上,让一个更强的 teacher 模型重新求解这个任务,得到的轨迹质量远超原轨迹,这点第五章会详细展开。

第二种是 Single-WS(单工作区合成)。一个离线生成器在每个恢复出的工作区上提 5 个候选任务,按是否扎根于工作区、结构是否多样、能否被验证来筛选,最后每个环境随机挑 1 个用于 rollout。它问的问题是:这个代码库里还能派什么新活?答案不会凭空出现,每个候选都要能被这个环境的测试验明真伪。

第三种是 Cross-WS 合成,也就是广度轴。先给每个工作区建 profile,刻画它的技术域和实现能力;再用 TF-IDF 在 profile 之间找候选对;最后由 LLM judge 确认是否存在"方向性依赖",即参考工作区具备、而目标工作区缺失的功能。确认后,参考工作区被只读挂载到独立路径,solver 必须自己导航过去、读懂实现、再回来适配。这模拟的正是开发者跨代码库改接口的真实场景,也解释了为什么这类轨迹明显更难:turns 从 14 涨到 23,tool calls 从 20 涨到 38,连 teacher 自己的 pass@1 都从 72.3% 掉到 49.2%。

第四种是 Multi-Round 合成,也就是深度轴。它让一个 user agent 扮演用户,维护一张需求追踪表,把单轮查询拉长成一场多轮会话。每一轮先提交更新后的规格,由 verifier agent 在容器里写本轮的 acceptance tests,再让 coding agent 执行,测试同时覆盖新增标准和历史需求的回归。三种交互样式让需求自然演化:功能扩展、修复失败的功能、需求冲突。比如用户先让 agent 修一个崩溃 bug,修复验证通过后又追加日志需求,下一轮再要求改动输出格式,需求的演化路径由测试动态把关。最多 6 轮,中途的失败会留在对话历史里,成为后续轮次的 recovery supervision。持久工作区加累计验证器这套设计,在多轮评测里已经流行了好几年,InterCode 等基准早就验证过这种模式的可行性,见 InterCode。Terminal-Universe 的贡献,是把这套评测范式搬到了训练侧。

四种机制跑完,数据漏斗就成型了:37,273 个够格环境,经过四路重查询和 verifier 逐条把关,最后留下 31,977 条 SFT 记录,约 1.42B tokens。看每条记录的长度分布就能明白两条轴各自补了什么:Intent Recovery 的记录中位 12 轮、36.1k tokens,Single-WS 是 14 轮、30.4k,Cross-WS 拉长到 23 轮、46.5k,而 Multi-Round 直接到 92 轮、126.1k tokens。深度轴产出的不是"更长的单轮",而是真正跨多轮、带状态延续的长程任务,见 Terminal-Universe。 两条轴也不是装饰:广度轴上,Single-WS 数据单独训出 56.4 分,混合进 Cross-WS 后涨到 58.4;深度轴上,Multi-Round 把 EvoCode-Bench v2 的 MT@4 从 18.4 推到 21.0。每条轴都实打实地贡献了分数。这批数据训出来的模型,到底值不值?下一章看结果。

3.2 万条重建数据让两个评测齐涨,功劳却不在模仿轨迹

先看这批数据是怎么筛出来的:

数据漏斗:从 359,593 条公共轨迹出发,重建出 68,263 个环境,其中 37,273 个通过充分性过滤,最终经四种重查询加 verifier 筛选,得到 31,977 条 SFT 记录。其中 Single-WS 贡献 25,386 条,Cross-WS 3,512 条,Multi-Round 3,079 条。出处见 Terminal-Universe。

用这批数据对 Qwen3.5-27B 做 SFT,结果在主结果表里:

评测基准基座模型Terminal-Universe-27B提升
Terminal-Bench 2.041.652.8+11.2
Terminal-Bench 2.146.258.1+11.9
EvoCode-Bench v2 MT@46.320.1+13.8
EvoCode-Bench v2 Case67.876.1+8.3

单轮评测提升了十来个点,多轮评测的 MT@4 更是从 6.3 翻了三个跟头到 20.1。多轮那栏尤其值得一提:EvoCode-Bench v2 的 227 轮是持久工作区加 fail-stop 记分,任何一轮掉链子之前的努力都可能白费,能涨这么多说明模型真的学会了在多轮需求演化里撑住。换个说法,单轮评测考的是"这道题会不会做",多轮评测考的是"需求变了三轮之后,你还记不记得前面改过什么"。后一种能力最难靠模仿轨迹获得,因为大部分公开轨迹都是单轮任务留下的,而 Multi-Round 合成专门补上了这个缺口。

但光看总分还不够,论文里最反直觉的一张消融表才是重点。同样是 35.8k 条记录、同样规模的数据:一组直接拿源轨迹做 SFT,让模型模仿原 agent 的动作;另一组用 Intent Recovery 在重建环境上让更强的 teacher 重新求解。结果在 Terminal-Bench 2.1 上,模仿源轨迹只有 36.7,重新求解达到 52.1,差了整整 15.4 分。这说明涨分根本不来自"模仿轨迹",而来自"在可验证环境上重新解题"。直接模仿会把原 agent 的犹豫、绕路和错误一起学进去;重新求解则让模型面对完整可验证的环境,自己找出正确答案,再由 verifier 把关。轨迹只是起点,真正值钱的,是重建之后那个能反复验证的世界。

另外两个消融把这条逻辑补完整:agentic completion 这一步单独值 4.2 分(48.7 到 52.9),还把多次运行的方差从 ±3.5 收窄到 ±1.4,说明补全不仅提分还让训练更稳;verifier 过滤在更难合成的 Cross-WS 数据上贡献 2.2 分(53.2 到 55.4)。把 budget 花在恢复更多环境上,比在同一批环境里多出题、多解几遍划算得多。这正好回到论文的出发点:环境才是稀缺资源,轨迹只是原料。

还有个细节值得说:这些轨迹不是哪个团队的私有财产。终端侧的 159,552 条来自 LFM2-Terminal 与 LiteCoder-Terminal,软件工程侧的 199,041 条来自 SWE-rebench、SWE-smith、CoderForge 和 SWE-Gym 等公开数据集,见 Terminal-Universe。也就是说,这套"回炉"工艺吃的是公开原料,谁都能复现。更有意思的是,从 1,900 个 SWE 仓库重建出的 Intent Recovery 数据(10.3k 条)也能迁移到终端任务上,Terminal-Bench 2.1 平均分从 47.0 涨到 50.0,说明"环境化的任务"带来的能力是可以跨域迁移的,见 Terminal-Universe。这比单点涨分更有说服力,它说明学到的是泛化能力,不是背题。

它在环境合成版图上的坐标,和造不出的那部分世界

"怎么给 agent 批量生产可执行环境"这个赛道,这两年已经挤满了选手,但走法各不相同:

路线代表工作规模一句话特征
repository-basedSWE-Gym2,438 实例 / 11 仓库从真实 issue 出发,人工配环境
perturbationSWE-smith50,137 实例 / 128 仓库先建环境,再自动往代码里注入 bug
procedural-from-commitsR2E-Gym8,135 任务 / 13 仓库从 commit 反推问题陈述
procedural-RLEndless Terminals3,255 任务程序化生成任务、容器与测试
taxonomy-guidedCLI-Universe6,000 条轨迹用能力分类学引导任务合成
recursive evolutionRST37,484 任务从已验证种子任务递归拉长
trajectory reconstructionTerminal-Universe37,273 个环境从轨迹反推环境再出题

手工搭环境(SWE-Gym)贵到只能覆盖 11 个仓库。注入 bug 的 SWE-smith 虽然能冲到 5 万个实例,但环境本身还是人造的。从 commit 反推的 R2E-Gym、程序化生成的 Endless Terminals、分类学引导的 CLI-Universe、递归演化的 RST 也都各自卡在不同环节。Terminal-Universe 的独特位置在于:它是唯一同时具备轨迹重建、跨工作区合成和多轮合成三项能力的工作。最干净的对照组是 RST,两家都用 Qwen3.5-27B 训练、都在 Terminal-Bench 2.0 上评测,RST 拿 49.4,Terminal-Universe 拿 52.8,轨迹反推这条路并不输给递归合成。

但论文自己也交代了三道边界,每一道都呼应标题里的半句话"追不上没跑过的领域"。

第一,所有工作区都跑在标准 Ubuntu 24.04 容器里,不走 SWE-Factory、RepoLaunch 这类自动化环境构建,遇到特殊系统依赖和复杂编译步骤,保真度有限。第二,重建出的世界被源轨迹的覆盖度锁死:轨迹里没有的领域、语言、工具链,一个都造不出来。轨迹池里 Python 的轨迹堆成山,冷门语言和专用工具链就是空白,这不是工艺能补的,是原料本身没有。第三,同一个 teacher 既出题又解题又写 verifier,能力上限同时决定覆盖度和自查能力,模型自己验证器抓不住的错,就会漏进训练数据。

所以这套方法真正的边界,不是工艺不够好,而是原料本身的边界:它能回收的世界,只到人类 agent 曾经跑过的地方为止。反过来想,这也给下一批工作指了路:多 teacher 加独立 verifier,把"出题、解题、批改"三个角色拆开互相制衡,或者把回收的触角伸向更偏的领域。轨迹不是废料,而是可以回收的世界,回收半径恰好等于 agent 走过的路。

想深入可以读原文:Terminal-Universe: Turning Agent Trajectories into Scalable Terminal Environments,arXiv:2609.04148。

参考文献

Terminal-Universe:轨迹回炉成环境,追不上没跑过的领域