Browse this library

Chinese source article

4.1.1 · OpenForge 轨迹与训练接口

拆解部署 Harness 中的轨迹生成、环境规范、课程设计和策略版本约束。

View original Markdown ↗

论文:OpenForge RL: Train Harness-native Agents in Any Environment 作者:Xiao Yu, Baolin Peng, Ruize Xu, Hao Zou, Qianhui Wu, Hao Cheng, Wenlin Yao, Nikhil Singh, Zhou Yu, Jianfeng Gao(Columbia / Dartmouth / Microsoft Research) arXiv:2607.21557(2026-07,ICLR 2027 under review) PDF:content/uploads/papers/openforge-rl.pdf GitHub:MSR-Orchard/OpenForge-RL 环境层:microsoft/Orchard

1. 在部署 Harness 中生成训练轨迹

简化 rollout 与真实部署的失配,当代 SOTA Agent 的能力越来越来自 inference harness——Claude Code、Codex、OpenClaw、ZeroClaw 等 orchestration 层管理多轮交互、工具调用、上下文与 MCP 接入。然而开源 SFT/RL 栈通常假设简化的单进程 rollout:固定 chat template、无子 agent、无 harness 特有控制流。

这造成 train–deploy mismatch(训练–部署失配):在简化环境里训出的 policy,部署到真实 harness 时,工具 schema、上下文管理、子 agent 路由、错误恢复语义都可能不同——Orchard 论文已展示:OpenSWE-32B 换到从未见过的 Kimi-CLI harness 时 SWE-bench Verified 从 45.0 崩到 3.6。OpenForge RL 的核心问题是:能否在 Agent 实际部署的 harness 里做端到端 RL,且与任意 RL 训练后端(如 veRL)解耦?

Proxy 与 K8s Orchestrator,OpenForge RL 由两个正交组件构成:

1.1. Lightweight Proxy:轻量代理

  • 插入 harness 与推理服务之间,Serving harness 发起的全部 LLM/VLM 调用。
  • 将请求路由到 RL 框架的 inference engine(训练中的 policy)。
  • 记录 io-pair,在 rollout 结束后重建为 (s₀,a₀,r₀, …, s_T,a_T,r_T) 轨迹,供 veRL / slime 等标准 RL codebase 消费。
  • 关键性质:不修改 harness 内部逻辑——换 harness 只改 sandbox 镜像/启动命令,不改 trainer。

K8s Rollout Orchestrator 的编排职责包括:

  • 每个 rollout 在独立远程容器中运行(与 Orchard Env 集成)。
  • 容器预装目标 harness(OpenClaw、ZeroClaw、Codex、Claude、Pi、OpenCode、Hermes 等)及任务环境(Terminal、Web、Computer Use)。
  • 训练与 rollout 物理解耦:rollout 占 CPU 容器,policy 更新占 GPU 节点——可 scale 0 → 数千并行 sandbox。

整体数据流:

Trainer (veRL, GPU)  ←── trajectories ──  Proxy (intercept & collect)
       │                                      ↑
       └── generation requests ──────────────┘
                                              │
                         Orchestrator → Sandbox Pod × N
                                      (真实 Harness + Environment)

数据合成(Claude Agent SDK + Opus 4.6) 五阶段 pipeline:Propose → Refine → Implement → Verify → Package,并行生成 Claw / GUI 域任务;SFT pool 经 benchmark 去重与流行网站过滤。

仓库提供两条 Recipe:

Recipe Backbone 训练数据 评测 harness
OpenForge-Claw Qwen3-30B-A3B-Thinking ~0.2K–2.6K 合成 Claw 任务 ZeroClaw / OpenClaw / Codex / ReACT
OpenForge-GUI Qwen3-VL-8B SFT + RL(~2.5K 任务) 纯 screenshot 输入的 computer-use

Claw、GUI 与跨 Harness 结果,OpenForge-Claw(30B-A3B) — ClawEval / QwenClawBench / MCPAtlas:

阶段 ClawEval pass@3 QwenClawBench MCPAtlas
Qwen3-30B-A3B-Thinking 基线 39.8 21.8 12.4
OpenForge-Claw (SFT) 52.1 32.1 23.6
OpenForge-Claw (SFT+RL) 55.9 33.7 28.1

对比同量级开源:Qwen3-32B pass@3 31.7 / MCPAtlas 22.5;LLaMA-4-Scout pass@3 16.8。距 Claude Opus 4.6(ClawEval pass@3 80.8)仍有巨大 gap,但 SFT+RL 一致提升。

Harness 迁移(ClawEval pass@1) — 训练多 harness vs 单 harness:

模型 ReACT* ZeroClaw OpenClaw Codex
Qwen3-30B-A3B 基线 26.1 32.5 11.4 12.2
OpenForge-Claw (SFT+RL, 三 harness 训练) 45.1 48.5 20.9 32.5

单 harness 训练已泛化到未见 harness(ZeroClaw-only → OpenClaw +3.3、Codex +4.6);三 harness 联合训练全面最优,复杂 harness(OpenClaw、Codex)增益最大。

