Browse this library

Chinese source article

4 · 训练环境与案例:如何教会 Agent 完成长任务

从可复现环境、任务验证器和交互轨迹出发,理解长任务 Agent 的数据构建、强化学习、benchmark 设计与系统横向对照。

View original Markdown ↗

目标、状态、动作和验证闭环定义了部署期行为,训练则要求模型反复经历完整闭环。语言模型在预训练里见过大量文字和代码,却很少真正经历「启动一个隔离环境,连续修改几十次,处理一次失败,再用外部验证器确认结果」的完整过程。SFT 可以展示成功轨迹,强化学习可以根据结果调整策略,两者都依赖一个可运行、可复位、可验证、可复现的任务环境。

训练环境不是装任务文件的容器。对长任务 Agent 来说,它同时定义状态空间、可用工具、动作后果、观察延迟、失败类型和最终 reward。一次 rollout 可以抽象为:

τ=(s0,a0,o1,s1,a1,o2,…,sT),r=V(sT,y,ν),\tau=(s_0,a_0,o_1,s_1,a_1,o_2,\ldots,s_T), \qquad r=V(s_T, y, \nu),

其中 sts_t 是环境在第 tt 步的事实状态,ata_t 是 Agent 动作,ot+1o_{t+1} 是环境返回的观察,yy 是任务目标,VV 是验证器,ν\nu 是环境和验证规则的版本。把版本写进公式并非形式主义。同一段轨迹放到更新后的依赖、网页或测试集里,可能得到不同结果;若没有 ν\nu,失败究竟来自 policy、环境漂移还是验证器改变就无法区分。

1. 长任务环境要提供什么

可用的长任务环境至少包含五个部分。第一是初始状态,包括代码仓库、浏览器账户、文件、服务和依赖版本。第二是动作接口,规定 Agent 能调用哪些工具,以及调用的权限和资源上限。第三是状态转移,动作必须真实改变环境,后续观察能够读回这一变化。第四是终止条件,区分成功、确定失败、超时和基础设施故障。第五是验证器,用任务自身的外部标准检查产物。

环境还必须支持 reset。第一个 rollout 创建的文件、缓存或后台进程若泄漏到第二个 rollout,训练数据就不再独立。最稳妥的做法是从版本化镜像和任务快照启动隔离实例,并把随机种子、网络策略、依赖锁文件、工具版本和任务资源一起登记。涉及实时网页时,完全冻结世界并不现实,此时需要保存关键响应、记录时间窗口,并将网站不可用与 policy 失败分开标注。

Long-Horizon 任务通常比单轮问答占用更多 CPU、内存、存储和墙钟时间。环境层因此直接影响训练吞吐。若一次 shell 调用都要穿过高延迟控制面,大量 rollout 会把算力耗在等待上;若为了追求速度而共享工作区,轨迹之间又会互相污染。工程上需要分别衡量 sandbox 启动时间、单次工具调用延迟、并发成功率、残留资源清理和每条有效轨迹的成本。环境效率应在隔离与真实性成立的前提下,以单位时间产出的可验证轨迹衡量。

1.1. 验证器决定 Agent 会学到什么

长任务的 reward 往往稀疏:几十步结束后,验证器只返回成功或失败。验证器如果过弱,Agent 会找到投机路径。例如只检查某个文件存在,它可能写一个空文件;只依赖字符串匹配,它可能绕过真正功能。验证器如果过窄,又会把等价但正确的实现判错。好的任务验证器应直接检查目标要求的外部性质,并把环境健康、格式要求和功能结果分层报告。

对代码任务,验证器可以组合单元测试、静态检查、构建和隐藏场景;对浏览器任务,可以检查页面或后端的事实状态;对研究任务,可以检查引用、产物结构和可重复计算结果。模型自己的陈述不能替代这些证据。Agent 说「已经完成」只是一个动作候选,真正的 reward 来自环境。

结果 reward rTr_T 还面临 credit assignment。设一条轨迹中有 TT 个动作,最终成功只能说明这些动作的组合有效,无法直接指出第几个动作贡献最大。最简单的 Monte Carlo 回报把同一个结果传播给整条轨迹:

Gt=∑k=tTγk−trk.G_t=\sum_{k=t}^{T}\gamma^{k-t}r_k.

当中间 reward 全为零时,早期动作得到的信号经过折扣后很弱,失败轨迹中的局部正确步骤也一起被否定。可行的改进包括过程验证器、从 checkpoint 分叉多个 continuation、对状态价值做比较估计,以及保留失败轨迹中的有效片段。不过,每一种方法都改变了监督信号的含义。过程 reward 可能把模型训练成迎合检查点;分叉估计更接近同一状态下的反事实比较,却要求环境支持可靠的暂停、复制和恢复。

