跳到主要内容

Verifiers — 架构与原理

30 秒导读: Verifiers 是 Prime Intellect 出的一个 Python 库,用来给大模型(LLM)造「环境」(environment)——一个环境把三样东西打包在一起:一批题目、一套让模型作答的交互流程、一个给答案打分的奖励函数。造好之后,同一个环境既能拿来评测模型,也能直接喂给 RL 训练器训练模型,还能用来刷合成数据。

1. 这是什么(零基础也能懂)

一句话定义

Verifiers 是一个造「LLM 强化学习环境」的库。它把「给模型出题 → 让模型(可能多轮、可能用工具)作答 → 给作答打分」这条链路,抽象成一个叫 Environment 的对象。

解决什么问题 / 给谁用

先说痛点。你想用强化学习(RL,reinforcement learning)训练一个大模型,或者想严肃地评测它,你都得回答同样三个问题:

  1. 题目从哪来?(数据集)
  2. 模型怎么作答?一次问答就完?还是要它反复调工具、跑代码、查网页?(交互流程 / harness)
  3. 答得对不对,给几分?(奖励函数 / rubric)

传统做法是每个项目各写一套,评测脚本和训练脚本还各写各的,互不通用。Verifiers 的主张是:把这三样封装成一个自包含的 Python 模块,评测和训练共用同一个环境定义。

给谁用:

  • 研究者 / 工程师:想训练或评测 LLM 在某个任务上的能力(做数学题、写代码、玩文字游戏、用搜索工具答题……)。
  • Prime Intellect 生态:环境可以推到官方的 Environments Hub 共享,配合它家的训练框架 prime-rl 和托管训练平台。

它能做什么

用途说明
评测(eval)拿一个 OpenAI 兼容的模型端点,跑一批题,算平均奖励、pass@k、token 用量、成本
RL 训练环境产出「轨迹 + 奖励」,喂给 GRPO 之类的 RL 训练器更新模型权重
合成数据让模型跑 rollout,把高分轨迹留下来当训练数据
Agent harness 实验换不同的工具集 / 多轮协议,看模型行为怎么变

用起来什么样

最小的一个环境长这样(来自 README,SingleTurnEnv = 单轮问答环境):

# my_env.py —— 一个环境模块必须暴露 load_environment()
import verifiers as vf

def load_environment(dataset_name: str = "gsm8k") -> vf.Environment:
dataset = vf.load_example_dataset(dataset_name) # 每行有 question / answer

async def correct_answer(completion, answer) -> float: # 一个奖励函数
completion_ans = completion[-1]["content"]
return 1.0 if completion_ans == answer else 0.0

rubric = vf.Rubric(funcs=[correct_answer]) # 把奖励函数装进 rubric
return vf.SingleTurnEnv(dataset=dataset, rubric=rubric)

然后命令行评测(eval 是 v1 的 CLI 入口,见 pyproject.toml[project.scripts]):

prime eval run my-env -m openai/gpt-5-nano

三步走:数据集(每行 question/answer)→ rubric(一个把 completion 和 answer 变成 float 分数的函数)→ SingleTurnEnv(把两者粘起来的环境)。就这么点代码,评测和训练都能跑。

一句话直觉 / 类比

Environment 想成一场标准化考试的完整试卷包:题库(dataset)、考试规则(一次答完 or 允许查资料/多轮 = harness)、判分标准(rubric)。造好这一个包,谁都能拿去「监考评分」(eval)或者「陪考特训」(RL train)。

本节到此不碰任何底层代码。记住一件事就够:Environment = dataset + harness + rubric,一次封装,评测/训练通用。

2. 顶层全景(它大概怎么转)

2.1 一次评测的数据流

先看最常见的路径——评测一个模型。从「一批题」到「一份带分数的结果」,中间经过这些部件:

dataset (一批题)


┌───────────────────────────────────────────────┐
│ Environment.evaluate() / generate() │ ← 并发调度器
│ 为每道题(或每组)起一个 async 任务,限流跑 │
└───────────────────────────────────────────────┘
│ 每道题一条