OpenForge-GUI(8B) — pass@1:

阶段 OSWorld-Verified Online-Mind2Web WebVoyager
Qwen3-VL-8B 29.4 38.7 49.2
OpenForge-GUI (SFT) 34.4 57.4 61.5
OpenForge-GUI (SFT+RL) 37.7 63.0 72.3

亮点:仅 2.5K 任务训练,Online-Mind2Web 63.0 超过 MolmoWeb-8B(35.3,200K+ 任务);WebVoyager 72.3 接近 UI-TARS-1.5-7B(66.4)。论文强调:在真实 deployment harness 里训练,样本效率显著高于简化栈上的大规模 SFT。

RL 行为分析(ClawEval):SFT→RL 后,generic shell 工具调用占比下降(22.6% → 13.9%),转向专用 service tools;self-verification、format robustness、tool coverage、step efficiency 等行为维度 SFT+RL 全面高于 SFT;error recovery 仍弱——RL 主要提升 reliability,非全能。

训练资源:Claw RL ~48H(8×B200 policy + Azure rollout VM);GUI browser-use ~32–36H。

Discussion 三章结论(Section 5) 对 harness 研究有直接指导意义:

  • Q1:哪个 harness 更难学? Codex / OpenClaw 等多进程、强工具编排的 harness 显著难于 ReACT* 简化栈——同样的 SFT+RL 预算下,复杂 harness 上的绝对分更低,但 RL 相对增益更大。
  • Q2:跨 harness 迁移? 在 ZeroClaw 上训练已能提升未见 OpenClaw / Codex 表现;三 harness 联合训练是 Pareto 最优——说明 policy 学到的是 partially harness-agnostic 的 agentic skill,而非 memorizing 单一 CLI 语法。
  • Q3:RL 加了什么? 主要是 reliability(self-verification、专用工具覆盖、步数效率),而非 error recovery——后者在 SFT+RL 后仍接近随机,暗示需要 failure-centric curriculum 或显式 recovery reward。

Claw 域 RL 超参(Table A1 摘要):lr 1e-6、batch 8、group 8、KL 0.001、max rollout 900s/step、100 training steps;GUI browser-use lr 1e-6、group 5、KL 0、entropy 0.001。Rollout pod 2–4 CPU / 2–6 GiB RAM——刻意 Small footprint 以提高并发。

1.2. 复现成本与适用边界

  • 完整复现门槛高:核心实现虽已公开,训练仍依赖 Orchard Env、Kubernetes、veRL 与成规模的推理资源,单机很难复现论文吞吐。
  • 任务规模小:Claw ~2.6K、GUI ~2.5K,泛化边界未充分探索。
  • Proxy 假设:要求 harness 所有 LLM 调用走可拦截 API;本地嵌入式模型或硬编码路径可能漏采。
  • Error recovery 瓶颈:RL 后仍弱,可能需要 dedicated failure-centric 数据。
  • 闭源 SOTA gap:距 GPT-5.4 / Claude Opus 4.6 在 OSWorld(75.0 / 72.7)仍差一个数量级。
  • 成本结构:每 rollout 一容器,虽比 managed sandbox 便宜(Orchard Env spot 约 0.10×),但 RL 需要海量 rollout,总成本仍可观。

OpenForge RL 在 Orchard 三层栈中位于 Recipe 层,依赖 Orchard Env 提供环境基础设施。数据按下面的方向流动:

层 组件 职责
Recipe OpenForge RL Proxy + 数据合成 + veRL 训练循环
Foundation Orchard Env K8s sandbox REST API、in-pod agent、网络隔离
Trainer veRL / slime Policy 优化、inference engine

Rollout 生命周期,1. Orchestrator 按任务 spec 启动 sandbox Pod(2 CPU / 2–6 GiB,任务 Dockerfile + harness 预装)。 2. Harness 在 sandbox 内驱动多轮 agent↔environment 交互;每次 LLM 调用经 Proxy 转发到 trainer 的 inference server。 3. Proxy 记录 (prompt, response, metadata);episode 结束信号触发 trajectory reconstruction。 4. Trainer 消费轨迹做 PPO/GRPO 等更新;新 policy 权重同步回 inference server,进入下一批 rollout。

与 Orchard 原有三 Recipe 关系:Orchard-SWE/GUI/Claw 是「Env + 简化/固定 harness」路线;OpenForge RL 是后续工作,把 harness 本身换成部署态真实栈(ZeroClaw、OpenClaw、Codex),专门消除 mismatch。

2. 可启动的环境规范

OpenForge RL 的数据合成流水线产出一份可以启动的环境规范,自然语言题目只是其中一项。对每个任务,至少需要固定以下对象:

  • 初始状态:sandbox 镜像、目录内容、账户或页面状态、依赖版本和预置服务;
  • 动作空间:Harness 能暴露给 policy 的 shell、文件、浏览器、MCP 与领域工具,以及各工具的参数 schema;
  • 目标描述:Agent 可以看到的任务文本和不能泄漏给它的隐藏验收条件;
  • 终止规则:成功提交、达到时间或步数预算、Harness 主动停止、环境崩溃分别怎样编码;
  • 验证器:从最终环境读取什么事实,怎样区分成功、任务失败和基础设施异常。

