mcpField
R
rewardkit

rewardkit

github.com/harbor-framework测试与质量6.6k1.3k 次安装今天更新
代码仓库

关于 rewardkit

rewardkit 是一个 Python 包和技能,可通过程序化检查及 TOML 配置的 LLM 或 Agent 评审器定义任务验证器,面向 Harbor 任务作者。它支持组合标准、分别评分多个维度并聚合得分。

主要功能

  1. 01内置文件、命令、数据、HTTP、图像及轨迹检查
  2. 02支持加权的自定义 Python 标准
  3. 03通过 TOML 配置 LLM 和 Agent 评审器
  4. 04多奖励维度与分数聚合
  5. 05输出分数及标准明细

适用场景

  1. 01用文件或命令检查任务输出
  2. 02通过 LLM 或 Agent 评审主观质量
  3. 03分别记录正确性与质量得分
  4. 04在共享或独立验证环境中运行检查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/harbor-framework/harbor --skill rewardkit

安装后在 Claude Code 中输入/rewardkit确认已加载。

详细介绍

帮助用户使用 Reward Kit 编写任务验证器。Reward Kit 是一个轻量级的 Python 包,可将包含条件文件的目录转换为奖励分数。每个条件都是 Python 函数调用或 TOML 裁判文件;每个文件夹对应一个独立奖励。

在 Harbor 任务中设置

将条件文件放在任务 tests/ 目录中,与 test.sh 同级:

tests/
├── test.sh
├── checks.py         # programmatic criteria
└── judge.toml        # optional LLM/agent judge

tests/test.sh:

#!/bin/bash
uvx --python '>=3.12,<3.14' --from 'harbor-rewardkit==0.2.*' rewardkit /tests

此脚本会针对 /app 中的工作区运行 /tests/ 中的所有条件,并将结果写入 /logs/verifier/reward.json。默认设置符合 Harbor 的约定,无需额外配置。

如果裁判条件需要 API 密钥,请通过 task.toml 传入:

[verifier.env]
ANTHROPIC_API_KEY = "${ANTHROPIC_API_KEY}"

询问 Reward Kit 应在 Agent 的共享环境中运行,还是在单独的验证器环境中运行。如果裁判提示词、评分依赖项、API 密钥或无干扰环境检查不应提供给 Agent,优先使用单独的验证器环境:

[environment]
network_mode = "no-network"   # Agent env baseline — offline during agent.run()

[verifier]
environment_mode = "separate"

[verifier.environment]
network_mode = "public"     # Verifier env baseline — LLM judge API calls
docker_image = "python:3.12-slim"

在共享模式下,验证器会在 Agent 容器中运行,并继承 [environment].network_mode。仅当 verify() 需要与 Agent 阶段不同的网络访问权限时,才设置 [verifier].network_mode(这是阶段级覆盖,不是基准设置)。如果 Agent 和验证器需要不同的基准设置,且不需要在运行时切换,请使用 environment_mode = "separate",并设置 [verifier.environment].network_mode。

调用外部 API 的裁判条件需要在验证器环境中使用 public 基准设置或允许列表。只读取本地文件的程序化检查可以使用 no-network。

在单独模式下,tests/ 是验证器镜像的构建上下文,且必须在运行时提供 /tests/test.sh;Harbor 不会将 tests/ 上传到正在运行的验证器容器中。

程序化条件

在 tests/ 中的任意 .py 文件里调用内置条件:

import rewardkit as rk

rk.file_exists("output.txt")
rk.file_contains("output.txt", "hello")
rk.command_succeeds("python main.py", weight=2.0)
rk.json_key_equals("result.json", "status", "ok")

所有条件都接受 weight(默认值为 1.0)和 isolated(默认值为 False,在 overlayfs 中运行,因此副作用不会泄漏)。

可用的内置条件
  • 文件:file_exists、file_not_exists、file_contains、file_contains_regex、file_matches、files_equal、diff_ratio
  • 命令:command_succeeds、command_output_contains、command_output_matches、command_output_matches_regex(默认超时为 30s,可选 cwd)
  • 数据:json_key_equals、json_path_equals、csv_cell_equals、xlsx_cell_equals(需要 [office] extra)、sqlite_query_equals
  • HTTP:http_status_equals、http_response_contains
  • 图像:image_similarity、image_size_equals(需要 [image] extra)
  • 轨迹:trajectory_tool_used、trajectory_tool_not_used、trajectory_turn_count

如需安装额外组件,请运行 uv tool install harbor-rewardkit[all]。

