tf-rewardkit 1.6.3__tar.gz → 1.6.4.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/PKG-INFO +1 -1
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/pyproject.toml +1 -1
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/__init__.py +0 -1
- tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/_judge_args.py +198 -0
- tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/agentic.py +136 -0
- tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/llm_judge.py +145 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/executor.py +0 -4
- tf_rewardkit-1.6.3/src/rewardkit/workflow/component/_source.py +0 -188
- tf_rewardkit-1.6.3/src/rewardkit/workflow/component/agentic.py +0 -184
- tf_rewardkit-1.6.3/src/rewardkit/workflow/component/llm_judge.py +0 -233
- tf_rewardkit-1.6.3/src/rewardkit/workflow/converter/__init__.py +0 -19
- tf_rewardkit-1.6.3/src/rewardkit/workflow/converter/_convert.py +0 -467
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/LICENSE +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/README.md +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/__init__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/__main__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/agents.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/compare.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/__init__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/_command.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/_trajectory.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_contains.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_matches.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_matches_regex.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_succeeds.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/csv_cell_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/diff_ratio.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_contains.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_contains_regex.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_exists.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_matches.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_not_exists.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/files_equal.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/http_response_contains.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/http_status_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/image_similarity.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/image_size_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/json_key_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/json_path_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/sqlite_query_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_tool_not_used.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_tool_used.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_turn_count.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/xlsx_cell_equals.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/isolation.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/judges.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/models.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/agent.md +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/llm.md +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/llm_trajectory.md +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/reward.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/runner.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/session.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/trajectory.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/attribution.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/cli.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/README.md +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/__init__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/__init__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/budget.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/rubric.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/salvage.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/scoring.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/code.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/consume_upstream.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/contracts.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/criterion.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/do_nothing.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/fail.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/llm_stub.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/__init__.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_code_methods.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_compute.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_content.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_contract.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_ctx.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_faults.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_html_render.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_pptx_render.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_render_common.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_tagging.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_visual.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_vlm.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/aggregate.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/content.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/gate.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/render.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/tag.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/visual.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/produce_value.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/registry.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/context.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/diagram.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/errors.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/loader.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/model_service.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/plan.py +0 -0
- {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/scoring.py +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""args 传参判分组件(``llm_judge@1`` / ``agentic@1``)的共享私有helper。
|
|
2
|
+
|
|
3
|
+
两个组件不经任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个
|
|
4
|
+
node 对应一次 ``arun_llm`` / ``arun_agent`` 调用。本模块承载三块共享逻辑:
|
|
5
|
+
|
|
6
|
+
- ``criteria`` 槽解析:TOML inline table 的数组,元素字段对齐存量 judge
|
|
7
|
+
TOML 的 ``[[criterion]]`` 表(``description`` 必填,其余选填、缺省值同
|
|
8
|
+
存量配置);元素形状校验失败返回原因串由调用方按 unjudged 处置——评分
|
|
9
|
+
项配置问题是清单问题,不是节点运行失败;
|
|
10
|
+
- 覆盖链解析:model 链 ``context.model_name``(CLI)> ``REWARDKIT_MODEL``
|
|
11
|
+
> 额外 env(如 ``REWARDKIT_JUDGE``)> args 槽 > 组件缺省;agent 链
|
|
12
|
+
``context.judge``(CLI)> agent 专用 env > ``REWARDKIT_JUDGE``(仅当值
|
|
13
|
+
在 known_agents 注册表内才采用——部署里该变量常被设成 LLM 模型名)>
|
|
14
|
+
args 槽 > 组件缺省;
|
|
15
|
+
- ``files`` 槽锚定:相对路径一律按 workspace 根解析(判分调用直读路径
|
|
16
|
+
相对进程 CWD,而 workspace 是独立注入的)。
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from rewardkit.models import Binary, Criterion, Likert, Numeric, Rubric
|
|
26
|
+
|
|
27
|
+
JUDGE_NAME_ENV = "REWARDKIT_JUDGE"
|
|
28
|
+
"""通用 judge 名覆盖变量(LLM 侧作模型名通道,agent 侧须过注册表门槛)。"""
|
|
29
|
+
|
|
30
|
+
MODEL_NAME_ENV = "REWARDKIT_MODEL"
|
|
31
|
+
"""模型名覆盖变量(两个组件的 model 链共用)。"""
|
|
32
|
+
|
|
33
|
+
_CRITERION_ENTRY_KEYS = frozenset(
|
|
34
|
+
{
|
|
35
|
+
"description",
|
|
36
|
+
"type",
|
|
37
|
+
"name",
|
|
38
|
+
"id",
|
|
39
|
+
"points",
|
|
40
|
+
"levels",
|
|
41
|
+
"min",
|
|
42
|
+
"max",
|
|
43
|
+
"weight",
|
|
44
|
+
"files",
|
|
45
|
+
"negate",
|
|
46
|
+
"optional",
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _output_format_for_entry(entry: dict[str, Any]) -> Any:
|
|
52
|
+
"""元素 type/points/levels/min/max → OutputFormat(映射对齐存量
|
|
53
|
+
``runner._build_criteria_from_toml``:likert → ``Likert(points)``、
|
|
54
|
+
numeric → ``Numeric(min, max)``、rubric → ``Rubric(levels)``、其余 →
|
|
55
|
+
``Binary()``)。"""
|
|
56
|
+
ctype = entry.get("type", "binary")
|
|
57
|
+
if ctype == "likert":
|
|
58
|
+
return Likert(points=entry.get("points", 5))
|
|
59
|
+
if ctype == "numeric":
|
|
60
|
+
return Numeric(min=entry.get("min", 0.0), max=entry.get("max", 1.0))
|
|
61
|
+
if ctype == "rubric":
|
|
62
|
+
return Rubric(levels=tuple(entry.get("levels", ())))
|
|
63
|
+
return Binary()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _validate_entry(entry: dict[str, Any], index: int) -> str | None:
|
|
67
|
+
"""单元素字段级校验;返回原因串或 None(合法)。"""
|
|
68
|
+
unknown = set(entry) - _CRITERION_ENTRY_KEYS
|
|
69
|
+
if unknown:
|
|
70
|
+
return f"criteria 元素 {index} 含未知字段:{sorted(unknown)}"
|
|
71
|
+
description = entry.get("description")
|
|
72
|
+
if not isinstance(description, str) or not description.strip():
|
|
73
|
+
return f"criteria 元素 {index} 缺少非空 description 字段"
|
|
74
|
+
ctype = entry.get("type", "binary")
|
|
75
|
+
if ctype not in ("binary", "likert", "numeric", "rubric"):
|
|
76
|
+
return f"criteria 元素 {index} 的 type 非法:{ctype!r}"
|
|
77
|
+
if "points" in entry and not isinstance(entry["points"], int):
|
|
78
|
+
return f"criteria 元素 {index} 的 points 必须是整数"
|
|
79
|
+
if "levels" in entry and not (
|
|
80
|
+
isinstance(entry["levels"], (list, tuple))
|
|
81
|
+
and all(isinstance(level, str) for level in entry["levels"])
|
|
82
|
+
):
|
|
83
|
+
return f"criteria 元素 {index} 的 levels 必须是字符串数组"
|
|
84
|
+
for field in ("min", "max", "weight"):
|
|
85
|
+
if field in entry and not isinstance(entry[field], (int, float)):
|
|
86
|
+
return f"criteria 元素 {index} 的 {field} 必须是数值"
|
|
87
|
+
for field in ("negate", "optional"):
|
|
88
|
+
if field in entry and not isinstance(entry[field], bool):
|
|
89
|
+
return f"criteria 元素 {index} 的 {field} 必须是布尔"
|
|
90
|
+
if "files" in entry and not (
|
|
91
|
+
isinstance(entry["files"], (list, tuple))
|
|
92
|
+
and all(isinstance(item, str) for item in entry["files"])
|
|
93
|
+
):
|
|
94
|
+
return f"criteria 元素 {index} 的 files 必须是字符串数组"
|
|
95
|
+
for field in ("name", "id"):
|
|
96
|
+
if field in entry and entry[field] is not None and not isinstance(entry[field], str):
|
|
97
|
+
return f"criteria 元素 {index} 的 {field} 必须是字符串"
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def parse_criteria_entries(
|
|
102
|
+
entries: Any, workspace_root: Any
|
|
103
|
+
) -> tuple[list[Criterion], list[float], str | None]:
|
|
104
|
+
"""解析 ``criteria`` 槽,返回 ``(criteria, weights, 原因串)``。
|
|
105
|
+
|
|
106
|
+
原因串非 None 表示槽非法(调用方按 unjudged 处置);合法时原因串为
|
|
107
|
+
None,weights 与 criteria 按下标一一对应(元素 ``weight`` 缺省 1.0)。
|
|
108
|
+
"""
|
|
109
|
+
if isinstance(entries, (str, dict)) or not isinstance(entries, (list, tuple)):
|
|
110
|
+
return [], [], "criteria 必须是评分项表的数组(args 的 array 槽)"
|
|
111
|
+
if not entries:
|
|
112
|
+
return [], [], "criteria 不能为空数组"
|
|
113
|
+
|
|
114
|
+
criteria: list[Criterion] = []
|
|
115
|
+
weights: list[float] = []
|
|
116
|
+
for index, entry in enumerate(entries):
|
|
117
|
+
if not isinstance(entry, dict):
|
|
118
|
+
return [], [], f"criteria 元素 {index} 必须是表,收到 {type(entry).__name__}"
|
|
119
|
+
reason = _validate_entry(entry, index)
|
|
120
|
+
if reason:
|
|
121
|
+
return [], [], reason
|
|
122
|
+
try:
|
|
123
|
+
output_format = _output_format_for_entry(entry)
|
|
124
|
+
criterion = Criterion(
|
|
125
|
+
description=entry["description"],
|
|
126
|
+
output_format=output_format,
|
|
127
|
+
name=entry.get("name") or None,
|
|
128
|
+
id=entry.get("id"),
|
|
129
|
+
files=abs_files(entry.get("files", ()), workspace_root),
|
|
130
|
+
negate=entry.get("negate", False),
|
|
131
|
+
optional=entry.get("optional", False),
|
|
132
|
+
)
|
|
133
|
+
except Exception as exc: # noqa: BLE001 - name/output_format 非法属清单问题
|
|
134
|
+
return [], [], f"criteria 元素 {index} 构造失败(name 或 output_format 非法):{exc}"
|
|
135
|
+
criteria.append(criterion)
|
|
136
|
+
weights.append(float(entry.get("weight", 1.0)))
|
|
137
|
+
return criteria, weights, None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def abs_files(entries: Any, workspace_root: Any) -> tuple[str, ...]:
|
|
141
|
+
"""路径列表按 workspace 根锚定;绝对路径原样。"""
|
|
142
|
+
resolved = []
|
|
143
|
+
for entry in entries:
|
|
144
|
+
path = Path(str(entry))
|
|
145
|
+
resolved.append(str(path if path.is_absolute() else Path(workspace_root) / path))
|
|
146
|
+
return tuple(resolved)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def resolve_arg_files(files: Any, workspace_root: Any) -> tuple[str, ...]:
|
|
150
|
+
"""``files`` 槽:单路径字符串或路径列表 → 按 workspace 根锚定;
|
|
151
|
+
空值与不认识的形状落空元组。"""
|
|
152
|
+
if isinstance(files, str) and files:
|
|
153
|
+
return abs_files([files], workspace_root)
|
|
154
|
+
if isinstance(files, (list, tuple)) and files:
|
|
155
|
+
return abs_files(files, workspace_root)
|
|
156
|
+
return ()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def resolve_model(
|
|
160
|
+
context: Any,
|
|
161
|
+
slot: str | None,
|
|
162
|
+
*,
|
|
163
|
+
extra_envs: tuple[str, ...] = (),
|
|
164
|
+
default: str | None = None,
|
|
165
|
+
) -> str | None:
|
|
166
|
+
"""model 覆盖链:``context.model_name``(CLI)> ``REWARDKIT_MODEL`` >
|
|
167
|
+
``extra_envs`` 逐个 > args 槽 > ``default``。"""
|
|
168
|
+
candidates = [getattr(context, "model_name", None), os.environ.get(MODEL_NAME_ENV)]
|
|
169
|
+
candidates += [os.environ.get(name) for name in extra_envs]
|
|
170
|
+
candidates += [slot, default]
|
|
171
|
+
for value in candidates:
|
|
172
|
+
if value:
|
|
173
|
+
return str(value)
|
|
174
|
+
return default
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def resolve_agent(
|
|
178
|
+
context: Any,
|
|
179
|
+
slot: str | None,
|
|
180
|
+
*,
|
|
181
|
+
agent_env: str,
|
|
182
|
+
default: str,
|
|
183
|
+
) -> str:
|
|
184
|
+
"""agent 覆盖链:``context.judge``(CLI)> ``agent_env`` >
|
|
185
|
+
``REWARDKIT_JUDGE``(仅当值在 known_agents 内才采用)> args 槽 >
|
|
186
|
+
``default``。"""
|
|
187
|
+
from rewardkit.agents import known_agents
|
|
188
|
+
|
|
189
|
+
cli_judge = getattr(context, "judge", None)
|
|
190
|
+
if cli_judge:
|
|
191
|
+
return str(cli_judge)
|
|
192
|
+
env_agent = os.environ.get(agent_env)
|
|
193
|
+
if env_agent:
|
|
194
|
+
return env_agent
|
|
195
|
+
env_judge = os.environ.get(JUDGE_NAME_ENV)
|
|
196
|
+
if env_judge in known_agents():
|
|
197
|
+
return env_judge
|
|
198
|
+
return slot or default
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""agentic 判分组件 ``agentic@1``:编码智能体 judge 的图内入口(args 传参薄封装)。
|
|
2
|
+
|
|
3
|
+
不读任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个 node
|
|
4
|
+
一次 ``arun_agent`` 调用。
|
|
5
|
+
|
|
6
|
+
- ``criteria`` 必填槽为评分项表的数组(元素字段与权重语义同
|
|
7
|
+
``llm_judge@1``);
|
|
8
|
+
- 其余选填槽与 ``AgentJudge`` 字段逐字同名(``agent`` / ``model`` /
|
|
9
|
+
``version`` / ``timeout`` / ``cwd`` / ``isolated`` / ``atif_trajectory``
|
|
10
|
+
/ ``mode`` / ``mcp_servers``),另加 ``system_prompt``;槽不写即不传
|
|
11
|
+
该字段,落 ``AgentJudge`` 自身缺省(``isolated`` 缺省 False 与宿主
|
|
12
|
+
对齐,组件层不自造缺省);槽值非法(如 agent 不在注册表内)按
|
|
13
|
+
unjudged 处置;
|
|
14
|
+
- agent 覆盖链:``context.judge``(CLI --judge)> ``REWARDKIT_AGENT``
|
|
15
|
+
环境变量 > ``REWARDKIT_JUDGE``(**仅当值在 known_agents 注册表内才
|
|
16
|
+
采用**——该变量常被设成 LLM 模型名)> args ``agent`` > 组件缺省
|
|
17
|
+
``codex``;agent 名的注册表校验由 AgentJudge 的 validator 兜底(非法
|
|
18
|
+
名显式报错,错误消息含已知 agent 列表);
|
|
19
|
+
- model 覆盖链:``context.model_name`` > ``REWARDKIT_MODEL`` 环境变量 >
|
|
20
|
+
args ``model`` > None(AgentJudge 自身缺省);
|
|
21
|
+
- ``cwd`` 槽缺省时由 workspace 根兜底(``arun_agent`` 自身语义:
|
|
22
|
+
``judge.cwd or workspace``);
|
|
23
|
+
- 产出 ``{"scores": [{"id", "score", "reasoning", "warnings", "weight",
|
|
24
|
+
"optional"}, ...], "output", "warnings", "judge_logs"}``(信封语义同
|
|
25
|
+
``llm_judge@1``)。agentic 没有门控职责,判 0 分也是有效判定,**调用
|
|
26
|
+
异常不由组件转 Failure**(冒泡为任务失败,由归因层收集);
|
|
27
|
+
``criteria`` 槽非法 → unjudged。
|
|
28
|
+
|
|
29
|
+
真实 Codex 执行的验证在 AP 题包与原生格式端到端验证中走过;仓库内
|
|
30
|
+
测试用假 backend 打桩。
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
from rewardkit.judges import arun_agent
|
|
38
|
+
from rewardkit.models import AgentJudge
|
|
39
|
+
from rewardkit.workflow.component._judge_args import (
|
|
40
|
+
parse_criteria_entries,
|
|
41
|
+
resolve_agent,
|
|
42
|
+
resolve_model,
|
|
43
|
+
)
|
|
44
|
+
from rewardkit.workflow.component.registry import InputSlot, component
|
|
45
|
+
|
|
46
|
+
AGENT_NAME_ENV = "REWARDKIT_AGENT"
|
|
47
|
+
DEFAULT_AGENT = "codex"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@component(
|
|
51
|
+
name="agentic",
|
|
52
|
+
version=1,
|
|
53
|
+
outputs=["verdict"],
|
|
54
|
+
inputs=[
|
|
55
|
+
InputSlot(
|
|
56
|
+
name="criteria",
|
|
57
|
+
accepted_types=("array",),
|
|
58
|
+
description="评分项表的数组,元素字段对齐存量 [[criterion]] 表",
|
|
59
|
+
),
|
|
60
|
+
InputSlot(name="agent", required=False, accepted_types=("string",)),
|
|
61
|
+
InputSlot(name="model", required=False, accepted_types=("string",)),
|
|
62
|
+
InputSlot(name="version", required=False, accepted_types=("string",)),
|
|
63
|
+
InputSlot(name="timeout", required=False, accepted_types=("int",)),
|
|
64
|
+
InputSlot(name="cwd", required=False, accepted_types=("string",)),
|
|
65
|
+
InputSlot(name="isolated", required=False, accepted_types=("bool",)),
|
|
66
|
+
InputSlot(name="atif_trajectory", required=False, accepted_types=("string",)),
|
|
67
|
+
InputSlot(name="mode", required=False, accepted_types=("string",)),
|
|
68
|
+
InputSlot(name="mcp_servers", required=False, accepted_types=("array",)),
|
|
69
|
+
InputSlot(name="system_prompt", required=False, accepted_types=("string",)),
|
|
70
|
+
],
|
|
71
|
+
)
|
|
72
|
+
async def agentic(
|
|
73
|
+
context,
|
|
74
|
+
criteria,
|
|
75
|
+
agent=None,
|
|
76
|
+
model=None,
|
|
77
|
+
version=None,
|
|
78
|
+
timeout=None,
|
|
79
|
+
cwd=None,
|
|
80
|
+
isolated=None,
|
|
81
|
+
atif_trajectory=None,
|
|
82
|
+
mode=None,
|
|
83
|
+
mcp_servers=None,
|
|
84
|
+
system_prompt=None,
|
|
85
|
+
) -> dict[str, Any]:
|
|
86
|
+
"""``arun_agent`` 的薄封装:评分项与调用配置全来自 args(见模块 docstring)。"""
|
|
87
|
+
root = context.workspace.root
|
|
88
|
+
criteria_objs, weights, reason = parse_criteria_entries(criteria, root)
|
|
89
|
+
if reason:
|
|
90
|
+
return {"unjudged": True, "reason": reason}
|
|
91
|
+
|
|
92
|
+
judge_kwargs: dict[str, Any] = {}
|
|
93
|
+
for key, value in (
|
|
94
|
+
("version", version),
|
|
95
|
+
("timeout", timeout),
|
|
96
|
+
("cwd", cwd),
|
|
97
|
+
("isolated", None if isolated is None else bool(isolated)),
|
|
98
|
+
("atif_trajectory", atif_trajectory),
|
|
99
|
+
("mode", mode),
|
|
100
|
+
("mcp_servers", tuple(mcp_servers) if mcp_servers else None),
|
|
101
|
+
):
|
|
102
|
+
if value is not None:
|
|
103
|
+
judge_kwargs[key] = value
|
|
104
|
+
try:
|
|
105
|
+
judge = AgentJudge(
|
|
106
|
+
agent=resolve_agent(context, agent, agent_env=AGENT_NAME_ENV, default=DEFAULT_AGENT),
|
|
107
|
+
model=resolve_model(context, model),
|
|
108
|
+
**judge_kwargs,
|
|
109
|
+
)
|
|
110
|
+
except Exception as exc: # noqa: BLE001 - 槽值非法属配置问题,按 unjudged
|
|
111
|
+
return {"unjudged": True, "reason": f"agentic 槽值非法:{exc}"}
|
|
112
|
+
|
|
113
|
+
result = await arun_agent(
|
|
114
|
+
judge,
|
|
115
|
+
criteria_objs,
|
|
116
|
+
weights,
|
|
117
|
+
workspace=str(root),
|
|
118
|
+
system_prompt=system_prompt,
|
|
119
|
+
)
|
|
120
|
+
all_scores = [
|
|
121
|
+
{
|
|
122
|
+
"id": c.id or score.name or f"criterion_{index}",
|
|
123
|
+
"score": score.value,
|
|
124
|
+
"reasoning": score.reasoning,
|
|
125
|
+
"warnings": list(result.warnings),
|
|
126
|
+
"weight": weights[index],
|
|
127
|
+
"optional": c.optional,
|
|
128
|
+
}
|
|
129
|
+
for index, (c, score) in enumerate(zip(criteria_objs, result.scores))
|
|
130
|
+
]
|
|
131
|
+
return {
|
|
132
|
+
"scores": all_scores,
|
|
133
|
+
"output": result.output,
|
|
134
|
+
"warnings": list(result.warnings),
|
|
135
|
+
"judge_logs": list(result.judge_logs),
|
|
136
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""判分组件 ``llm_judge@1``:LLM judge 的图内入口(args 传参薄封装)。
|
|
2
|
+
|
|
3
|
+
不读任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个 node
|
|
4
|
+
一次 ``arun_llm`` 调用。
|
|
5
|
+
|
|
6
|
+
- ``criteria`` 必填槽为评分项表的数组(元素字段对齐存量 judge TOML 的
|
|
7
|
+
``[[criterion]]`` 表:``description`` 必填,``type`` / ``points`` /
|
|
8
|
+
``levels`` / ``min`` / ``max`` / ``files`` / ``negate`` / ``optional`` /
|
|
9
|
+
``name`` / ``id`` / ``weight`` 选填、缺省同存量配置);条目 ``weight``
|
|
10
|
+
透传为 ``arun_llm`` 的 weights 入参与分数信封的 ``weight`` 键;
|
|
11
|
+
- 其余选填槽与 ``LLMJudge`` 字段逐字同名(``model`` / ``files`` /
|
|
12
|
+
``mode`` / ``timeout`` / ``reasoning_effort`` / ``reference`` /
|
|
13
|
+
``atif_trajectory``),另加 ``system_prompt``;槽不写即不传该字段,
|
|
14
|
+
落 ``LLMJudge`` 自身缺省(mode=batched、timeout=300 等);槽值非法
|
|
15
|
+
(如 mode 不在枚举内)按 unjudged 处置;
|
|
16
|
+
- model 覆盖链:``context.model_name``(CLI --model)> ``REWARDKIT_MODEL``
|
|
17
|
+
环境变量 > ``REWARDKIT_JUDGE`` > args ``model`` > 组件缺省;
|
|
18
|
+
- ``files`` 槽为组级共享(单路径字符串或路径列表),相对路径一律按
|
|
19
|
+
workspace 根解析(``arun_llm`` 直读路径相对进程 CWD,而 workspace 是
|
|
20
|
+
独立注入的);条目级 ``files`` 仅 individual 模式生效(存量 arun_llm
|
|
21
|
+
语义);batched 下被忽略——组件在该条目的 warnings 里记录提示,不
|
|
22
|
+
静默丢失;
|
|
23
|
+
- 产出 ``{"scores": [{"id", "score", "reasoning", "warnings", "weight",
|
|
24
|
+
"optional"}, ...], "output", "warnings"}``(``score`` 键是交分信封
|
|
25
|
+
``value`` 的别名,可直接标记 ``is_score_node``;``optional`` 进图级
|
|
26
|
+
聚合);任一次调用异常 → Failure(error_kind 为 llm-error);
|
|
27
|
+
``criteria`` 槽非法 → unjudged。
|
|
28
|
+
|
|
29
|
+
模型调用经 ``context.model``(ModelService)的 ``acompletion`` 注入
|
|
30
|
+
arun_llm——占 ``max_concurrent_workflow`` 名额;注入的替身无
|
|
31
|
+
acompletion 时回退 litellm 直调。
|
|
32
|
+
|
|
33
|
+
本组件不 import prefect(分层约束)。
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
from typing import Any
|
|
39
|
+
|
|
40
|
+
from rewardkit.judges import arun_llm
|
|
41
|
+
from rewardkit.models import LLMJudge
|
|
42
|
+
from rewardkit.workflow.component._judge_args import (
|
|
43
|
+
JUDGE_NAME_ENV,
|
|
44
|
+
parse_criteria_entries,
|
|
45
|
+
resolve_arg_files,
|
|
46
|
+
resolve_model,
|
|
47
|
+
)
|
|
48
|
+
from rewardkit.workflow.component.registry import InputSlot, component
|
|
49
|
+
from rewardkit.workflow.errors import Failure
|
|
50
|
+
|
|
51
|
+
DEFAULT_JUDGE_MODEL = "anthropic/claude-sonnet-5"
|
|
52
|
+
"""judge 模型缺省(与 JudgeConfig.judge 的缺省一致,作文档锚点)。"""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@component(
|
|
56
|
+
name="llm_judge",
|
|
57
|
+
version=1,
|
|
58
|
+
outputs=["verdict"],
|
|
59
|
+
inputs=[
|
|
60
|
+
InputSlot(
|
|
61
|
+
name="criteria",
|
|
62
|
+
accepted_types=("array",),
|
|
63
|
+
description="评分项表的数组,元素字段对齐存量 [[criterion]] 表",
|
|
64
|
+
),
|
|
65
|
+
InputSlot(name="model", required=False, accepted_types=("string",)),
|
|
66
|
+
InputSlot(name="files", required=False, accepted_types=("string", "array")),
|
|
67
|
+
InputSlot(name="mode", required=False, accepted_types=("string",)),
|
|
68
|
+
InputSlot(name="timeout", required=False, accepted_types=("int",)),
|
|
69
|
+
InputSlot(name="reasoning_effort", required=False, accepted_types=("string",)),
|
|
70
|
+
InputSlot(name="reference", required=False, accepted_types=("string",)),
|
|
71
|
+
InputSlot(name="atif_trajectory", required=False, accepted_types=("string",)),
|
|
72
|
+
InputSlot(name="system_prompt", required=False, accepted_types=("string",)),
|
|
73
|
+
],
|
|
74
|
+
)
|
|
75
|
+
async def llm_judge(
|
|
76
|
+
context,
|
|
77
|
+
criteria,
|
|
78
|
+
model=None,
|
|
79
|
+
files=None,
|
|
80
|
+
mode=None,
|
|
81
|
+
timeout=None,
|
|
82
|
+
reasoning_effort=None,
|
|
83
|
+
reference=None,
|
|
84
|
+
atif_trajectory=None,
|
|
85
|
+
system_prompt=None,
|
|
86
|
+
) -> Any:
|
|
87
|
+
"""``arun_llm`` 的薄封装:评分项与调用配置全来自 args(见模块 docstring)。"""
|
|
88
|
+
root = context.workspace.root
|
|
89
|
+
criteria_objs, weights, reason = parse_criteria_entries(criteria, root)
|
|
90
|
+
if reason:
|
|
91
|
+
return {"unjudged": True, "reason": reason}
|
|
92
|
+
|
|
93
|
+
judge_kwargs: dict[str, Any] = {}
|
|
94
|
+
for key, value in (
|
|
95
|
+
("mode", mode),
|
|
96
|
+
("timeout", timeout),
|
|
97
|
+
("reasoning_effort", reasoning_effort),
|
|
98
|
+
("reference", reference),
|
|
99
|
+
("atif_trajectory", atif_trajectory),
|
|
100
|
+
):
|
|
101
|
+
if value is not None:
|
|
102
|
+
judge_kwargs[key] = value
|
|
103
|
+
try:
|
|
104
|
+
judge = LLMJudge(
|
|
105
|
+
model=resolve_model(context, model, extra_envs=(JUDGE_NAME_ENV,), default=DEFAULT_JUDGE_MODEL),
|
|
106
|
+
files=resolve_arg_files(files, root),
|
|
107
|
+
**judge_kwargs,
|
|
108
|
+
)
|
|
109
|
+
except Exception as exc: # noqa: BLE001 - 槽值非法属配置问题,按 unjudged
|
|
110
|
+
return {"unjudged": True, "reason": f"llm_judge 槽值非法:{exc}"}
|
|
111
|
+
|
|
112
|
+
per_item_warns: list[list[str]] = []
|
|
113
|
+
for c in criteria_objs:
|
|
114
|
+
warns_for_item: list[str] = []
|
|
115
|
+
if judge.mode == "batched" and c.files:
|
|
116
|
+
warns_for_item.append(
|
|
117
|
+
f"mode=batched:条目 {c.id or c.name} 的 files 被忽略"
|
|
118
|
+
"(组级 files 生效;条目级 files 需 mode=individual)"
|
|
119
|
+
)
|
|
120
|
+
per_item_warns.append(warns_for_item)
|
|
121
|
+
|
|
122
|
+
completion = getattr(context.model, "acompletion", None)
|
|
123
|
+
try:
|
|
124
|
+
scores, output, warns = await arun_llm(
|
|
125
|
+
judge, criteria_objs, weights, system_prompt, completion=completion
|
|
126
|
+
)
|
|
127
|
+
except Exception as exc: # noqa: BLE001 - 判分调用失败 = 节点失败
|
|
128
|
+
return Failure(
|
|
129
|
+
root_cause_node_id=context.node_id,
|
|
130
|
+
message=f"llm_judge 调用失败:{exc}",
|
|
131
|
+
error_kind="llm-error",
|
|
132
|
+
chain=(context.node_id,),
|
|
133
|
+
)
|
|
134
|
+
all_scores = [
|
|
135
|
+
{
|
|
136
|
+
"id": c.id or score.name or f"criterion_{index}",
|
|
137
|
+
"score": score.value,
|
|
138
|
+
"reasoning": score.reasoning,
|
|
139
|
+
"warnings": list(warns) + per_item_warns[index],
|
|
140
|
+
"weight": weights[index],
|
|
141
|
+
"optional": c.optional,
|
|
142
|
+
}
|
|
143
|
+
for index, (c, score) in enumerate(zip(criteria_objs, scores))
|
|
144
|
+
]
|
|
145
|
+
return {"scores": all_scores, "output": output, "warnings": list(warns)}
|
|
@@ -56,7 +56,6 @@ from rewardkit.workflow.attribution import (
|
|
|
56
56
|
is_unjudged,
|
|
57
57
|
make_unjudged,
|
|
58
58
|
)
|
|
59
|
-
from rewardkit.workflow.component._source import clear_source_cache
|
|
60
59
|
from rewardkit.workflow.component.registry import (
|
|
61
60
|
ComponentSpec,
|
|
62
61
|
ensure_builtin_components,
|
|
@@ -503,9 +502,6 @@ def run(
|
|
|
503
502
|
并参与并发上限的优先级合并。
|
|
504
503
|
"""
|
|
505
504
|
ensure_builtin_components()
|
|
506
|
-
# 每次 run() 取数据源的新鲜快照:清空判分组件共享的 tests/*.toml
|
|
507
|
-
# 解析缓存,使进程内缓存不跨运行泄漏。
|
|
508
|
-
clear_source_cache()
|
|
509
505
|
rc = dict(run_context or {})
|
|
510
506
|
workflow_limit, tag_limits = _effective_concurrency(plan, rc)
|
|
511
507
|
if model is None:
|