初始状态必须可重建。若任务要求修复仓库,镜像摘要、代码 commit 和依赖锁文件应一起记录;若任务发生在网页,登录态、页面版本和后端数据也属于状态。只保存一段 prompt,几周后重新运行时得到的已经可能是另一道题。环境生成阶段的 Verify 因而有两层含义:它既要确认任务可完成,也要确认验证器能从干净初态判失败、从参考完成态判成功。

动作空间同样影响任务难度。给 Agent 一个领域专用工具,与只给通用 shell 后让它自行调用 API,并不是同一实验。Proxy 虽然能够看到 LLM 请求和响应,却未必自动掌握 Harness 内部的所有确定性动作。因此轨迹清单需要标出:哪些动作由 policy 直接生成,哪些由 Harness 按规则插入,哪些环境变化来自外部事件。缺少这层区分时,训练器可能把 Harness 的固定行为误算成模型 action。

从 Harness 日志重建可训练轨迹,一次真实 Harness rollout 可能包含多轮 LLM 调用、子进程、上下文压缩和工具返回。Proxy 记录的基本单元是调用时模型真正看到的输入 xtx_t 与生成的输出 ata_t。训练轨迹还需要把它们与环境观察和 episode 身份对齐:

τ={(k,t,xt,at,ot+1,mt)}t=0T−1,\tau=\{(k,t,x_t,a_t,o_{t+1},m_t)\}_{t=0}^{T-1},

其中 kk 是 rollout 标识,tt 是逻辑顺序,ot+1o_{t+1} 是动作后的环境观察,mtm_t 保存 Harness、工具和截断等元数据。多进程 Harness 不能只依赖日志到达时间排序,因为并发请求可能交错;重建器需要稳定的 episode、parent call 和 sequence 标识,才能恢复每条分支实际看到的历史。

训练时还要明确 logits mask。系统消息、用户任务和工具返回构成 state,只为模型生成的 token 计算 policy loss;Harness 自动拼接的模板或确定性路由不应被当成模型选择。若消息经过上下文压缩,Proxy 应记录压缩后的真实输入,同时保留压缩器版本。否则训练数据声称模型根据完整历史做出动作,实际部署时它看到的却是另一份摘要。

轨迹终点需要绑定验证证据。Harness 退出和模型输出「完成」都只能标记执行流程结束;reward 由验证器重新读取环境后给出,例如执行测试、查询后端状态或检查目标页面。episode 最终可被标成 success、task_failure、timeout、environment_error 和 verifier_error。后两类通常不应直接作为 policy 的负样本,因为模型未必有机会影响它们。

最终奖励、过程进度与一个小型手算,OpenForge RL 强调 task-native verifier。最干净的终局奖励可以写成:

rT=1[V(sT)=success],rt=0  (t<T).r_T=\mathbb{1}[V(s_T)=\text{success}], \qquad r_t=0\;(t<T).

它回答的是最终任务有没有完成。过程进度则描述中间状态离验收条件还有多远,例如通过了多少个独立测试、是否建立了正确资源、是否完成必要的自检。过程进度适合诊断和构造辅助信号,却不能自动冒充最终奖励:通过四个测试中的三个,不一定代表任务完成了四分之三,其中一个失败可能正好暴露核心功能缺失。

考虑同一任务采样四条轨迹,最终验证结果为 [1,0,1,0][1,0,1,0]。组内平均奖励为

rˉ=1+0+1+04=0.5.\bar r=\frac{1+0+1+0}{4}=0.5.

若使用最简单的组内中心化优势,四条轨迹得到

Ai=ri−rˉ=[0.5,−0.5,0.5,−0.5].A_i=r_i-\bar r=[0.5,-0.5,0.5,-0.5].

成功轨迹中的 policy action 被提高概率,失败轨迹中的 action 被降低概率。现在假设第二条轨迹已经通过三个过程检查,但最终验证失败;它的终局奖励仍是 00,优势仍为 −0.5-0.5。这三个检查可以作为分析字段,也可以在经过论证后加入 shaped reward,例如 ri′=ri+λpir'_i=r_i+\lambda p_i。然而只要 λ>0\lambda>0,优化目标就改变了:policy 可能学会积累容易通过的中间项,却不完成收尾阶段的关键条件。

再看第四条轨迹。Sandbox 在验证前崩溃,这属于 environment_error;若仍记成 00,它同样得到 −0.5-0.5,模型会为系统故障受到惩罚。该样本应从有效 reward 组中剔除或重新 rollout。剩下三条有效轨迹的均值变为 2/32/3,相应优势也要按实际采用的归一化规则重新计算。这个小例子说明:奖励计算之前,先把终局事实、过程进度和系统异常分开。