自定义条件

使用 @criterion 装饰器。第一个参数始终是 workspace: Path。返回值可以是 bool、float,也可以是包含 score 以及可选 reasoning、confidence 和 model 的字典:

from pathlib import Path
from rewardkit import criterion

@criterion
def has_valid_output(workspace: Path) -> bool:
    return (workspace / "output.txt").read_text().strip() != ""

零参数条件会自动注册。带额外参数的条件必须通过 rk 调用:

@criterion(description="output has at least {n} lines")
def has_n_lines(workspace: Path, n: int) -> bool:
    return len((workspace / "output.txt").read_text().splitlines()) >= n

rk.has_n_lines(10, weight=2.0)
rk.has_n_lines(50, weight=1.0)

如需在多个奖励子目录中共享条件,请在根目录文件中使用 shared=True 定义条件,然后从子目录中调用。

裁判条件(LLM 或 Agent 裁判)

对于主观检查(质量、可读性、边缘情况),请创建 TOML 文件:

[judge]
judge = "anthropic/claude-opus-5-5"   # LiteLLM model string
files = ["/app/main.py"]

[[criterion]]
description = "Is the code correct?"
type = "binary"

[[criterion]]
description = "How readable is the code?"
type = "likert"
points = 5
weight = 2.0

条件类型:

  • binary — 是/否 → 1.0 或 0.0
  • likert — 1..points,归一化到 [0, 1]
  • numeric — min..max,归一化到 [0, 1]
  • rubric — 包含 2 到 10 个描述性 levels,构成从最差到最好的等级;位置决定分数
Agent 裁判

Agent 裁判会调用 CLI,并可浏览文件系统:

[judge]
judge = "claude-code"
model = "anthropic/claude-opus-5-5"
isolated = true

[[criterion]]
description = "Does the solution handle edge cases?"
type = "binary"

它们比 LLM 裁判更慢、成本更高,但可以运行命令并检查文件。

JEV 评审器

JEV 是 TypeSafe 推出的一种新型语言模型。它会为每项标准给出概率或评分细则分数,不提供推理过程,因此速度快、成本低。它需要 jev 附加依赖(harbor-rewardkit[jev])和 TYPESAFE_API_KEY。

[judge]
judge = "jev"
files = ["/app/answer.md"]

[[criterion]]
description = "Does the answer address the requested task?"

[[criterion]]
description = "How complete is the answer?"
type = "rubric"
levels = ["Omits the information", "Covers part of it", "Covers all of it"]

二元标准的概率达到 0.5 或更高即为通过。仅支持 binary 和 rubric 标准以及文本文件;不支持 atif-trajectory 和 prompt_template。 任务镜像需要 CA 证书(Debian 和 Ubuntu 上的 ca-certificates),因为 TypeSafe SDK 会使用系统信任库验证 TLS。

实用的 [judge] 选项

timeout(默认值为 300)、reasoning_effort(每种 LLM 和 Agent 评审器均支持 low|medium|high,其他级别取决于评审器;jev 不接受此选项)、reference(参考解决方案的路径)、atif-trajectory(评估 Agent 的执行轨迹)、weight、prompt_template(包含 {criteria} 占位符的自定义提示词)、samples(运行评审器 N 次,并以各项标准的样本中位数计分)、guard(防止评审器受到 Agent 写入待评分文件中的指令影响;"flag" 会在详情的 guard 字段下报告这些指令,"penalize" 还会将被标记的提交计为 0)、isolated(仅适用于 Agent 评审器:工作区的只读 overlayfs 副本)。如果任务中运行多个 Agent(多个 Agent 评审器、samples 大于 1,或包含多项标准的 individual 模式),则每个 Agent 评审器都必须设置 isolated = true,这需要单独的验证器,并具备 fuse-overlayfs 和挂载权限;--yolo 可跳过检查。

评分聚合(在单个评审器 TOML 内)
[scoring]
aggregation = "all-pass"   # weighted-mean | weighted-sum | all-pass | any-pass | threshold | required-pass
threshold = 0.7             # only for threshold

只有分数为 1.0 时,all-pass、any-pass 和 required-pass 才会将其视为通过,因此 Likert 或数值标准需要获得满分。

这只影响此文件自身标准的组合方式。若要跨维度聚合,请参阅聚合维度。

程序化文件的评分配置

每个注册标准的 .py 文件都是一个等权评分组件,其名称取自文件名主体。仅提供导入项或共享标准工厂、不注册任何检查的文件会被忽略。若要更改文件内标准的组合方式,请在同一目录的 reward.toml 中使用 [scoring.<stem>]:

