框架提供 select、compare、track、ProgressTracker 接口,支持 N 选最优候选、成对对比、轨迹步骤进度评估,还可在线监控智能体运行,提前终止无效样本。采用概率支点锦标赛 PPT 算法,将排序复杂度从 O (N²) 降至 O (Nk) 降低推理成本;前缀缓存优化使未缓存 token 减少 3.4 倍,附带完整 token 用量统计。
原生支持文本、图像、视频多模态输入,适配代码、医疗、机器人等任务。可作为独立库使用,也可作为 Claude Code 插件 TurboAgent。在 Terminal‑Bench、SWE‑Bench Verified 等数据集验证,自验证场景下模型评判自身输出也能显著提升 Pass@1。支持自定义基准任务,提供完整复现脚本与开源代码。
7 个关键问题问与答
Q1:LLM‑as‑a‑Verifier 和传统 LLM‑as‑a‑Judge 的核心区别?
A:LLM‑as‑Judge 输出单一离散分数;本框架利用打分 token 完整 logprob 对数概率分布计算期望,输出连续细粒度奖励,同时搭配重复评估、标准拆解,输出反馈粒度更细。
Q2:什么是概率支点锦标赛 PPT,带来什么收益?
A:是候选轨迹排序算法,只将全部样本和少量支点样本对比,复杂度由 O (N²) 降低到 O (Nk),大幅减少成对验证调用成本,同时通过轮换 A/B 位置消除模型位置偏见。
Q3:框架支持自验证是什么含义?效果如何?
A:生成轨迹的模型和做打分验证的是同一个模型。Terminal‑Bench2.1 实验中 Best‑of‑5 配置 Pass@1 由 78.7% 提升至 88.0%,距离理想 oracle 上限仍有差距,但显著优于原生输出。
Q4:track 和 ProgressTracker 接口有什么差异?
A:track用于已经完整结束的轨迹,批量对全部检查点打分;ProgressTracker用于智能体运行过程中,每输入一步拿到实时分数,支持提前放弃效果差的 rollout。
Q5:前缀缓存优化是如何实现、收益多大?
A:把任务、轨迹放在提示词前缀,评判标准放在末尾,复用公共缓存片段。Terminal‑Bench2.1 缓存命中率从 5.2% 提升 78.4%,未缓存输入 token 减少约 3.4 倍,降低推理开销。
Q6:框架可以适配自定义任务吗?如何做?
A:可以。三步:1)放入自定义轨迹数据;2)修改基准模板文件任务名称;3)借助 Claude/Codex 生成评判标准与运行脚本,即可接入整套评估流水线。
Q7:该框架可以用于哪些下游场景?
A:①测试时缩放,多候选中挑选最优智能体输出;②智能体执行进度监控,早停无效任务;③生成强化学习的细粒度奖励信号;④作为插件赋能 Claude Code 代码智能体;支持机器人、代码修复、医疗智能体多模态任务。
附录 大模型验证器(LLM‑as‑a‑Verifier):一套通用统一的验证框架
多模态输入,广泛应用场景,统一验证框架
|
|
|
|
|
|
|
|---|
🔥 LLM‑as‑a‑Verifier在多个智能体基准测试上取得当前最优(SOTA)效果,包括 Terminal‑Bench、SWE‑Bench Verified、MedAgentBench、RoboRewardBench 等。欢迎社区贡献更多使用案例!
安装
pip install llm-verifier
从代码仓库克隆后安装最新版本:
pip install -e .
0.2.0 版本更新内容(完整更新日志见 CHANGELOG.md)
-
前缀缓存优化:针对轨迹密集型基准测试,未命中缓存的输入 token 数量减少约3.4 倍 -
Terminal‑Bench 2.1 自验证基准集 -
新增 deepseek‑v4‑flash 验证器后端 -
Token 用量统计接口( llm_verifier.token_usage())
项目简介
LLM‑as‑a‑Verifier 是一套通用框架,可为任意智能体提供细粒度反馈。核心思路十分简洁:
-
使用细粒度打分粒度; -
基于大模型打分 token 完整对数概率分布求期望; -
扩大重复评估规模,同时对评判标准做拆解。
得到的细粒度反馈可用于测试时缩放、进度追踪、强化学习。
快速上手
简单 N 选 1 最佳结果筛选
运行首个端到端筛选逻辑(需要在.env中配置DEEPSEEK_API_KEY或VERTEX_API_KEY;也可以使用兼容 OpenAI 接口、可返回对数概率的服务,例如通过 vllm 启动模型:vllm serve Qwen/Qwen3.5‑9B,设置环境变量OPENAI_BASE_URL=http://localhost:8000/v1)
import llm_verifier
problem = "Write a function that reverses a string."
candidates = [
"def rev(s): return s[::-1]",
"def rev(s): return s",
"def rev(s): return ''.join(sorted(s))",
]
result = llm_verifier.select(
problem=problem,
candidates=candidates,
criteria={"Correctness": "Does the code actually reverse the string?"},
)
print(result.index) # 最优候选项索引:0
print(result.scores) # 各个候选项分数:[0.73104, 0.38446, 0.38449]
直接对两个候选项打分
select接口底层基于成对奖励模型实现。如需获取单次对比的原始细粒度奖励值,调用compare:
reward_a, reward_b = llm_verifier.compare(
problem, candidates[0], candidates[1],
criteria={"Overall": "Does the code solve the problem?"},
)
print(reward_a, reward_b) # [0,1]区间细粒度奖励值:0.99994 0
细粒度进度追踪
同样的细粒度奖励,也可以通过track接口,在智能体每一步执行结束后评估任务进度:
steps = [
'Read the problem statement',
'Wrote def rev(s): return s ',
'Tested: rev("abc") returned "abc"',
'Changed to def rev(s): return s[::-1]',
'Tested: rev("abc") returned "cba"',
]
result = llm_verifier.track(problem=problem, steps=steps,
checkpoint_steps=[1, 2, 3, 4, 5], n_evaluations=4)
print(result.scores) # 每一步完成后的进度分数:[0.00106, 0.02417, 0.03143, 0.62004, 0.99978]
自验证(Terminal‑Bench 2.1)
模型能否评判自己生成的执行轨迹?在 Terminal‑Bench 2.1 上,我们用 deepseek‑v4‑flash 为每个任务生成 5 条 mini‑swe‑agent 轨迹,再用同一个模型充当验证器。即便验证器评判的是自身输出,筛选后的效果也显著优于 Pass@1。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
轨迹数据存放路径:data/terminal_bench_2.1_trajs/;打分仅需要在.env配置DEEPSEEK_API_KEY。每种配置都提供复现脚本:
python scripts/run_bo3.py # 3选1实验
python scripts/run_bo5.py # 5选1实验
智能体基准测试的测试时缩放
所有基准的智能体轨迹数据都放在data/目录。以下全部基准均使用 Gemini 2.5 Flash (gemini‑2.5‑flash) 作为验证器,实验结果如下:
|
|
|
|
|
|
|
|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
复现实验结果
按基准名称运行脚本(不带参数执行python scripts/run.py可查看全部可用基准):
python scripts/run.py terminal_bench
python scripts/run.py swe_bench
python scripts/run.py medagentbench
可通过命令行参数覆盖锦标赛算法默认配置:
python scripts/run.py swe_bench --pivots 2 --n-evaluations 8 --seed 0 --max-workers 50
基准定义文件:llm_verifier/benchmarks.py,可在此新增或修改基准。
从多条智能体轨迹选出最优结果
给定任务与一批智能体执行轨迹,仅需几行代码选出最优轨迹:
import llm_verifier
problem = "Fix the failing test in utils.py."
candidates = [traj_1, traj_2, traj_3, traj_4, traj_5]
result = llm_verifier.select(
problem=problem,
candidates=candidates,
criteria={
"Root cause": "Did the agent fix the real cause?",
"Verification": "Did the agent confirm the fix?"
},
model="gemini-2.5-flash", # 指定验证器模型
n_evaluations=4, # 每条评判标准重复评估次数
pivots=2, # 支点数量,pivots小于候选项数量;平衡验证成本与精度
)
print("Best candidate:", result.index)
print("Ranking:", result.ranking)
底层实现:select使用概率支点锦标赛(Probabilistic Pivot Tournament)对 N 条轨迹排序。相比完整循环两两对比的\(O(N^2)\)复杂度,该算法仅需\(O(Nk)\)次成对验证。
pivots参数权衡成本与精度:支点数量越多,对比次数越多,排序精度越高。
将 LLM‑as‑a‑Verifier 适配到你的业务场景
三步即可把验证器用于自定义任务,剩下工作交给 Claude Code(自动生成评判标准、编写运行脚本、完成 N 选 1 筛选):
- 导入数据
将你的智能体轨迹复制到 data/task_name_trajs/ - 修改命名
在 add_new_benchmark.md把所有task_name替换为你的任务名 - 运行大模型辅助脚本
在本项目仓库启动 Claude Code(也可使用 Codex 等其他模型,关闭高危权限),粘贴 add_new_benchmark.md的内容执行。
代码智能体的进度追踪
细粒度奖励可以对轨迹每一步做打分(快速上手的track接口)。下图是 Terminal‑Bench 任务pytorch‑model‑cli下两条 Terminus‑2 运行轨迹:成功轨迹的验证分数持续走高;失败轨迹全程分数偏低,伴随大量错误行为。
运行脚本复现绘图:
python scripts/terminal_bench_progress.py # 对两条轨迹打分并绘图
在线实时进度追踪
track接口用于已经执行完毕的轨迹。若要在智能体运行过程中监控状态,使用ProgressTracker:每产生一步就送入追踪器,拿到实时进度分数。可以用来提前终止没有希望的执行分支,或者决定何时重新采样。验证器只能看到已经发生的步骤,看不到未来。
tracker = llm_verifier.ProgressTracker(problem, n_evaluations=4)
score = tracker.update('Read the problem statement') # 0.00002
score = tracker.update('Wrote def rev(s): return s') # 0.00013
score = tracker.update('Changed to def rev(s): return s[::-1]') # 0.73938
score = tracker.update('Tested: rev("abc") returned "cba"') # 0.98604
if score < 0.05: # 任意一步分数过低,提前放弃该次执行
...
在线模式复现 Terminal‑Bench 轨迹,每一步输出实时分数条,模拟智能体运行框架视角:
python scripts/terminal_bench_progress.py --online
多模态支持
使用多模态验证模型(例如 Gemini 2.5 Flash、vllm 部署的 Qwen/Qwen3.5‑9B),所有接口均支持传入图片:单张图片images="frame.png"或者图片列表;支持本地文件路径、http/https 链接、原始字节。
result = llm_verifier.select(problem, candidates, criteria=criteria,
images=["before.png", "after.png"])
tracker = llm_verifier.ProgressTracker(problem)
score = tracker.update(step, images="camera_frame.png") # 单步附带画面帧
每一步传入的画面帧会完整保存在轨迹历史,后续所有更新验证时都可以看到全部视觉历史,适合机器人任务的轨迹追踪。更多输入格式、后端限制、可运行示例见多模态文档。
Claude Code 插件
TurboAgent 将 LLM‑as‑a‑Verifier 封装为 Claude Code 的代理 API。部署在客户端与模型服务商之间,并行生成多条候选回复,通过概率支点锦标赛选出最优输出。
pip install git+https://github.com/llm-as-a-verifier/TurboAgent
把 Claude Code 请求指向代理服务,直接使用原有功能:
turbo-agent # 在8888端口启动代理
ANTHROPIC_BASE_URL=http://localhost:8888 claude
内置可视化页面:http://localhost:8888/visualizer,可以查看流水线 DAG、进度分数、候选回复、最终筛选结果。配置与部署细节见 TurboAgent 仓库。
项目目录结构
.
├── scripts/ # 命令行入口脚本
│ ├── run.py # 基于注册表的基准测试启动器
│ ├── run_bo3.py # 复现3选1自验证实验
│ ├── run_bo5.py # 复现5选1自验证实验
│ └── terminal_bench_progress.py # 轨迹打分+绘图示例
├── criteria/ # 验证评判标准与真值说明
│ ├── TEMPLATE.md # 自定义评判标准模板
│ ├── terminal_bench.md
│ ├── swe_bench.md
│ └── medagentbench.md
├── llm_verifier/ # 可导入的框架源码
│ ├── __init__.py # select() / compare() 对外接口
│ ├── __main__.py # python -m llm_verifier <file.md>预览评判标准
│ ├── benchmarks.py # 基准注册表
│ ├── fine_grained_reward.py # R(x,τ)对数概率打分与分数缓存
│ ├── progress.py # track() 逐步进度曲线
│ ├── pivot_tournament.py # 概率支点锦标赛PPT(Bradley‑Terry模型)
│ ├── prompts.py # 加载criteria目录下的评判标准
│ └── loaders.py # 各基准轨迹加载器
└── data/ # 各个基准的智能体轨迹数据
运行产生的验证分数缓存存入cache/,结果表格输出到results/;两个目录会自动创建,不纳入 git 版本管理。
底层原理
细粒度奖励计算
不同于传统 LLM‑as‑a‑Judge 直接输出单一离散分数,LLM‑as‑a‑Verifier 对任务x下轨迹\(\tau\)的奖励做如下估计:
-
C:评估评判标准数量 -
K:重复验证次数 -
G:打分 token 数量(粒度) -
\(p_{\theta}(v_g|x c \tau)\):模型\(\theta\)输出打分 token \(v_g\) 的概率 -
\(\phi(v_g)\):将打分 token 映射为标量数值 -
\(V_{score}=v_1,…,v_G\):有序离散打分 token 集合
实现代码位于:llm_verifier/fine_grained_reward.py
概率支点锦标赛
对 N 条候选轨迹做排序,普通循环两两对比复杂度为组合数\(\binom{N}{2}\),即\(O(N^2)\)。概率支点锦标赛(PPT)是一套低成本排序算法:全部候选项只和少量支点 (pivot)做对比,复杂度降低至\(O(Nk)\)。
- 候选集
待排序轨迹集合\(\tau_1,…,\tau_N\) - 环遍历
构造随机哈密顿环,对相邻两两打分;每个候选项一次作为 A、一次作为 B,消除模型的位置偏好 - 支点筛选
根据环遍历得分\(w_{(i)}\)排序,取前k个作为支点集合P - 支点锦标赛
非支点与支点、支点互相之间全部成对对比;成对偏好概率\(p(a\succ b)=\sigma(R_a-R_b)\)。计算资源集中在高分不确定样本,复杂度由\(O(N^2)\)降为\(O(Nk)\)。每一组对比交替 A/B 位置,消除位置偏差。 - 结果选择
聚合全部对比得到总获胜权重\(w_i\)与对比次数\(c_i\),返回归一化\(\frac{w_i}{c_i}\)最高的候选项。
实现代码位于:llm_verifier/pivot_tournament.py
提示词模板
成对对比提示词
你是该领域专业评审。你将看到任务描述与两条执行轨迹。
评估标准:【领域相关评判标准】
任务:{task prompt} 轨迹 A:{A} 轨迹 B:{B}
仔细分析两条轨迹,输出最终分数:
<score_A> 1‑20之间整数 </score_A><score_B> 1‑20之间整数 </score_B>打分规则:依据评估标准,1 分代表完全错误,10 分为边界存疑,20 分为完全正确。
进度追踪提示词
你是智能体任务评估专家。以实际输出为准,不要轻信智能体自身描述。
任务:{task prompt} 智能体轨迹(共 N 步):{trajectory}
需要在 N 个检查点打分:根据到此步为止智能体全部行为,判断当前状态是否已经完成任务。
独立对每个检查点打分,严格输出 N 行结果:
<c1>1‑20整数</c1>…<cN>1‑20整数</cN>打分规则:1 = 确定未完成,10 = 存疑,20 = 确认完成。
注:实际代码中没有使用数字,而是 A‑T 字母打分,方便提取对数概率实现粒度缩放。
前缀缓存优化
每次验证提示词包含两条完整轨迹(Terminal‑Bench 2.1 场景可达 8 万 token),每条评判标准、每轮重复都要重新打分。在支持提示词前缀缓存的后端,绝大部分输入可以被缓存复用。 实现要点:评判标准放在提示词末尾;任务、两条轨迹、打分规则作为共享前缀。先预热请求填满缓存前缀,再批量下发剩余请求。 Terminal‑Bench 2.1 上缓存命中率从 5.2% 提升到 78.4%,未命中缓存的输入 token 减少约3.4 倍。
Token 用量统计
每一次验证调用都会记录实际消耗 token,缓存命中率为实测值而非估算。运行scripts/run.py结束后会在结果表格输出统计信息,同时写入results/<benchmark>.txt。
仅统计本次实际发起的调用;命中分数缓存的对比不会产生开销。推理 token 属于输出 token 子集;缓存输入 token 属于输入 token 子集。计数器为进程全局、线程安全。
import llm_verifier
llm_verifier.USAGE.reset()
result = llm_verifier.select(problem, trajectories, criteria="terminal_bench")
print(llm_verifier.token_usage())
# {
# 'calls': 24,
# 'input_tokens': 1512480,
# 'cached_input_tokens': 1190208,
# 'uncached_input_tokens': 322272,
# 'output_tokens': 180224,
# 'reasoning_tokens': 145408,
# 'cache_hit_rate': 0.787
# }
llm_verifier.USAGE为TokenUsage对象:
.snapshot()返回上述字典 .reset()清零统计 .format_usage(...)格式化输出报告
统计数据来自模型后端返回的用量;如果后端不返回用量字段,则全部记为 0。
引用
如果你使用本项目工作,请引用:
@misc{kwok2026llmasaverifiergeneralpurposeverificationframework,
title={LLM-as-a-Verifier: A General-Purpose Verification Framework},
author={Jacky Kwok and Shulu Li and Pranav Atreya and Yuejiang Liu and Yixing Jiang and Chelsea Finn and Marco Pavone and Ion Stoica and Azalia Mirhoseini},
year={2026},
eprint={2607.05391},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2607.05391},
}
术语对照表
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