若 reward 只在终点出现,长轨迹仍有 credit assignment 困难。给整条 response 序列分配同一个 episode advantage 是常见近似,但它无法指出某次工具选择究竟好在哪里。OpenForge 的行为分析表明 RL 提升了 self-verification、工具覆盖和步数效率,却没有同等解决 error recovery。这与终局奖励的性质一致:成功样本能强化一整套可靠行为,稀少的失败恢复片段却难以得到清晰、稳定的局部信号。

2.1. RL 更新与异步 rollout 的边界

在一次训练迭代中,trainer 固定 policy 版本,Orchestrator 启动一批 sandbox,Harness 经 Proxy 请求生成,验证器给出 episode reward,随后 trainer 才用这些轨迹更新参数。无论底层采用 PPO、GRPO 还是其他 on-policy 变体,都需要知道每条 action 是由哪个 policy checkpoint 生成的。若 rollout 持续时间差异很大,而新旧 policy 的轨迹混入同一 batch,重要性比率和组内比较的含义都会变得含糊。

因此,轨迹元数据至少要含 policy_version、采样参数、Harness 版本、任务版本和 reward 版本。异步系统可以容忍不同 episode 在墙钟时间上交错,但不能让样本来源不可追踪。训练器也要分别统计有效轨迹率、环境失败率和验证器失败率;只报告 GPU 利用率或总 rollout 数量,会掩盖大量不能用于更新的坏样本。

真实 Harness 训练还有一个选择性偏差:特别长或频繁失败的 episode 更容易超时,最终进入 batch 的可能主要是短轨迹。如果不报告长度分布和截断原因,policy 看起来在改善,实际上训练数据可能逐渐偏向简单任务。对长任务而言,max rollout 是实验条件,也是改变数据分布的过滤器。

泄漏、不可复现与判定器错误,合成任务最直接的泄漏来自 benchmark 本身。若生成模型能看到评测任务、参考实现或隐藏测试,再通过改写进入训练池,最终分数无法说明泛化。论文的数据流水线包含 benchmark 去重;复现时还应在任务文本、代码片段、网站目标和验证逻辑多个层面检查近重复,不能只比较标题字符串。验证器源代码若直接暴露在 Agent 可读目录里,也可能诱导 policy 针对检查条件投机,而不是完成真实目标。

不可复现通常来自环境漂移。容器标签指向了新镜像、网站内容更新、MCP server 升级、依赖下载到不同版本,都会改变状态转移。每个任务包应记录内容寻址的镜像摘要、资源校验和、网络策略、Harness commit、工具 schema 与验证器 commit。若必须依赖实时服务,至少要记录执行时间和关键响应,并把服务不可用单独计数。

判定器也会犯错。假阳性把未完成任务判成功,会直接奖励投机行为;假阴性把正确的等价解法判失败,会压低合理策略。发布 benchmark 前,可以让参考解、已知错误解和一组扰动解共同经过 verifier:参考解应稳定通过,缺关键功能的扰动解应稳定失败,重复执行不应因残留状态改变结果。对 GUI 任务,只看最终截图往往不够,后端状态或可访问性属性能提供更稳定的事实。

一套可执行的评测协议,要验证「Harness-native 训练」而不是其他变量带来的提升,可以按以下协议组织实验:

  1. 冻结任务包:给每个任务固定初始快照、动作权限、终止条件和 verifier 版本,并清理与训练池的近重复项。
  2. 固定 policy 条件:比较系统使用同一 backbone、checkpoint、采样参数和上下文预算;若训练后模型不同,则另设推理 Harness 消融。
  3. 建立 Harness 矩阵:至少包含训练中出现的 Harness 和未见 Harness;记录各自工具 schema、上下文策略和自动重试行为。
  4. 隔离 rollout:每次从干净 sandbox 启动,保存 policy、任务、镜像、Harness 和 reward 的版本标识,禁止上一条轨迹残留状态。
  5. 运行外部验证:Harness 退出后由独立 verifier 检查环境;将任务失败、超时、环境错误和 verifier 错误分开。
  6. 报告共同预算:除 pass rate 外,同时报告有效 episode 数、墙钟时间、token、工具步数、截断比例和每个成功任务的成本。
  7. 检查恢复能力:单列需要从失败中恢复的任务,不用总体成功率代替;OpenForge 的分析已经提示这一维仍弱。
  8. 保存可复算产物:保存任务清单、去重方法、轨迹 schema、版本 manifest 和逐任务验证结果;公开代码仍不足以替代论文未提供的完整训练资源与运行记录。

这套协议不要求所有系统内部实现相同。它要求共同控制的变量真正一致,并把无法控制的差异完整报告。只有这样,三 Harness 联合训练的收益、未见 Harness 迁移和 RL 带来的可靠性变化,才能与额外预算、环境差异或判定器偏差区分开。

2.2. Train-deploy mismatch 是怎样产生的

真实 Harness 会改写模型实际面对的决策过程。它决定 system prompt 怎样拼接、工具如何命名、历史何时压缩、错误会不会自动重试,也决定一次模型输出之后环境返回什么。训练时若用一个简化 ReAct loop,部署时换成 Codex 或 OpenClaw,表面上仍是同一个模型,状态空间与动作空间却都变了。

