rewardkit について
rewardkitは、プログラムによるチェックやTOML設定のLLM・エージェント判定器でタスク検証器を作るPythonパッケージとスキルです。Harborのタスク作成者向けに、基準の組み合わせ、評価軸ごとの採点、スコア集計を提供します。
主な機能
- 01ファイル、コマンド、データ、HTTP、画像、軌跡の検査
- 02重み付きのカスタムPython基準
- 03TOMLによるLLM・エージェント判定器の設定
- 04複数の報酬軸とスコア集計
- 05スコアと基準別の詳細を出力
活用シーン
- 01ファイルやコマンドでタスク出力を採点
- 02LLMやエージェント判定器で主観的な品質を評価
- 03正確性と品質のスコアを分けて記録
- 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
これにより、/tests/ 内のすべての基準を /app のワークスペースに対して実行し、/logs/verifier/reward.json に書き込みます。デフォルト設定は Harbor の規約に沿っているため、追加の設定は不要です。
評価基準で API キーが必要な場合は、task.toml 経由で渡します。
[verifier.env]
ANTHROPIC_API_KEY = "${ANTHROPIC_API_KEY}"
Reward Kit をエージェントの共有環境で実行するか、別の検証環境で実行するかを確認してください。評価プロンプト、採点の依存関係、API キー、またはクリーンルームチェックをエージェントから利用できないようにする場合は、別の検証環境を使用してください。
[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"
共有モードでは、検証器はエージェントのコンテナ内で実行され、[environment].network_mode を引き継ぎます。verify() にエージェントのフェーズとは異なるネットワークアクセスが必要な場合に限り、[verifier].network_mode を設定してください(これはベースラインではなく、フェーズの上書き設定です)。エージェントと検証器に異なるベースラインが必要で、実行時の切り替えを行わない場合は、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(デフォルトのタイムアウトは 30 秒、cwdは任意) - データ:
json_key_equals、json_path_equals、csv_cell_equals、xlsx_cell_equals([office]エクストラが必要)、sqlite_query_equals - HTTP:
http_status_equals、http_response_contains - 画像:
image_similarity、image_size_equals([image]エクストラが必要) - 軌跡:
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 を含む dict です。
from pathlib import Path
from rewardkit import criterion
@criterion
def has_valid_output(workspace: Path) -> bool:
return (workspace / "output.txt").read_text().strip() != ""
パラメーターが 0 個の基準は自動的に登録されます。追加の引数を取る基準は 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 または評価者としてのエージェント)
品質、可読性、エッジケースなどの主観的なチェックには、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.0likert— 1..points。正規化して [0, 1] にしますnumeric— min..max。正規化して [0, 1] にしますrubric— 最低から最高までの尺度を構成する、説明付きのlevelsを 2 ~ 10 個指定します。位置によってスコアが決まります
エージェント評価者
エージェント評価者は 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 判定器とエージェント判定器では low|medium|high。その他のレベルは判定器によって異なります。jev は受け付けません)、reference(参照解のパス)、atif-trajectory(エージェントの軌跡を評価)、weight、prompt_template({criteria} プレースホルダーを含むカスタムプロンプト)、samples(判定器を N 回実行し、各評価基準をサンプルの中央値で採点)、guard(採点対象のファイルにエージェントが書き込んだ指示から判定器を保護します。"flag" は詳細の guard に報告し、"penalize" はフラグが付いた提出物も 0 点にします)、isolated(エージェント判定器のみ:ワークスペースの読み取り専用 overlayfs コピー)。タスク内で複数のエージェント実行(複数のエージェント判定器、1 より大きい samples、または複数の評価基準を持つ個別モード)を行う場合、各エージェント判定器で isolated = true が必要です。そのため、fuse-overlayfs とマウント権限を備えた専用の検証環境が必要です。--yolo を指定するとチェックをスキップします。
スコア集計(1 つの judge TOML 内)
[scoring]
aggregation = "all-pass" # weighted-mean | weighted-sum | all-pass | any-pass | threshold | required-pass
threshold = 0.7 # only for threshold
all-pass、any-pass、required-pass では、スコアが 1.0 の場合にのみ合格として扱われるため、リッカート尺度または数値の評価基準には満点が必要です。
これは、このファイル内の評価基準をどのように組み合わせるかだけに影響します。ディメンション間の集計については、ディメンションの集計を参照してください。
プログラムファイルのスコア設定
評価基準を登録する各 .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
各エントリーには judge TOML と同じ集計値を指定します。未知のキーや、評価基準を含む Python ファイルに解決されないステムを指定するとエラーになります。
ディレクトリは再帰的にネストできます。ルート以外のディレクトリでは、名前のない [[reward]] テーブルを 1 つ使って、そのディレクトリ内の Python ファイル、判定器、および直下の子ディレクトリを集計できます。
# tests/correctness/reward.toml
[[reward]]
aggregation = "weighted-mean"
weights = { files = 2.0, behavior = 1.0 }
メンバーシップは暗黙的に決まります。子ディレクトリの重みは、上書きしない限り 1.0 です。ローカルの Python ファイルと judge TOML にはファイル名のステムを、子グループにはディレクトリ名を使用します。[[reward]] がない場合、ディレクトリはデフォルトで加重平均になります。
複数報酬タスク
評価基準をサブディレクトリに置きます。各ディレクトリが個別の報酬になります。
tests/
├── test.sh
├── correctness/
│ └── check.py
├── structure/
│ └── files_exist.py
└── quality/
└── quality.toml
judge TOML は、報酬サブディレクトリと並べて tests ルートに直接置くこともできます。それぞれのファイル名のステムにちなんだトップレベル報酬として公開され、ルートの集計から参照できます。
評価基準を含む Python ファイルを tests ルートに置いた場合も、ステムにちなんだトップレベルのディメンションになります。評価基準を登録しないルートのサポートファイルは無視されます。
生成される内容:
{ "correctness": 0.75, "structure": 1.0, "quality": 0.6 }
ディメンションの集計
ディメンションごとのキーに集計スコアを追加するには、ルートレベルの tests/reward.toml に [[reward]] テーブルを 1 つ以上追加します。それぞれのテーブルで reward.json にキーが 1 つ追加され、[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 に対して基準を実行し、そのステップの reward.json を /logs/verifier/reward.json に書き込みます。
その後、Harbor が task.toml の multi_step_reward_strategy を使ってステップごとの結果を試行単位の報酬に集約します。集約は Reward Kit の外部で行われるため、基準にステップ間のロジックを組み込まないでください。
タスクレベルの tests/ ディレクトリ(タスクルートにあります)が最初に /tests にアップロードされ、その後、ステップ独自の tests/ が上書きレイヤーとして追加されます(同名ファイルが優先されます)。
共有ヘルパー(shared=True の共通 checks.py 関数、フィクスチャファイル、フォールバックの test.sh)はタスクレベルに置き、ステップ固有の基準は各ステップの下に置いてください。
複数報酬用のサブディレクトリは、引き続きステップ内で利用できます。steps/foo/tests/ に correctness/、structure/、quality/ を含めると、各ディレクトリがそのステップの個別の報酬キーを生成し、multi_step_reward_strategy = "mean" は各キーをステップ間で平均します。最後のステップがタスク全体を対象とするエンドツーエンドのチェックで、その報酬がすでにタスク全体を表している場合は、"final" を使用してください。
用途に応じた選び方
- 組み込み機能を使う:ファイルの存在確認、文字列の一致、コマンド出力、JSON/CSV のチェック、HTTP プローブ。
@criterionを使う:ロジックがタスク固有でありながら、プログラムで評価できる場合。- LLM 判定器を使う:読みやすさや文章の正確さなど、主観的な品質を評価する場合。
- エージェント判定器を使う:ルーブリックの評価にファイルシステムの探索やコードの実行が必要な場合(例:「テストスイートは実際にパスするか?」)。
- サブディレクトリを使う:1 つの合成スコアではなく、正確性・構造・品質などを個別に採点したい場合。
isolated=Trueを使う:変更を伴うコマンドを実行する基準では、他の基準のワークスペースを破損させないようにします。
使用例
Harbor リポジトリの examples/tasks/reward-kit-example/ を参照してください。