跳到正文
Prime Intellect Blog·· 2026-07-12精选AI 评分66

Prime Intellect 发布 verifiers 0.2.0 预览版,拆分 taskset 与 harness 支持智能体 RL

verifiers v1: Decomposing Tasksets and Harnesses for Agentic RL & Evaluations

AI 导读

Prime Intellect 发布 verifiers 0.2.0 预览版,以 verifiers.v1 命名空间重写核心,把环境拆成 taskset、harness 和 runtime 三层,实现任意 taskset 与兼容 harness 的组合运行。

推荐理由

原文给出 taskset、harness、runtime 三层拆分与可组合设计,读者可据此判断智能体训练与评测流程的改造方向。

正文 · AI 翻译

verifiers v1:为智能体强化学习与评估分解任务集和测试框架

今天,我们推出 verifiers 0.2.0,它预览了一个重写的核心,旨在为现代智能体训练和评估提供可组合的任务集和测试框架。

现代评估不仅仅是提示词。它们涉及运行编码智能体,这些智能体附带工具和自定义逻辑,例如压缩技术或内置子智能体。能够轻松运行任意任务对于现代评估和训练至关重要。

verifiers 的下一个演进版本(“v1”)正是为此而构建。其核心将环境拆分为任务集、测试框架和运行时。任务集定义了要完成的工作,即数据、工具和评分。测试框架是解决任务并产生 rollout 的程序:ReAct 循环、基于 CLI 的测试框架(如 Codex 或 Terminus 2),或你自己的智能体。rollout 发生在运行时内,运行时可以是本地的(作为子进程或 Docker),也可以在沙箱中,例如 Prime Sandboxes。

An environment decomposes into a taskset (what), a harness (how), and a runtime (where) — any taskset runs under any compatible harness, inside any runtime

v1 将几个新组件整合在一起:

  • 可组合的任务集 × 测试框架:任何任务集都可以在任何兼容的测试框架下运行
  • 可替换的运行时:测试框架、工具和用户都在统一的 Runtime 契约下运行
  • 一等公民的分支:rollout 不假设是线性的——压缩和子智能体是原生支持的
  • 训练就绪的轨迹:轨迹通过 renderers 携带训练就绪的 token 和 logprobs

由于这些变更影响广泛,我们以新的 verifiers.v1 命名空间向社区发布预览版本。我们推出时即支持完整的 prime-rl 训练。

我们强烈鼓励在新抽象之上进行构建,过去几周我们一直将其用于所有生产训练和评估需求。旧代码路径现已冻结,将不再积极维护。我们的目标是在未来完全弃用它。

架构

真正可替换的任务集和测试框架面临的一个核心挑战是,我们必须对测试框架内部发生的事情做尽可能少的假设。测试框架可能只是一次模型调用,但也可能是一个功能齐全的编码智能体。这类智能体可能使用不同的模型 API 以及子智能体或压缩策略等高级功能。

在本节中,我们将深入探讨一些技术细节,这些细节使该架构能够胜任大规模训练和评估。

运行时

到目前为止,环境构建者必须自己管理运行时生命周期。编写沙箱环境意味着在正确的时机设置沙箱、正确处理瞬态基础设施错误,并可靠地清理资源。

借助新的 Runtime 抽象,这些关注点被移入框架内部,让环境构建者可以专注于任务特定逻辑,而不是基础设施和网络。核心运行时 API 由 run、read 和 write 组成。框架确保每个 rollout 获得隔离的运行时,并妥善处理基础设施错误。

class Runtime(ABC):
    # lifecycle
    async start() -> None      # provision runtime resource
    async stop() -> None       # free runtime resource
    cleanup() -> None          # sync, idempotent teardown

    # user-facing
    async run(argv, env) -> ProgramResult
    async read(path) -> bytes
    async write(path, data) -> None