可将部署 Harness 诱导出的轨迹分布记为 dHdπd_{H_d}^{\pi},训练 Harness 的分布记为 dHtπd_{H_t}^{\pi}。某个策略在训练分布上的期望回报为:

JHt(π)=Eτ∼dHtπ[R(τ)].J_{H_t}(\pi)=\mathbb{E}_{\tau\sim d_{H_t}^{\pi}}[R(\tau)].

部署时真正关心的是 JHd(π)J_{H_d}(\pi)。两者差异来自 Harness 对状态、动作与转移的共同改写,不能只用「prompt 有点不同」概括。举个具体例子:训练 loop 把工具错误原样返回,部署 Harness 却会自动重试两次再压缩错误;模型在训练中学到的恢复动作,部署时可能接收到另一种观察,甚至没有机会看到第一次失败。

动作 schema 也会制造错位。训练环境把写文件表示为 write(path, content),部署环境可能要求 patch、基线哈希和权限确认。策略即使理解任务,也可能因格式不适配而无法行动。OpenForgeRL 让真实 Harness 自己构造上下文并解析调用,Proxy 只拦截它原本就会发出的模型请求,这才保留了部署时的接口语义。

多 Harness 训练可以看成在多个分布上共同优化:

J(π)=∑h∈Hλh Eτ∼dhπ[Rh(τ)],J(\pi)=\sum_{h\in\mathcal H}\lambda_h\,\mathbb{E}_{\tau\sim d_h^{\pi}}[R_h(\tau)],

其中 λh\lambda_h 控制各 Harness 的采样比例。若简单 Harness 便宜、成功率高,它可能占据大部分有效轨迹,策略随后偏向容易解析的工具格式。训练调度器需要同时观察任务域、Harness 与结果分桶,避免总样本数很大,复杂 Harness 却几乎没有产生可用更新。

Proxy 拦截面与轨迹忠实度,官方仓库把 recording proxy 放在 Harness 与 OpenAI-compatible endpoint 之间,这个位置能看到每次模型请求与响应,却看不到所有环境变化。Harness 可能在两次模型调用之间自动裁剪历史、执行确定性重试、启动子进程,甚至按规则补上一条工具消息。轨迹重建器必须明确哪些事件来自 policy,哪些来自 Harness。

一条可训练记录至少需要如下标识:

episode_id / parent_call_id / sequence_id
policy_version / harness_version / task_version
messages_seen_by_model / sampled_tokens / sampling_config
tool_call / tool_result / termination_reason
reward_version / verifier_result / infrastructure_status

messages_seen_by_model 应保存请求发出时的真实消息,而非事后从完整日志推测。若 Harness 在请求前做过 compaction,训练就应使用压缩后的输入;把被删历史重新塞回样本,会让优化器学习一个部署时不存在的条件分布。sampled_tokens 还要配套 logits mask,只给 policy 真正生成的 token 计算损失,不能把 Harness 模板和工具返回当成模型答案。

多进程 Harness 对顺序提出了更高要求。日志到达 Proxy 的墙钟顺序不一定等于因果顺序;两个子进程可能并行请求,各自依赖不同父调用。只靠时间戳拼接,会产生一条现实中从未出现过的对话。parent_call_id 与局部序号用于恢复调用树,训练器随后选择保留分支结构,或按清楚定义的规则切成多条样本。

轨迹忠实度可以用三项检查:请求重放后消息哈希一致;动作在相同 checkpoint 上能复现相同工具调用;终局 reward 能由独立 verifier 重算。三项分别覆盖输入、转移和结果。任一项失真,RL 都可能稳定优化错误的数据。

Rollout 吞吐如何手算,远程 sandbox 把 CPU 侧执行与 GPU 侧更新解耦,但 GPU 不会因此自动满载。设平均一条轨迹有 LL 次模型调用,每次生成占用 GPU 时间 tgt_g,环境与工具等待为 tet_e,sandbox 启动为 tst_s。单条轨迹墙钟时间约为:

Tepisode=ts+L(tg+te).T_{episode}=t_s+L(t_g+t_e).

若并发 sandbox 数为 NN,理想吞吐接近 N/TepisodeN/T_{episode};实际还受 Proxy 排队、推理动态批处理与长尾任务影响。假设 ts=20st_s=20s,L=12L=12,tg=2st_g=2s,te=8st_e=8s,单条轨迹约需 140s140s。100 个 sandbox 的理想吞吐约为每分钟 42.9 条。若环境等待翻倍,吞吐降到约每分钟 23.1 条,GPU 可能在两轮请求之间空转。

扩大 NN 也有上限。推理服务饱和后,排队时间进入 tgt_g;Kubernetes 启动大量 Pod 会争抢镜像、CPU 和网络;某些实时网站还会限流。工程上应同时观测 sandbox 启动 P50/P99、Proxy 队列深度、有效轨迹率、GPU token 吞吐和环境错误率。只有 GPU 利用率很高而有效轨迹率很低,意味着算力正在认真学习一堆坏 episode。