2. 从轨迹到 SFT 与强化学习

一条轨迹不只是对话文本。它还包含工具调用、工具返回、文件变化、时间信息、错误类型、Harness 内部控制流和最终验证证据。数据管道需要保留足够信息,使训练阶段能够重建「模型当时看见什么、选择了什么、环境随后发生什么」。若只保存最终的自然语言回答,大量与长任务最相关的状态转移都会丢失。

SFT 通常先提供行为起点。成功轨迹让模型学会工具格式、任务分解和基本工作流;经过筛选的失败轨迹也能展示诊断和恢复。问题在于,teacher 轨迹会把 teacher 的 Harness 偏好、工具习惯和冗余步骤一起蒸馏进 student。清洗时既不能只留完美结尾,让模型从未见过失败;也不能把所有日志原样塞进训练集,使基础设施噪声变成行为模板。

强化学习随后让 policy 在环境中生成新轨迹,并用验证结果更新参数。长任务 RL 的难点不只在算法公式,更在 rollout 系统:一次训练 batch 可能对应许多持续数分钟的异步环境,不同 episode 长度差异很大,还会夹杂 sandbox 崩溃、网络超时和验证器故障。训练器必须区分任务失败与系统失败。前者是学习信号,后者若被当成负 reward,会让模型为基础设施问题承担责任。

真实 Harness 也会改变训练分布。部署时的 Harness 可能会压缩上下文、重试工具、插入系统消息、调用多个子进程;若训练时只使用简化的 ReAct 循环,policy 学到的动作节奏与部署环境并不一致。最直接的解决方向是在目标 Harness 内采集 rollout,或者通过稳定的代理层捕获真实消息与工具轨迹。由此得到一个重要判断:训练的是「模型在某个控制系统中的行为」,不能把裸模型和 Harness 当成两个完全独立的阶段。

2.1. 版本与复现:一条轨迹为什么会变质

复现长任务实验,需要同时锁定四层版本:任务数据、环境镜像、Harness 与工具、模型与训练配置。仅记录 checkpoint 名称不够。一个 CLI 升级可能改变工具 schema,一项网页更新可能让旧任务失效,一个依赖的小版本变化也可能改变测试结果。实验记录应至少包含任务标识、镜像摘要、仓库提交、Harness 版本、工具权限、随机种子、最大步数或时间预算,以及验证器版本。

轨迹本身也要有可演化的 schema。消息列表、tool call、观察内容、截断规则和 reward 证据应被显式版本化。否则 Harness 升级后,旧解析器可能悄悄错位:看似读到了全部对话,实际把一次工具返回归给了错误动作。这个问题很危险,因为训练过程仍然可以运行,只是监督数据已经失真。

可复现并不要求每次执行逐 token 完全一致。带采样的 policy、实时网站和并发系统本来就会产生方差。更合理的要求是:初始条件和规则能够恢复,实验差异能够定位,统计口径能够重复计算。对于需要比较的系统,应使用相同任务版本、相同资源预算和相同验证器,再报告多次运行的分布,而不是只挑一条成功轨迹。

3. Benchmark 应该测量哪一种能力

长任务 benchmark 需要把「持续推进」变成可观测量。最终成功率仍然重要,但它不足以解释失败。至少还应记录完成时间、工具步数、有效进度、验证次数、失败后恢复率、上下文或 token 成本,以及环境故障比例。对于允许多次尝试的任务,还要明确使用 pass@k、独立尝试成功率还是要求连续成功的更严格指标;这些口径回答不同问题,不能只看数值大小混在一起排序。

横向对照时应把模型、Harness、环境和预算视为四个变量。更强的 Harness 可能提高同一模型的成绩,更多工具调用也可能换来更高成功率。若两个系统使用不同终止条件、不同网络访问权限或不同时间预算,榜单差距无法直接归因于模型能力。一个有解释力的对照矩阵应尽量包括:

对照轴 需要固定或报告的内容 主要回答的问题
Policy 模型、checkpoint、采样设置 模型策略本身改变了什么
Harness 控制流、上下文策略、工具封装 系统编排贡献了什么
Environment 镜像、状态、网络、依赖 任务条件是否一致
Budget 时间、步骤、token、重试次数 成功率是否用更多资源换来
Verifier 版本、成功条件、异常处理 分数是否具有相同含义

Benchmark 还应包含能够暴露错误传播的任务。只需要一次工具调用的题目,即使运行很久,也难以测出状态维护能力。更有价值的任务会让早期决策影响后续状态,要求 Agent 发现中间错误、重新规划,并在最终提交前完成独立验证。这样得到的失败轨迹,才真正提供 Long-Horizon 的研究信号。