可以大致区分:

  • 本地运行时——例如用于最简单工作负载的 subprocess,或用于容器化任务小型实验的 docker。本地运行时非常适合本地调试和开发,但不推荐用于生产规模的评估或训练。
  • 远程运行时(沙箱)——例如 prime 或 modal 提供可水平扩展的运行时资源。它们是稳定运行现代基准测试和训练工作负载的必要条件。

拦截

让 v1 设计得以运作的核心抽象是拦截服务器(interception server)的概念。拦截服务器是由 verifiers 管理的 HTTP 服务器。

The interception server sits between the agent's runtime and the inference server

一旦在运行时中于某个 agent 的 harness 里设置好任务,agent 就开始向推理服务器发起请求。verifiers 将这些请求路由经过拦截服务器,由拦截服务器代理转发请求到推理服务器,并代理返回推理服务器的响应。因此,拦截服务器位于 agent 运行时与推理之间。这样做有几个关键优势:

  • 我们可以实时记录 agent 轨迹
  • 我们可以在那些未必暴露这些设置的 harness 中设置采样参数
  • 我们可以拦截并重写服务器端工具响应,例如用于缓解奖励黑客行为

出于可扩展性的考虑,拦截服务器是多路复用的,这意味着一个服务器处理固定数量的 rollout(默认:32)。拦截服务器池会根据观察到的并发量弹性扩缩容,从而即使在极高并发下也能保证可扩展性。

方言

并非所有 agent 都说同一种语言。如今,一个 harness 可能支持以下一种或多种方言:

  • OpenAI Chat Completions(/v1/chat/completions)
  • OpenAI Responses(/v1/responses)
  • Anthropic Messages(/v1/messages)

由于某些 agent 强制使用单一方言(例如 Claude Code 要求 Anthropic Messages,或 Codex 要求 OpenAI Responses),构建真正与 harness 无关的运行时意味着要正确支持所有这些请求和响应类型。

在 verifiers 中,方言是一个适配器,使我们能够检测线上消息类型,并将其动态转换为规范的 vf.types。实现这一点的核心部分是类级别的 routes 注册表(我们通过匹配它来检测应使用哪种方言),以及 parse_request 和 parse_response 方法(它们验证方言特定的线上载荷,并将其规范化为我们的规范 vf.Messages 和 vf.Response 类型)。

class Dialect(ABC, Generic[ReqT, RespT]):
    # --- registration / routing (class-level) ---
    routes: ClassVar[tuple[str, ...]]

    # --- wire → vf ---
    @abstractmethod parse_request(body)  -> tuple[vf.Messages, list[vf.Tool] | None]
    @abstractmethod parse_response(resp) -> vf.Response

这让你可以将任务设置 + 评分逻辑编写为精简 vf.types 的函数,而与所测试的 agent 无关。

客户端

拦截服务器必须拥有一个客户端来中继(并转换)传入的请求和响应。我们识别出两种具有不同需求的主要用例:

  • 评估(EvalClient)—— 盲 HTTP 代理
  • 训练(TrainClient)—— 包装 renderers 客户端,以实现忠实的 token-in RL 训练

在评估期间,目标是精确中继 agent 的请求和响应,以便我们的拦截机制不会干扰 agent 的 rollout。

然而,在训练期间使用环境时,我们希望获得忠实的 token-in-token-out 表示。为此,我们使用 renderers 库:客户端渲染器对不断增长的提示前缀进行分词,并调用 vLLM 服务器上的原始 token-in 生成端点。它返回精确的 token_ids 和 logprobs,这些会被记录下来,并在 agentic rollout 的未来轮次中复用。

轨迹

v1 rollout 的主要产物是 Trace。它是 rollout 期间累积的所有数据的唯一事实来源,包含评估和训练所需的一切。它是一个严格类型的 Pydantic 模型,使下游应用(例如 prime-rl)能够轻松消费和处理这些数据。

消息图

trace 上的核心数据结构是其消息图。消息图表示消息节点的有向无环图(DAG)。每条消息都是唯一的,并链接到其前驱,确保不会保存冗余信息。与朴素地记录请求和响应对象中的 prompt 和 completion 相比,这是一项关键优化。

  • v0 —— 每一轮都包含 prompt-completion 对,导致轮数呈二次方膨胀。