长尾决定训练同步点。若 trainer 等整批 rollout 全部返回,最慢的少数任务会阻塞更新;若提前截断,又会系统性丢掉复杂长任务。可以采用有界异步窗口:每个样本携带 policy_version,只接受落后不超过阈值的轨迹;超出阈值则重新采样或使用明确的 off-policy 修正。阈值越宽,硬件越忙,数据与当前策略的偏差也越大。

3. Harness 选择与课程设计

论文显示 Codex、OpenClaw 一类复杂 Harness 更难学,RL 的相对增益又更明显。这提示课程不能只按任务难度排序,还要按 Harness 难度分层。一个任务在 ReAct* 下可能很简单,换到包含上下文管理、专用工具和多进程路由的 Harness 后,失败点已经变化。

训练初期可以让策略先学会稳定格式和基本工具闭环,再增加长轨迹、错误恢复与复杂 Harness;但不能长期停留在简化 loop,否则错位会被重新带回来。更可靠的课程单位是 (task, harness, failure_mode):同一任务分别在工具缺失、响应超时、局部成功和验证失败下采样,明确观察策略能否把失败转成下一步动作。

error recovery 仍弱,也说明成功轨迹不够。终局奖励能强化顺利完成的行为,却很少告诉模型如何从半途故障回来。可以从真实失败 episode 截取「故障出现到恢复完成」的片段,构造带初始 checkpoint 的 recovery task;也可以让环境确定性注入超时、旧文件和工具返回畸形。验证仍以最终环境为准,不能奖励模型写出一段漂亮的反思。

多 Harness 课程还要防止表面迁移。策略可能只是记住多套工具别名,并没有学到共享能力。未见 Harness 评测应选接口、上下文策略和自动恢复机制都不同的系统,同时报告格式错误、工具选择、计划完成和错误恢复等细分行为。若只在工具名称相近的 Harness 上得分提升,泛化结论要收窄。

Reward 管线的失败模式,Reward 从 verifier 到 trainer 之间还有一条数据管线。Reward 一旦绑定到错误 episode,训练会在没有报错、损失正常下降的表象下学习随机标签。episode_id 复用、超时回执晚到或任务重试覆盖旧记录,都可能让一个成功结果落到另一条轨迹上。

因此 reward 记录应同时绑定 episode、任务版本、初始 checkpoint、最终状态哈希和 verifier 版本。Trainer 消费前再检查这些字段,与轨迹 manifest 不一致的样本进入隔离队列。二元成功率之外,还要统计 task_failure、timeout、environment_error、verifier_error 与 invalid_trace,只有确实反映 policy 行为的结果才能参与优势计算。

判定器投机同样会在 RL 中被放大。只检查文件存在,策略会学会创建空文件;只检查页面出现某段文本,策略可能把文本写进无关区域。对每个 verifier,可以准备参考解、缺关键步骤的错误解和扰动解,验证它能区分三者。训练过程中还应抽样人工复核高奖励轨迹,尤其关注回报突然上升而外部质量没有同步改善的阶段。

过程奖励需要克制。若一条任务含五个检查,四个容易、一个决定成败,按通过比例给 reward 会鼓励策略反复收割容易项。更稳妥的方式是把过程信号用于课程采样与诊断,终局硬条件仍决定成功;确需 shaping 时,权重、上限和消融结果都应报告,使读者能判断增益来自完成任务,还是改变了评测目标。

从研究数字到部署决策,OpenForgeRL 的结果证明真实 Harness 可以进入开放训练栈,也显示数千任务已经能带来明显提升,但它没有替团队回答「该训练哪一个 Harness」。部署选择要看现有工具生态、权限模型、可观测性和维护成本。一个基准分稍高却无法稳定记录轨迹的 Harness,可能不适合持续训练;一个较简单但接口稳定、验证充分的 Harness,反而更容易形成数据飞轮。

部署前可以做四格实验:基座模型在旧/新 Harness 上各跑一次,训练后模型再在两种 Harness 上各跑一次。四个结果能够粗分模型增益、Harness 增益与二者交互。若训练后只在训练 Harness 上提高,说明适配性很强;若在未见 Harness 上也提高,才有较强证据支持共享 agentic skill。

成本也应按成功任务计算。设一次训练周期总成本为 CtrainC_{train},评测或生产中每个 episode 成本为 cc,成功率为 pp,那么忽略重试差异时,每个成功任务的运行成本约为 c/pc/p。训练价值来自 pp 的提高、cc 的下降,或者减少人工接管。若成功率提升很小而 rollout 成本翻倍,技术上有效,业务上仍可能不划算。

OpenForgeRL 把真实 Harness 纳入可记录、可训练、可比较的实验对象。模型、Harness、环境和 verifier 可以分别版本化,训练结果也由此能够追问:能力究竟长在 policy 里,还是来自部署栈替它做了更多工作。

把系统拆开看,一条训练样本从任务入队到进入 loss,至少经过八个阶段:选择任务、启动 sandbox、加载 Harness、请求 policy、执行工具、终局验证、重建轨迹、训练消费。任何阶段失败,都不该笼统记成 reward 0。

