数据截至 (上游 commit 8b292c9f1b14)
Verifiers — 架构与原理
30 秒导读: Prime Intellect 出的「agent 考场」框架——你定义任务集(taskset),它把任务装进隔离的运行时(runtime),让真 实 harness(Claude Code、Codex 这类真程序)去做题,所有模型流量从它的拦截服务器过境并被逐笔记账,最后产出既能量分又能直接训练的记录。评测和强化学习(RL)用的是同一套东西。
1. 这是什么(零基础也能懂)
一句话定义: verifiers 是一个「定义任务 → 让 agent 在隔离环境里做 → 打分」的框架;打分结果可以直接当评测报告,也可以当 RL 的训练样本。
解决什么问题 / 给谁用: 假设你想知道「Claude Code 换上某个新模型后,修 bug 能力是涨了还是跌了」,或者你想用 RL 训一个会用终端的 agent。两件事都需要:一批标准化任务、一个让 agent 真刀真枪干活的考场、一套可信的记分。verifiers 把这三样做成可复用的库,供评测团队和 RL 研究者使用(它是 Prime Intellect 训练栈 prime-rl 的环境层)。
它能做什么(功能):
- 用 Python 类定义任务集(prompt、文件、参考答案、资源需求、打分函数),
uv run init一键脚手架; - 把任务跑在真实 agent 程序里(Claude Code、Codex、mini-swe-agent、bash 等 14 种内置 harness),而不是自己拼的简化循环;
- 四种隔离级别任选:本地子进程(调试)→ 本地 Docker → Modal / Prime 沙箱(生产级并发);
- 所有模型调用经过内置拦截服务器:实时落轨迹、统一改采样参数、改写可疑的工具返回(防 reward hacking);
- 多 agent 编排:单个解题、模拟用户多轮对话、best-of-N、裁判 agent 评判;
- 结果写到
outputs/<任务集>--<模型>--<harness>/<uuid>/traces.jsonl,--resume只补跑失败/缺失的。
用起来什么样: 安装后一条命令就能拿公开的终端任务集评测一个模型:
uv run eval primeintellect/terminal-bench-2 \
--env.agent.harness.id codex --env.agent.runtime.type docker
一句话直觉/类比: 把 RL 训练想成「组织一场大规模考试」:taskset 是题库,runtime 是考场隔间,harness 是考生自带的文具和答题习惯,而拦截服务器是监考+阅卷记录员——考生(模型)写的每一笔都先经过它,再送到真正的阅卷处(模型 API),所以它手里有最完整的原始记录。
2. 顶层全景(它大概怎么转)
verifiers 当前的主栈是 verifiers/v1/(旧的 v0 栈整体搬进 verifiers/legacy/,见第 6 章)。v1 把「跑一次评测」拆成四个正交的角色:
taskset(题库) env(编排:谁上场) interception server(监考/记账)
┌────────────┐ ┌────────────────┐ ┌──────────────────────┐
│ TaskData×N │─────▶│ run(task, │──────▶│ 每个 rollout 注册槽位 │
│ +Task 行为 │ │ agents) │ │ 按 secret 认领请求 │
└────────────┘ └───────┬────────┘ │ 改采样/防作弊/记 trace│
│ └─────────▲────────────┘
每个 agent = harness × 模型 × runtime │
│ │ 模型流量必经
┌─────────▼─────────┐ │
│ rollout(执行单元)│─────────────────┘
│ runtime 里起盒子 │ endpoint+secret
│ harness 在里面跑 │
└───────────────────┘
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
Taskset | 从数据集/生成器产出一个个 Task | verifiers/v1/taskset.py:38 |
Task / TaskData | 行为(搭环境、打分)/ 数据(题目卡)两半 | verifiers/v1/task.py:137 / :80 |
Env | 多 agent 控制流;默认 SingleAgentEnv | verifiers/v1/env.py:73 |
Harness | 驱动真实 agent 程序的适配器 | verifiers/v1/harness.py:33 |
Rollout | 一道题 × 一个 agent 的完整执行 | verifiers/v1/rollout.py:54 |
Runtime | rollout 的隔离盒子(进程/容器/沙箱) | verifiers/v1/runtimes/base.py |
InterceptionServer | 模型流量关口 + trace 记录员 | verifiers/v1/interception/server.py:139 |
Trace / Episode | 单 agent 记录 / 多 agent 一局记录 | verifiers/v1/trace.py:357 / verifiers/v1/episode.py:22 |
主线走一遍(一次 uv run eval <taskset-id>):
- 客户端加载 taskset,把任务一个个发给 worker;
- 每个任务在 env 里变成一局(episode):默认一个 agent 上场;
- 这个 agent 的一次执行 = 一个 rollout:开 runtime 盒子 → 装 harness → 拉起该 rollout 专属的拦截槽位和工具服务器 → harness 开跑;
- harness 里的程序想调模型,只能打向拦截服务器的
endpoint(配 secret);服务器代它调真实 API,顺手把这次问答记进该 rollout 的 trace; - 跑完:task 的
@reward/@metric、harness 的@metric、judge 三路打分写进 trace;trace 汇成 episode,落盘traces.jsonl。
3. 阅读地图
- 想定义自己的任务集 → 先读 01-task-and-taskset.md,再看 05 的 eval CLI 一节。
- 想接一个新的 agent 程序进来当 harness → 02-harness-and-runtime.md。
- 想知道轨迹怎么被记、作弊怎么被防 → 03-interception-and-trace.md——这是全场设计含量最高的一章。
- 想搞清一次执行的生命周期与超时/预算语义 → 04-rollout-lifecycle.md。
- 要多 agent(模拟用户、裁判、best-of-N) → 05-env-and-evaluation.md。
- 从 v0 迁移 / 找巧妙设计与代码地图 → 06-clever-legacy-map.md。
8. 代码地图(导航索引)
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 任务数据卡 | verifiers/v1/task.py | TaskData、WireTaskData |
| 任务行为/打分 | verifiers/v1/task.py | Task.score、Task.hooks |
| 题库加载 | verifiers/v1/taskset.py | Taskset.load、head、shuffle |
| 多 agent 编排 | verifiers/v1/env.py | Env.run、Env.finalize |
| harness 契约 | verifiers/v1/harness.py | Harness.launch、Harness.resume |
| 执行生命周期 | verifiers/v1/rollout.py | Rollout.open/step/close |
| 预算/钩子路由 | verifiers/v1/session.py | RolloutLimits、hook_boundary |
| 拦截服务器 | verifiers/v1/interception/server.py | InterceptionServer.handle_request |
| 轨迹结构 | verifiers/v1/trace.py | Trace、ModelCall、Branch |
| 一局记录 | verifiers/v1/episode.py | Episode、WireEpisode |
| 预制 env | verifiers/v1/envs/ | SingleAgentEnv、UserSimEnv、BestOfNEnv |
| v0 兼容层 | verifiers/__init__.py | LegacyAliasFinder |
| 示例任务集 | environments/alphabet_sort/alphabet_sort/taskset.py | AlphabetSortTaskset |