Message graph in v0: prompt-completion pairs repeated each turn

  • v1 —— 在消息图中每条消息都是唯一的,确保 trace 大小随轮数线性增长。

Message graph in v1: each message is a unique node

为了说明长时程训练的收益究竟有多大,我们使用 N 轮构建合成的 v0/v1 trace,每轮约 1K token,并测量在不同轮长度下表示线性轨迹的大小。

Trace size comparison between v0 and v1 across turn counts

在存储大量训练数据时,例如 router replay 期间的 experts 或多模态数据,差距会进一步拉大。这是一项核心基础设施优化,使我们能够毫无顾虑地在数百轮上训练 agent。

分支

并非所有 trace 都是线性的。例如,harness 可能会进行压缩或调用子 agent。在这种情况下,某条消息在图中可能没有前缀。我们称此时发生了一个分支。

分支是消息图上的任意一条根到叶路径。每个分支代表 rollout 期间的一条线性轨迹,因此可以作为一个连续的样本进行训练。这意味着具有 N 个分支的 trace 会产生 N 个可训练样本。这使得跨压缩和子 agent 的训练变得可行,并解锁了超出模型上下文窗口的长时程训练。

以压缩为例:初始的系统消息(S1)和用户消息(U1)定义了任务。agent 与其工具(A1,T1,…,TN)反复迭代,直到达到压缩限制,此时 harness 注入一条压缩 prompt(UC),agent 以摘要(AC)作为回应。在下一轮中,我们发送 (S1, U1'):harness 系统 prompt 以及包含 agent 摘要的新用户消息。

Message graph with compaction branches sharing the system prompt root

我们可以看到,harness 级别的系统 prompt S1 是唯一的,并且是所有压缩分支的根。除此之外,每个压缩分支都由唯一的消息节点组成,并产生一个独立的训练样本。

API

我们简要概述 taskset 的 API 表面,这也是大多数现有环境将迁移到的目标。

Tasksets

一个 Taskset 会生成一个带类型的 Task 对象列表。任务定义了诸如 setup 和评分逻辑等行为,并由 TaskData 作为种子。重要的是,它与将用于解决任务的 harness 无关。

例如,以下 taskset 使用精确匹配奖励定义了简单的加法任务。同一个 taskset 既可以在完全没有工具的 null harness 上运行,也可以在诸如 kimi-code 这样的大型 agent harness 上运行,用于评估和训练。

import verifiers.v1 as vf


# The data for a given task
class AdditionData(vf.TaskData):
    answer: int


# A runnable task instance
class AdditionTask(vf.Task[AdditionData]):
    # @vf.reward denotes the scoring function for the task.
    # It needs the trace, which contains the whole message graph, including function calls, user messages etc.
    # It returns the reward for the single task based on this function.
    @vf.reward
    async def exact_match(self, trace: vf.Trace) -> float:
        return float(trace.last_reply == str(self.data.answer))


# The taskset defines the tasks and needs a vf.TasksetConfig, which can be empty.
class AdditionTaskset(vf.Taskset[AdditionTask, vf.TasksetConfig]):
    def load(self) -> list[AdditionTask]:
        return [
            AdditionTask(
                AdditionData(idx=i, prompt=f"What is {i} + {i}?", answer=2 * i),
                self.config.task,
            )
            for i in range(100)
        ]


# Export the Taskset for verifiers to find it when loading
__all__ = ["AdditionTaskset"]

与之前一样,verifiers 允许你添加自定义工具、模拟用户、记录指标并设计复杂的奖励。所有这些逻辑都属于任务,而 rollout 策略则留在 harness 中。有关 v1 taskset 的示例,请查看 research-environments。

Harbor

Harbor 作为社区中 agentic 任务的抽象已获得大量关注。verifiers v1 内置了一个 harbor taskset,使得添加任何 Harbor 数据集都变得轻而易举。例如,将 Terminal Bench 2 移植到 verifiers v1 只需这些代码:

import verifiers.v1 as vf
from verifiers.v1.tasksets.harbor import HarborConfig, HarborTask, HarborTaskset

# Set the dataset to the same name as registered in the Harbor registry
class TerminalBench2Config(HarborConfig):
    dataset: Literal["terminal-bench/terminal-bench-2"] = "terminal-bench/terminal-bench-2"


# The data will get loaded automatically
class TerminalBench2Taskset(HarborTaskset, vf.Taskset[HarborTask, TerminalBench2Config]):
    pass
    # No need for a reward function, as it will get inherited from the Harbor dataset

在我们的内部测试中,verifiers 在使用第三方 harness 运行相同任务时,性能与 Harbor 本身相当,这表明 verifiers 没有引入额外开销。

Harbor 是第一个获得完整支持的第三方 taskset 格式,我们还对其他流行的环境注册中心提供了 alpha 支持,例如 NeMo Gym 和 OpenEnv。

评估

一旦有了 taskset,你就可以选择要运行的 harness。我们开箱即用地支持许多流行的 harness,包括 Codex、Kimi Code、Terminus 2、Mini-SWE-Agent,同时也允许你编写自己的 harness。

要运行评估,只需准备一个 TOML

model = "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B"

[sampling]
temperature = 1.0
top_p = 0.95

[taskset]
id = "primeintellect/terminal-bench-2"

[harness]
id = "codex"
version = "0.116.0"

然后使用 CLI 运行它

uv run eval @ path/to/config.toml

Running an evaluation with the verifiers CLI

训练

和之前一样,v1 环境可以直接接入我们的训练框架 prime-rl,而且集成比以往更加紧密:

  • Configs — 直接从 verifiers 中读取,使环境在评估和训练中可以以相同方式进行配置
  • Traces — 直接读取,无需冗余计算,例如分支可以直接从 trace 中读取,因为它们已经可用,从而显著降低 orchestrator 的内存开销。

我们已经将所有内部环境移植到新格式,并正在积极使用它们进行训练。例如,这个用于长度惩罚消融的训练配置在 6 个 H200 节点上,用自定义 harness 在 ScaleSWE 上训练 GLM-4.5-Air,并在 2 天内评估 SWE-Bench-Verified,展示了稳定的 agentic 训练,使 GLM-4.5-Air 成为更强大、更高效的编码 agent。

SWE ablation training curves for GLM-4.5-Air

迈向 1.0.0

v1 作为预览版发布,我们鼓励在 verifiers.v1 之上构建新环境。未来,我们打算移除所有旧代码。

我们的 1.0.0 路线图上有以下事项:

  • 多 agent 环境
  • 使用任何 API 方言进行训练(当前:Chat、Responses、Messages;即将支持:Interactions)
  • 对所有主要环境框架提供稳健支持,包括 OpenEnv、NeMo Gym 和 OpenReward。

在 1.0.0 发布后,旧环境仍然可以通过将 verifiers 固定到 1.0.0 之前的版本来在本地运行。

延伸阅读

  • 查看 verifiers v1 的新公共文档页面,包括编写 tasksets、harnesses、CLI 使用等的用户指南
  • 查看我们最近的 AIE workshop 概览视频,内容涵盖 v1 + prime-rl
  • 查看 verifiers 以了解内部实现、入门示例和更新后的文档
  • 查看 prime-rl 以开始训练你的 v1 环境
  • 更新 prime CLI 并将 skills 与 prime lab sync 同步
@article{primeintellect2026verifiersv1,
author = {Mika Senghaas and Florian Brand and Will Brown and Prime Intellect Team},
title = {verifiers v1: Decomposing Tasksets and Harnesses for Agentic RL \& Evaluations},
journal = {Prime Intellect Blog},
year = {2026},
month = {July},
note = {https://www.primeintellect.ai/blog/verifiers-v1}
}

来源:Prime Intellect Blog · primeintellect.ai