# tests/structure/reward.toml
[scoring.files_exist]       # configures files_exist.py
aggregation = "all-pass"

[scoring.behavior]          # configures behavior.py
aggregation = "threshold"
threshold = 0.75

每个条目采用与评审器 TOML 相同的聚合值。未知键以及无法解析为包含标准的 Python 文件的文件名主体都会引发错误。

目录可以递归嵌套。非根目录可以通过一个未命名的 [[reward]] 表聚合本地 Python 文件、本地评审器和直接子目录:

# tests/correctness/reward.toml
[[reward]]
aggregation = "weighted-mean"
weights = { files = 2.0, behavior = 1.0 }

成员关系为隐式设置。除非另行指定,子目录的权重为 1.0;本地 Python 文件和评审器 TOML 使用文件名主体,子分组使用目录名。若没有 [[reward]],目录默认采用加权平均。

多奖励任务

将标准放在子目录中——每个子目录都会成为单独的奖励:

tests/
├── test.sh
├── correctness/
│   └── check.py
├── structure/
│   └── files_exist.py
└── quality/
    └── quality.toml

评审器 TOML 也可以直接放在 tests 根目录下,与奖励子目录并列。每个文件都会作为顶层奖励公开,其名称取自文件名主体,并可供根级聚合引用。

tests 根目录中包含标准的 Python 文件也会成为顶层维度,名称取自文件名主体。根目录中未注册任何标准的支持文件会被忽略。

生成:

{ "correctness": 0.75, "structure": 1.0, "quality": 0.6 }
聚合维度

若要在各维度分数之上添加聚合分数,请在根目录下添加 tests/reward.toml,其中包含一个或多个 [[reward]] 表。每个表都会向 reward.json 添加一个键,使用与 [scoring] 相同的模式聚合各维度:

# tests/reward.toml
[[reward]]
name = "reward"
aggregation = "weighted-mean"
weights = { correctness = 2.0, quality = 1.0 }
{ "correctness": 0.75, "structure": 1.0, "quality": 0.6, "reward": 0.775 }

各维度分数会保留;聚合键会与它们并列添加(name 不得与维度名称冲突)。除非该聚合的内联映射另有指定,否则顶层维度的权重相同;reward-details.json 会保留完整的递归明细。

输出文件

  • /logs/verifier/reward.json — 每项奖励的分数
  • /logs/verifier/reward-details.json — 每项标准的结果、评审推理和错误

多步任务

在多步任务中,每个步骤都有自己的 tests/,位于 steps/{name}/tests/,验证器会针对每个步骤运行一次。Reward Kit 的行为 与单步任务相同:对于每个步骤,它会读取 /tests,针对 /app 运行各项标准, 并为该步骤写入 /logs/verifier/reward.json。 然后,Harbor 会通过 task.toml 中的 multi_step_reward_strategy 将每步结果 汇总为试验级奖励——汇总发生在 Reward Kit 之外,因此不要尝试在标准中编码跨步骤逻辑。

任务级 tests/ 目录(位于任务根目录)会先上传至 /tests,然后再叠加该步骤自己的 tests/(同名文件优先)。 将共享辅助项(设置了 shared=True 的通用 checks.py 函数、fixture 文件、备用 test.sh)放在任务级目录中,并将步骤专属标准放在各步骤下。

多奖励子目录在单个步骤内仍然有效:steps/foo/tests/ 可以包含 correctness/、structure/、quality/——每个目录都会为该步骤生成一个单独的奖励键,而 multi_step_reward_strategy = "mean" 会对各步骤的每个键取平均值。如果最后一步是端到端检查,且其奖励已代表整个任务,则使用 "final"。

如何选择

  • 使用内置功能检查文件是否存在、字符串匹配、命令输出、JSON/CSV,以及 HTTP 探测。
  • **使用 @criterion**处理任务专属但仍可通过程序判断的逻辑。
  • 使用 LLM 评审器评估主观质量维度(可读性、文本正确性)。
  • 使用 Agent 评审器处理要求探索文件系统或运行代码的评分标准(例如“测试套件是否确实通过?”)。
  • 使用子目录分别评分(正确性、结构、质量),而不是合并为一个分数。
  • 对任何会运行修改性命令的标准使用 isolated=True,以免损坏其他标准使用的工作区。

示例

请参阅 Harbor 仓库中的 examples/tasks/reward-kit-example/。

评论

支持 Markdown