┌───────────────┐ 反复循环直到停止条件命中
│ rollout() │─────────────────────────────┐
│ (一条轨迹) │ │
└───────────────┘ │
│ ① 取当前对话 │
▼ │
┌───────────────┐ HTTP ┌──────────────┐ │
│ get_model_ │────────► │ Client │ │
│ response │◄──────── │ (OpenAI/ │ │
└───────────────┘ 回答 │ Anthropic) │ │
│ ② 把回答记进 trajectory │
▼ │
┌───────────────┐ │
│ env_response │ ③ 环境回话(工具结果/下一轮) │
└───────────────┘──────────────────────────────┘
│ 循环结束

┌───────────────┐
│ Rubric.score │ ④ 跑所有奖励函数,加权求和 → reward + metrics
└───────────────┘


RolloutOutput (prompt / completion / reward / metrics / timing ...)

怎么读这张图:从上往下是一次评测的时间顺序;中间 ①②③ 的小循环就是「模型说一句 → 环境回一句」的多轮对话,SingleTurnEnv 只是把这个循环限制成 1 轮。

2.2 部件一句话职责

部件干什么在哪
Environment抽象基类:持有 dataset/parser/rubric,提供 generate/evaluate 并发调度verifiers/envs/environment.py
MultiTurnEnv实现多轮 rollout 循环(模型说一句、环境回一句,直到停止)verifiers/envs/multiturn_env.py
SingleTurnEnv / ToolEnv常用具体环境:单轮 / 带工具调用verifiers/envs/singleturn_env.pytool_env.py
Client把「发一次模型请求」抽象成 provider 无关的调用verifiers/clients/
Parser / XMLParser从模型输出里抽出「最终答案」verifiers/parsers/
Rubric一组奖励函数 + 权重,把一条轨迹打成分数verifiers/rubrics/rubric.py
State一次 rollout 的可变工作台(对话、轨迹、奖励、计时都塞这里)verifiers/types.py

2.3 两代 API:先认清这件事

Verifiers 现在同时存在两套 API,读代码前必须先分清,否则会看串:

经典 API(v0)新 API(v1)
核心抽象Environment(dataset+harness+rubric 揉在一个对象里)Taskset(出题+评分)与 Harness(怎么跑)拆开
代码位置verifiers/envs/rubrics/parsers/verifiers/v1/
一次 rollout 的记录State(dict 子类,约 600 行)Trace(pydantic 模型,带类型)
CLI 入口vf-evaleval / serve / validate(见 pyproject.toml
怎么跑代码直接在评测进程里Runtime(subprocess / docker / prime 沙箱),可远程
兼容——能通过「legacy bridge」把 v0 环境包一层跑起来(EnvConfig.is_legacy

本文的教学顺序:先讲透经典 API(概念更少、直觉更清)→ 再讲 v1 为什么这么重构、多解决了什么。两套都在活跃使用,v1 是明显的演进方向。

2.4 主线走一遍(不进代码)

  1. 你写一个环境模块,暴露 load_environment(),返回一个 Environment(或 v1 的 Taskset)。
  2. CLI 或训练器用 load_environment(env_id, **args) 按模块名把它 import 进来(verifiers/utils/env_utils.py)。
  3. env.evaluate(client, model):内部把每道题变成一个 RolloutInput,并发跑 rollout()
  4. 每条 rollout 反复调模型、让 env_response 回话,直到某个 @vf.stop 停止条件命中。
  5. 轨迹交给 Rubric 打分,得到 reward 和各项 metrics
  6. 汇总成 GenerateOutputs:平均奖励、pass@k、token/成本、每条轨迹明细。

3. 阅读地图(建议顺序)

想快速看懂「一次 rollout 怎么跑」 → 读 01-core-loop.md:Environment 基类、rollout/generate/evaluate 三层调度。

想懂「怎么打分、怎么从输出抽答案」 → 读 02-rubric-parser.md:Rubric 加权、Parser/XMLParser、MathRubric、JudgeRubric(用另一个模型当裁判)。

想懂「多轮对话和工具调用」 → 读 03-multiturn-tools.md:MultiTurnEnv 的循环、停止条件装饰器、ToolEnv、State 数据结构。

想懂「v1 为什么把环境拆成 Taskset + Harness」 → 读 04-v1-taskset-harness.md:新架构、Runtime 沙箱、Interception 拦截层。

想看精华技巧、边界、全局跳转表 → 读 05-clever-boundaries-map.md

依据:verifiers/__init__.py(公开 API 与懒加载表 _LAZY_IMPORTS)、pyproject.toml[project.scripts] 入口)、README.md(Overview 与最小示例)。