task@v3
  → sandbox(image@sha256)
  → harness@commit
  → proxy(policy@step-120)
  → environment actions
  → verifier@v7
  → trajectory manifest
  → trainer batch@121

假设 Harness 在第六次模型调用后超时,但环境里的目标已经完成。Orchestrator 记录的是 harness_timeout,verifier 却可能返回 success。是否把这条样本用于训练,要看终止语义:若生产系统允许超时后的外部验收,成功信号仍有意义;若产品要求 Harness 必须在预算内主动提交,超时就是失败。这个决定属于任务定义,不能由训练脚本临时猜。

再假设 verifier 成功,轨迹重建却发现第三次调用缺少工具返回。此时 reward 没问题,样本却不完整。把它送进 trainer 会让某个 action 缺少真实条件,应标为 invalid_trace。相反,轨迹完整而 verifier 服务宕机,动作数据仍可用于 SFT 或离线分析,却不适合直接生成 RL 优势。将阶段状态分开保存,才能让不同数据用途各取所需。

3.1. 数据选择会改变学到的行为

只保留成功轨迹做 SFT,模型会看到大量顺利路径,却很少看到失败后的处理;把所有失败轨迹用于 RL,又可能混入环境故障和验证器错误。数据清理不能只按最终 reward 切一刀。

可以按转移片段标注四类行为:有效推进、无效探索、从失败恢复、产生不可逆错误。有效推进适合监督学习;恢复片段即使整条 episode 最终失败,也可能包含有价值动作;环境故障附近的片段通常需要剔除;不可逆错误则适合安全训练与动作门控。OpenForgeRL 观察到 RL 对 self-verification 和 tool coverage 有帮助,而 error recovery 仍弱,这也提示数据池需要主动寻找恢复片段。

任务采样还会影响成功率表象。若当前策略在简单任务上容易成功,在线采样会迅速积累这些任务的数据,随后进一步优化简单任务。困难任务因为持续得 0,既缺少正样本,也难产生可区分的组内优势。Balanced rollout 或基于成功率的课程可以提高临界难度任务的采样权重,但采样规则本身必须进入实验记录,否则最终成绩无法复算。

去重不能只看 prompt。两个任务的文字不同,底层仓库、隐藏测试或目标网站可能相同;反过来,同一句目标在不同初始状态下又可能是两道真正不同的题。任务指纹可组合文本嵌入、代码与资源哈希、验证器结构和初始状态摘要。评测集污染检查也沿用同一套多层指纹,而非只比标题。

版本矩阵与回归定位,一次实验至少涉及 policy、Harness、环境镜像、任务、Proxy 重建器和 verifier 六个版本。只记模型 checkpoint,几个月后很难解释同一权重为何复跑得到不同结果。可以把一次 run 的身份写成:

ρ=(p,h,e,t,x,v),\rho=(p,h,e,t,x,v),

其中六个字母分别对应上述组件。成绩表中的每个数字都应能落到一组 ρ\rho 和逐任务结果。

当成功率下降时,版本矩阵可以做最小二分。先固定旧 policy,只升级 Harness;若下降复现,问题来自接口或控制流。再固定 Harness,只升级环境与 verifier;若结果变化,检查任务漂移。收尾阶段才比较新旧 policy。一次同时升级所有组件,只能得到「新系统变差了」,无法指导修复。

真实 Harness 往往快速迭代,训练数据也会跨版本。旧轨迹是否还能使用,取决于消息模板、工具 schema 与动作语义是否兼容。若只是增加无关日志,可继续使用;若工具参数或自动重试逻辑改变,旧轨迹代表的 policy 条件分布已经变化,应分桶训练或降权,而非全量混合。

安全边界进入训练环,远程 sandbox 限制了单条 rollout 的破坏范围,但训练会反复运行成千上万条轨迹,小概率事故会被放大。环境默认禁用宿主机挂载,网络访问使用 allowlist,凭证按任务发放短期 token,资源配额限制进程、磁盘与调用次数。Harness 的权限也应与生产目标一致;训练时给无限权限、部署时再收紧,依然是一种 train-deploy mismatch。

外部网站和 API 还涉及真实副作用。用于训练的环境最好提供镜像、模拟服务或专用测试账户。确需访问实时服务时,写操作进入隔离租户,并设置总预算与速率限制。Verifer 读取的凭证与 Agent 使用的凭证分离,防止 policy 直接修改验收数据。

训练日志可能包含仓库代码、页面内容和工具响应。Proxy 位于所有模型调用的汇合点,天然也是敏感数据的汇合点。记录前要按消息字段脱敏,原始 trace 设置访问与保留周期,发布数据集再做许可证和隐私检查。一个能训练真实 Harness 的系统,也更容易收集真实环境里的秘密,这部分不能留给上线前补救。

4. 复现实验时应保存什么

论文数字要能复算,至少保存任务清单与版本、容器镜像摘要、Harness 启动参数、模型采样参数、每条轨迹的终止原因、verifier 输出和汇总脚本。模型训练还需记录 optimizer、batch、group size、KL/entropy 系数、最大 rollout 时间、有效样本数与 policy 版本推进规则。