4. 验证器的可靠性也要单独测

把验证器当作 reward 来源以后,它本身便成为学习系统的一部分。可以用两个条件描述它的质量。健全性要求验证通过的产物确实满足任务目标:

Pr⁡(Y=1∣V=1) 足够高;\Pr(Y=1\mid V=1)\ \text{足够高};

完备性要求真正正确的产物不会因实现路径不同而被大量拒绝:

Pr⁡(V=1∣Y=1) 足够高.\Pr(V=1\mid Y=1)\ \text{足够高}.

YY 表示经过更强审计得到的真实正确性,VV 是训练时验证结果。健全性差会鼓励 reward hacking,完备性差会压制有效探索。二者无法靠验证器在自身任务上的通过率估计,需要人工构造正例、合理替代实现和对抗样例,再测混淆矩阵。

长轨迹还会放大验证器泄漏。如果测试名称、错误消息或隐藏输入的结构稳定暴露给 policy,模型可能逐渐学习针对检查器,而没有获得可迁移能力。环境应控制返回信息的粒度:诊断信息要足够支持修复,又不能直接泄漏隐藏答案。一个实用对照是替换等价验证器或改变输入生成方式;成绩若大幅崩塌,原策略很可能绑定了验证表面。

验证器版本升级后,旧 reward 也不能直接与新 reward 混合。旧版漏检的轨迹在新版下可能失败,新版新增的合法实现又可能让旧失败样本转为成功。训练数据需要记录 ν\nu,并在合并前重放可重放的轨迹;无法重放的样本只能保留原口径,不能伪装成同一标签空间。

4.1. 超时会造成删失偏差

长任务评测常用固定墙钟或最大步数。到达上限的轨迹只说明「预算内没有完成」,无法断言继续执行也不会成功。统计上这属于右删失。若把全部超时记作普通失败,动作更慢但最终更稳的系统会受到额外惩罚;若忽略超时样本,又会高估成功率。

因此应同时报告固定预算成功率与完成时间分布。对于成功轨迹,记录终止时间 TT;对于超时轨迹,只知道 T>BT>B。比较系统时可以画出随预算增长的累计成功曲线

S(B)=Pr⁡(T≤B),S(B)=\Pr(T\le B),

而不是只选一个截止点。曲线能够区分「很快完成一部分任务后遇到能力上限」与「成功率仍随更多预算稳步增长」。工具步数、token 和墙钟也要分别报告,因为等待远程服务会拉长时间,却未必消耗更多模型推理。

环境故障造成的删失要另设标签。sandbox 崩溃、网络中断或验证器异常既不能算 policy 失败,也不能悄悄从分母删除。报告有效 episode 数、基础设施故障率和重试规则,才能看出高分是否依赖筛掉大量困难运行。

预算曲线还要配合任务难度分层。若简单任务很快饱和、困难任务始终为零,把两者平均后可能得到一条缓慢上升的曲线,误以为系统正稳定改善。按初始依赖深度、必要工具数、不可逆动作数和环境变化次数分桶,才能定位新增预算究竟解决了等待问题、搜索问题,还是根本没有触及长程状态维护。

4.2. 两个案例如何拼成一条训练链

OpenForge RL 关注的是如何在接近部署态的真实 Harness 中获得轨迹,并把外部控制流接入训练器。它让研究者看到,训练—部署落差不只是 prompt 不同,还来自工具封装、消息转换、并发过程和 Harness 自己的决策。通过代理捕获模型调用与环境交互,可以在不重写完整 Harness 的前提下重建训练轨迹,同时也带来了轨迹完整性和版本契约的新要求。

Orchard 把重心放在可复用的环境基座:隔离 sandbox、稳定的环境接口、不同任务 Recipe 与训练系统之间的边界。它说明环境不应只是某个实验脚本的附属品。只有环境生命周期、状态读写和验证协议足够稳定,SFT 数据、RL rollout 和最终评测才可能共用同一套事实基础。

两者组成一套长任务训练栈:Orchard 一类环境层提供可复位的真实世界,OpenForge RL 一类适配层让真实 Harness 进入 rollout,训练器根据任务验证器返回的 reward 更新 policy,评测继续沿用同一版本化协议。checkpoint、审计和进度验证在部署期保证可靠执行,在训练期提供更细的 credit assignment 和可复现实验。

这一章最终想建立的尺度很简单:看到一个 Long-Horizon 成绩时,不只问「用了哪个模型」,还要追问任务怎样初始化、Harness 怎样运行、轨迹怎样记录、reward 由谁验证、系统故障怎样剔除、预算是否一致,以及别人能否恢复同样的实验条件。只有这些问题有明确答案,长任务能力才从一次漂亮演示变成可以训练、比较和积累的研究对象。