论文
- 标题:FACET: Preserving Source Intent and Executable State in Terminal Task Synthesis
- 论文链接:https://arxiv.org/abs/2608.18580
- 发表时间:2026 年 8 月(arXiv:2608.18580v1,2026-08-19 提交)
- 机构:中国科学技术大学(MoE Key Lab of BIPC,通讯作者 Feng Zhao)+ 上海人工智能实验室 + 复旦大学(高校 + 新型研究机构合作,USTC 主导)
- 代码:原文标注开源(GitHub Code、Model & Datasets、Project Page),但 PDF 中链接未展开,以论文页为准
- Hugging Face 当日热度:114 票(当日第二高)
一句话概括:别让大模型凭想象出题——先把考场真实搭起来,让考卷、标准答案、评分表都对着同一间「真实存在」的考场来写。
一、研究背景:终端任务合成,难在「四件套」对齐
1.1 终端任务成了训练 agent 的硬通货
从 GPT-5.2-Codex、Claude Code 到 Gemini CLI,能在终端里真正干活的 agent 已经成了各家竞速的主赛道。终端环境的独特价值在于:成功不取决于你生成了一段看起来像样的文本,而取决于你是否与一个不断变化的执行状态正确交互——建文件、装依赖、调工具、从报错中恢复、跑完长流程。正因如此,Terminal-Bench 这类容器化、执行验证的基准成了 agent 能力的试金石,而一系列工作进一步表明:可执行的终端任务本身就是优质的后训练监督信号。
需求随之而来:任务从哪来?人工写太慢,于是各种合成管线涌现——从领域规范、技能分类、终端录制、社区问答到程序化任务签名(Endless-Terminals、Nemotron-Terminal、TerminalWorld、Terminal-Lego、Tmax 等)。但论文一针见血地指出:源材料数量和多样性的堆叠,并不自动等于高质量的可执行任务。
1.2 一个终端任务是「四件套」,不是一道题
这是理解全文的钥匙。按 Harbor 格式,一个终端任务是紧密耦合的捆绑包 T = (I, E, S, V, M):
| 工件 | 目录 | 角色 | 类比 |
|---|---|---|---|
| Instruction(I) | instruction.md | 用户指令 | 考卷 |
| Environment(E) | environment/(Dockerfile、夹具文件、服务) | 初始化环境 | 考场 |
| Solution(S) | solution/solve.sh | 参考解 | 标准答案 |
| Verifier(V) | tests/test_*.py | 可执行验证器 | 评分表 |
| Metadata(M) | task.toml | 运行时元数据 | 考务信息 |
四件套中任何两者不一致,整个任务就作废:考卷里提到的文件考场里没有(I 与 E 不一致)、标准答案假设的 schema 与环境里的不同(S 与 E 不一致)、评分表要检查的状态是任务根本产生不出来的(V 与 S/E 不一致)。
1.3 两大病症:信息丢失与工件漂移
论文把多阶段合成管线的病灶归纳为两条:
病症一:源信息丢失(source information loss)。 丰富的源材料里原本包含能力、依赖关系、中间状态、输入输出契约、过程约束,但一连串生成阶段会像传话游戏一样逐级压缩,最后只剩一句干瘪的任务描述——往往只用到每个技能最表面的功能,产出「浅工作流」。
病症二:工件漂移(artifact drift)。 各工件分头生成时基于各自的隐式假设。在生成阶段之间传递文本规格能缓解,但文本规格不等于已实现的真实状态——指令可以引用一个「计划中有、实际没建成」的文件,验证器可以测一个「规格里写了、实际到不了」的状态。
打个比方:让三位老师分头出考卷、写答案、定评分表,即便发给三人同一份「考试说明」,只要没人真的走进考场核对桌椅,考卷上「请打开桌内的资料袋」就可能落空。FACET 的解法,就是先布置考场、拍照存档,再让所有人对着同一套实景照片工作。
二、核心思想:先盖考场,再出题、写答案、定评分表
FACET(Fine-grained Agentic Construction of Executable Tasks)对上述两大病症各下一味药,外加一道保险:
| 病症 | FACET 对策 | 直觉 |
|---|---|---|
| 源信息丢失 | 代理式场景重建:先把相关技能组合成完整场景,恢复跨技能依赖与中间状态,再生成 | 先还原「一桌宴席」的上菜顺序与共用半成品,而不是把三道菜谱各抄一遍 |
| 工件漂移 | 可执行状态接地:先构建/修复 Docker 环境,把实现的容器态 e₀ 作为 I/S/V 生成的共享参照 | 房子先真装好,卖房文案、验房步骤、收房清单都对着同一套实景写 |
| 残余不一致 | 执行验证 + 定向修复:跑一遍四条验收,按失败溯源只修肇事工件 | 只修肇事零件,不整机返厂 |
形式化地,一个任务被接受当且仅当:
A(T) = B(E) ∧ ¬ν_V(e₀) ∧ (e_T ≠ ⊥) ∧ ν_V(e_T)
翻译成人话:环境能构建成功(B(E))、验证器在「什么都没做」的初始态 e₀ 上不能通过(¬ν_V(e₀),防止白送分)、参考解能从头执行到底(e_T ≠ ⊥)、执行后的终态 e_T 能通过验证器(ν_V(e_T))。这四条合取,就是「四件套对齐」的可执行定义。
这里最值得咀嚼的范式转变是:任务合成的核心参照物,从「写出来的规格」变成了「跑起来的状态」。这与软件工程里「单一事实源」(Single Source of Truth)的思想同构——与其让多份文档努力保持同步,不如让它们都引用同一个不断更新的实体。环境一旦在修复中改了文件名、端口或包版本,所有下游生成器看到的都是更新后的状态,漂移从机制上被掐断。
三、方法拆解:三阶段流水线
3.1 Stage 1 信息源获取:71,341 个技能与场景-技能库
第一步是从 OpenClaw、ClawHub 和 GitHub 收集公开技能包,剔除含不安全指令、依赖私有网站/信息/资源、不可读、不可执行或重复的记录。每个保留技能被规范化为结构化记录(描述、所需工具、输入输出、过程步骤、来源出处),共得 71,341 个有效技能。
接着做场景-技能配对:为每个技能抽取可能的应用情境、用户目标、初始态与期望终态(场景假设),用嵌入检索找到其他技能中的相似假设,组成候选对 (c, X_c),再由模型裁判判断该场景与技能组合是否相关、互补、不冗余、且可作为终端工作流执行,只有全过者进入库。
技能语料的分布相当均衡地覆盖了五大顶级类:多媒体创作与发布 24.42%、AI 与代理工具 21.28%、软件系统与安全 21.11%、数据与分析研究 17.39%、文档生产力与工作流 15.79%(共 34 个细类)。最终 6,078 个验证任务归入九大任务族,各占 9.59%~11.99%——没有哪个类别一家独大,多样性是刻意经营出来的。
3.2 Stage 2 代理式场景重建:五模块 + 五维表示
直接把场景-技能对转成任务工件,会过早压缩信息。Stage 2 因此先通过五个模块渐进式重建场景:
- 技能分析:识别每个技能的能力、工具、输入输出、前置条件与可观察效果;
- 场景探索:提出这些技能能共同服务于某个用户目标的具体应用情境;
- 关联与过滤:留下真正用上这些技能的场景,剔除「不相干操作硬拼盘」;
- 演化与恢复:把选定能力组织成连贯工作流,恢复连接各操作的跨技能依赖、中间产物与状态转移——这是对抗「早压缩」的关键一步;
- 信息扩充:用具体资源、格式、约束与可观察的成功条件充实工作流。
重建结果用五维表示保存:目标(用户目标与交付物)、情境(应用设定与动机)、能力(各技能角色及相互关系)、状态(初始态、中间态、期望终态)、输入输出与工具(所需文件、格式、schema、路径、工具、服务、依赖)。一个模型再把五维整合成完整的自然语言场景 C。
随后的参考构建有个耐人寻味的顺序:先生成解参考 R_S = f_S(C)(记录安装动作、执行流程、中间产物、状态转移、关键步骤),再由 C 和 R_S 共同生成指令参考 R_I = f_I(C, R_S)——先答案后考卷。最后由一致性对齐模型检查:两份参考的初始态与目标一致、指令的每项要求都有解流程支撑、每个要求的效果在终态可观察。
3.3 Stage 3 可执行状态接地构造:Algorithm 1 的四步舞
第一步:环境构建与修复。 一次性生成文件繁多的环境(多文档、数据集、媒体资产、归档、二进制)很不可靠,FACET 把「规划」与「物化」分开:环境代理先产出清单(目录、文件、服务、依赖及预期属性),再在受限基础镜像内物化。物化过程中代理可联网检索公共资源、转换格式、程序化生成文本与二进制资产,但所有资源都被本地化进构建上下文,评测时零联网——保证自包含。为了避免夹具过于模板化,代理还会做受控扰动:给结构化夹具加记录、加元数据字段、加干扰项、加跨文件关系,让可观察状态足够丰富。构建失败(编译错误、缺包、夹具损坏、下载失败、服务起不来)时,失败 trace 连同规格 Z 一起送回环境代理做定向修复,以 Z 为条件是为了防止代理靠砍掉任务需求来换构建通过,至多 3 轮。
第二步:共享状态接地。 环境构建成功后,启动临时容器检视工作区,把实现的初始态 e₀(可用文件、目录、schema、依赖、本地服务)以只读记录的形式暴露给所有下游生成器:
- 指令 I ← (R_I, e₀):指令引用的文件、服务、schema 必然真实存在;
- 解 S ← (I, R_S, e₀):解在同一环境里现场检视后写出;
- 执行 S 得到终态 e_T;
- 验证器 V 最后生成,输入是 (I, R_S, e₀, e_T)——它同时看得见「做之前」与「做之后」的差别,因此检查的是可达的真实状态变化。验证器偏好行为与状态检查而非精确命令匹配,允许其他正确解法通过;时间戳等非确定值会被归一化。
第三步:验证与定向修复。 候选按 Harbor 格式打包(environment/、solution/、tests/、instruction.md、task.toml),在干净容器里跑完整验收:环境能构建、验证器初始态不给过、参考解跑通、终态过验证器。失败时,受限路由器根据执行 trace 定责:构建/初始化失败归环境、解执行失败归解、测试收集或断言缺陷归验证器、指令-状态错配按错配来源归指令或环境——只修被点名的那一件。每次修复后从干净初始态全量重验,至多 5 轮,超预算即弃。
第四步:构建漏斗。 整条流水线的吞吐如下表:
| 阶段 | 数量 | 阶段留存率 |
|---|---|---|
| 场景-技能种子 | 7,852 | — |
| 初始环境构建成功 | 6,630 | 84.56% |
| + 环境修复挽回 874 → 成功环境 | 7,504 | 95.70% |
| 进入任务验证 | 7,446 | 99.23% |
| 首次验证通过 | 2,856 | 38.35% |
| + 任务修复挽回 3,222 → 最终验证任务 | 6,078 | 81.63% |
注意最后一行的反差:首过率只有 38.35%,但定向修复把超过一半的「差一口气」候选救了回来,最终 81.63% 的验证率说明大部分初始失败是单点缺陷而非全局性坏任务——这正是「只修肇事工件」策略的红利。
四、实验设置:怎么证明数据有用
数据与轨迹采集:用 DeepSeek-V4-Pro 驱动的 Terminus-2 代理在约 6K 个验证任务上跑 rollout。6,066 次完成执行中 1,270 次拿到奖励 1,教师成功率 20.94%(注意:任务难是特性不是缺陷)。从中选出 1,200 条完整成功轨迹构成 SFT 集。
微调配置:对 Qwen3.5-4B / 9B / 27B 做全参数 SFT——LLaMA-Factory、8 张 H200、BF16 + ZeRO-3、3 个 epoch、有效 batch 64、学习率 1e-5 余弦调度、最大序列长 32,768 tokens。
评测协议:Terminal-Bench 2.1(容器化任务 + 执行验证),统一 Terminus-2 脚手架,每任务 3 次独立尝试、每次 2 小时超时、温度 1.0,报告平均通过率。
五、主要结果:1.2K 轨迹撬动 7~8 分提升
5.1 数据集对比:测试最密、轨迹最长、任务最难
| 数据集 | 轨迹数 | 平均轮次 | 任务数 | 平均测试数/任务 | P@1 | P@3 |
|---|---|---|---|---|---|---|
| Nemotron-Terminal | 5K | 6.12 | 15K | 6.18 | 40.67 | 48.00 |
| Endless-Terminals | 200 | 4.53 | 2,492 | 5.51 | 83.00 | 87.00 |
| Terminal-Lego | 32K | 5.77 | 15K | 16.60 | 47.00 | 49.00 |
| TerminalWorld | 200 | 11.94 | 1,530 | 3.98 | 57.00 | 82.00 |
| Tmax | 500 | 11.14 | 15K | 3.29 | 80.00 | 86.00 |
| FACET | 1.2K | 11.86 | 6K | 22.77 | 27.00 | 35.00 |
三个信号值得圈点:平均 22.77 项可执行测试/任务,全场最高(次名 Terminal-Lego 16.60)——每个任务独立检查的要求更多、完成标准更严;轨迹均长 11.86 轮,与 TerminalWorld(11.94)同处第一梯队,远高于多数数据集的 4~6 轮,这与场景重建把多个技能串成含依赖的长工作流直接相关;P@1 = 27.00,全场最低——合取判据下,主流程做完但差一条检查就整题算错。三个信号合起来读:FACET 的任务检查密、流程长、通过难,是「难而公平」的任务,而非简单任务。
5.2 SFT 主结果:三个规模全线提升
| 模型 | 规模 | Terminal-Bench 2.1 | 提升 |
|---|---|---|---|
| Qwen3.5-4B → FACET-SFT | 4B | 17.60 → 24.72 | +7.12(相对 +40.5%) |
| Qwen3.5-9B → FACET-SFT | 9B | 27.34 → 35.58 | +8.24(绝对增益最大) |
| Qwen3.5-27B → FACET-SFT | 27B | 40.82 → 47.57 | +6.75 |
| (参照)Qwen3.5-397B-A17B | 397B | 49.06 | 差距仅 1.49 |
用区区 1.2K 条轨迹做 SFT,三个规模一致获益,说明这种监督的迁移不挑容量档位。最有冲击力的是:27B 微调后 47.57,距 397B 的 49.06 只差 1.49 分——模型小了约 15 倍,几乎抹平了规模差距。作为横向参照:同设置下 Qwen3.6-27B 为 53.93、Kimi-K2.6 为 59.93、DeepSeek-V4-Pro 为 73.03、GPT-5.5(xhigh)为 78.00,说明 27B 之上仍有充足上升空间,但「数据杠杆」的效率已经得到充分展示。
5.3 端到端管线对比:产出率高出 42~54 个百分点
在相同 500 个技能对输入、同一生成模型(DeepSeek-V4-Pro)、同一验证评测设施下,对比三条管线:
| 管线 | 完整包 | 验证通过 | 端到端产出率 | P@1 | P@3 | 平均命令数/rollout |
|---|---|---|---|---|---|---|
| Baseline(无场景重建,静态蓝图) | 437 | 78 | 15.6% | 80.8% | 85.9% | 12.8 |
| TW(TerminalWorld 式复现) | 449 | 139 | 27.8% | 58.8% | 64.0% | 17.0 |
| FACET | 395 | 350 | 70.0% | 25.1% | 33.1% | 21.5 |
三个观察:
- 产出率高不等于质量差:FACET 的完整包数量反而最少(395),但验证通过 350 个,产出率 70.0%,比 TW 高 42.2 个百分点、比 Baseline 高 54.4 个百分点。对比管线「文件都生成了、凑不成一致任务」的巨大落差,正说明把四个文件写齐很容易,让它们对齐很难——而 FACET 的价值恰恰在这一步。
- 修复机制真实干活:350 个被接受任务中,182 个首过、168 个靠定向修复挽回,执行反馈把大量「初始不一致」的候选变成了有效任务。
- 高产不是靠放水:FACET 保留下来的任务 P@1 最低(25.1%)、平均命令数最多(21.5 条/rollout),说明它没有把任务简化成短平快的送分题。
六、消融实验:生成顺序里藏着一致性密码
这是我认为全文最精彩的分析。固定 100 个相同的场景-技能对,只改变 I/S/V 三个工件的生成顺序:
- Forward(FACET 采用):环境建好后 I→S→V 顺序生成,验证器最后写、且能看到解执行前后的两个状态;
- Reverse:I→V→S,验证器在解诞生之前就写好;
- Joint:三个工件一次模型调用同时生成。
| 方案 | 到达验证 | 初始有效 | 初始有效率 | 最终产出 |
|---|---|---|---|---|
| Forward | 99 | 46 | 46.5% | 83/100 |
| Reverse | 91 | 22 | 24.2% | 63/100 |
| Joint | 96 | 36 | 37.5% | 65/100 |
更有说服力的是失败类型构成:Reverse 的失败中 56.5% 是跨工件契约错配——没见过解就写评分表,行为对齐自然困难,这从反面印证了「验证器必须接地于真实执行」;Joint 把契约错配压到 13.3%,但失败转移到 38.3% 的夹具/schema/路径接地和 21.7% 的基础设施/依赖问题上——一次调用看似省事,实则失去了顺序生成中逐件核对环境的机会;Forward 的失败分布最分散(契约错配 37.7%),没有哪种错误占主导。
配对比较(88 个三种方案都到达验证的路径):Forward 在 29 个路径上成功而 Reverse 失败,反向仅 9 个,双侧精确符号检验 p = 0.0017,证据很强;Forward 对 Joint 为 27:18(p = 0.233),优势方向一致但不够显著。需要诚实说明的是:三者的修复预算不同(Forward 5 轮、另两者 3 轮),最终产出刻画的是完整管线配置而非同等预算下的修复效率——论文对此的坦白值得肯定。
七、质性分析:难在「最后一公里」,赢在「先看再做」
7.1 任务难在哪:需求满足的完备性,不是主流程
终端任务是合取判据:所有条件都满足才算过。教师 rollout 中,单项检查的通过率高达 89.40%,但整任务成功率只有 20.94%——大量正确进展被二元奖励掩盖了。更细的发现是:失败 rollout 中 54.00% 只差一到两项验证检查(2,590 次近成功试验),典型模式是主产物做出来了、主流程跑通了,却栽在一个残留要求上——字段值不对、约束未满足、次级交付物缺失。
按技能标签看,通过率在 7.14%~35.00% 间波动;结构化数据任务好于叙事文档任务,指令越长、验证器覆盖越宽越难(这些属性彼此相关,论文谨慎地将其定位为描述性特征而非孤立因果因子)。结论:FACET 任务的难度不在执行主流程,而在精确且完整地满足一组相互依赖的要求——密集的可执行验证恰好让这些「最后一公里」错误变得可观察。
7.2 好轨迹长什么样:观察-行动-验证循环
对 1,270 条成功教师轨迹(15,075 个助手轮次、39,136 次命令)的命令级分析揭示了惊人的集中度:cat、python3、ls 三个命令占全部出现的 69.5%,前十命令占 88.4%;观察类命令(读、搜、列目录、检查)占 84.7%。轮次动态上:95.6% 的轨迹以纯观察轮开局;纯观察轮之后 55.6% 还是纯观察(连续多次检查再动手);行动轮之后 53.1% 回到观察(做完就回看),只有 28.7% 连续行动。
这就是清晰的 observe–act–verify 循环:先看、再做、做完回看。成功的终端代理用一套极紧凑的交互界面(查文件、写脚本、验输出)横扫异质任务,而这套行为模式被 1.2K 轨迹有效蒸馏进了 4B~27B 的学生模型——与第五节的成绩单互为印证。
八、讨论与总结:局限、点评与启发
8.1 贡献回顾
- 框架:首个面向异构 agent 技能、以「场景重建 + 状态接地 + 定向修复」三件套组织的终端任务合成框架,产出 6,078 个高密度验证任务;
- 范式:提出可执行状态接地的构造范式,把任务合成从「独立生成貌似合理的组件」转向「围绕共享真实环境构造连贯整体」;
- 证据:生成顺序消融(Forward 46.5% vs Reverse 24.2%,p=0.0017)与端到端对比(70.0% vs 27.8%/15.6%)为设计选择提供了机制层面的解释;1.2K 轨迹驱动三个规模一致提升,验证了监督的数据效率。
8.2 局限与冷思考
教师成功率仅 20.94%,虽证明了「少而精」的数据效率,但意味着每条成功轨迹背后有约四倍失败轨迹的采样成本;跨数据集的 P@1/P@3 对比是描述性的(各管线保留的任务子集不同);TW 是 best-effort 复现,适配器可能引入实现差异;22.77 项检查/任务的「清单式」任务形态是否覆盖了真实终端工作的全部形态(如探索式、开放式任务),仍待讨论。
8.3 我的点评
我喜欢这篇工作的三个地方。其一,它把「一致性」从模型能力问题变成了机制设计问题:不是指望更大的模型一次写对四件套,而是用共享接地让漂移无从发生、用执行验证暴露不一致、用定向修复低成本收敛——这与编译器的类型检查、软件工程的 CI 是同一哲学。其二,Reverse 方案 56.5% 的契约错配是一个漂亮的反面教材:它定量地告诉社区「先写验证器」这条看似高效的路为什么走不通。其三,数据杠杆足够震撼:1.2K 轨迹、三个规模、27B 逼平 15 倍大的模型——在小模型军备竞赛白热化的当下,这条「以数据换规模」的路线图极具实操价值。
对后续研究的启发:状态接地的思想可以自然延伸到 RL(论文自己也把 RL 列为下一步),密集的 22.77 项检查几乎就是现成的密集奖励信号;而「场景重建防早压缩」对一切多阶段合成管线(不只终端任务)都有借鉴意义。
8.4 总结
FACET 用一句话可以收束:终端任务合成的质量瓶颈不在生成能力,而在跨工件一致性;一致性的答案不在更好的文本规格,而在共享的可执行状态。 先建考场、实景接地、按图索骥地修——这套朴素的工程组合拳,换来的是密度最高、最难、也最能教小模型做事的任务集。对于关心 agent 训练数据、合成环境与可验证奖励的读者,这篇论文值得放进 2026 年的必读清单。