只发布平均分不够。逐任务结果能够检查任务子集变化,失败类别能够区分 policy 与基础设施问题,长度分布能够发现超时带来的选择偏差。对于有随机性的 Agent,报告采样次数、pass@k 或 pass^k 的明确定义,并保留随机种子与原始 episode;否则相同的百分比可能对应完全不同的统计量。

OpenForgeRL 官方仓库已经公开核心 rollout engine、环境实现、veRL 示例与推理脚本,Kubernetes 编排依赖 Orchard Env。复现顺序宜从单任务单 sandbox 开始,确认 Proxy 能重建完整轨迹与 verifier 能复算结果,再扩到并发 rollout,收尾阶段接入参数更新。直接从大集群起跑,任何一个版本或路由错误都会被吞进海量日志里。

训练轨迹必须满足的约束,1. Harness-native rollout:训练轨迹必须来自真实 harness 控制流,非 reimplementation。 2. Train–inference 解耦:Proxy 是唯耦点;trainer 与 sandbox 可异构部署。 3. Trajectory fidelity:Proxy 记录的 io-pair 必须能重建 harness 实际看到的 state–action 序列。 4. Environment portability:换环境只改 sandbox 镜像;换 harness 只改启动命令与 Proxy 路由。 5. Reward 仍 task-native:ClawEval / OSWorld / WebVoyager 等官方 verifier,非 LLM judge。

要把 Harness 写进受控决策过程,普通 MDP 的粒度还不够。人们常把状态写成 sts_t、动作写成 ata_t,再把工具执行理解为环境转移 P(st+1∣st,at)P(s_{t+1}\mid s_t,a_t);这对固定的 ReAct 循环勉强够用,对真实 Harness 却过于粗糙。模型并不直接接触环境状态,它看到的是 Harness 经过选择、排序、裁剪和格式化之后生成的消息;模型输出也不一定直接成为环境动作,还可能先经过语法解析、权限检查、参数补全、自动重试与路由。更贴近实际的分解是:

xt=OH(zt,mt),ut∼πθ(⋅∣xt),at=GH(ut,mt),zt+1∼P(⋅∣zt,at),x_t=O_H(z_t,m_t),\qquad u_t\sim\pi_\theta(\cdot\mid x_t),\qquad a_t=G_H(u_t,m_t),\qquad z_{t+1}\sim P(\cdot\mid z_t,a_t),

其中 ztz_t 是外部环境的真实状态,mtm_t 是 Harness 自己维护的记忆与控制状态,OHO_H 决定模型看见什么,GHG_H 把模型生成内容解释成可执行动作。工具返回之后,Harness 还会更新自己的状态:

mt+1=FH(mt,ut,at,zt+1).m_{t+1}=F_H(m_t,u_t,a_t,z_{t+1}).

这组式子解释了为什么换 Harness 并非只换一段 system prompt。上下文压缩改变 OHO_H,工具参数修复改变 GHG_H,自动重试和子代理调度改变 FHF_H;三者都会改变策略实际面对的条件分布。即便底座权重、任务和外部环境完全相同,轨迹分布仍可能明显不同。

这里还有一层容易被忽略的部分可观测性。模型只看到 xtx_t,不知道 Kubernetes Pod 的剩余寿命、后台进程是否仍在运行、网页服务是否刚刚发生瞬时故障,也未必知道 Harness 已替它重试过几次。若这些隐藏变量会影响下一步结果,模型面对的其实是 POMDP。Harness 的历史整理机制承担了近似信念状态的角色:它把哪些失败、文件变化和工具结果保留下来,决定模型能否推断当前处境。压缩器若删除了「第一次写入失败但产生了半成品文件」这条信息,模型下一轮可能重复执行破坏性动作;保留全部原始日志又可能挤掉任务目标。所谓 Harness 能力,很大一部分正是在有限上下文中维护足够的信念状态。

因此,训练数据中的一条消息不能脱离产生它的控制状态来解释。相同的 permission denied,可能是模型首次越权,可能是 Harness 降权后重放旧命令,也可能是沙箱策略临时加载失败。三者对应的责任归因不同。Proxy 能保存模型真正看到的消息,却无法仅凭消息还原全部 mtm_t。若研究目标涉及自动重试、压缩、并行分支或审批门控,就要由 Harness 额外输出结构化控制事件,并让这些事件与 LLM 调用共享 episode 与父子调用标识。

两种接入模式由此有了明确差别。DirectEnvInstanceConfig 让训练引擎驱动外层循环,状态更新和 token mask 较容易掌握,代价是部署 Harness 的 FHF_H 可能被简化。PipelineEnvInstanceConfig 让环境拥有整个黑盒 episode,能够保留真实控制流,代价是训练器只能通过记录与重建理解发生了什么。前者适合研究模型在规范工具循环里的学习规律,后者适合研究部署系统中的真实行为;把前者的结论直接外推到后者,需要额外的跨 Harness 验证。