en un clic
add-benchmark
集成外部 benchmark 数据集到 HolyEval 框架 — 从论文/仓库到可执行评测的端到端流程。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
集成外部 benchmark 数据集到 HolyEval 框架 — 从论文/仓库到可执行评测的端到端流程。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
| name | add-benchmark |
| description | 集成外部 benchmark 数据集到 HolyEval 框架 — 从论文/仓库到可执行评测的端到端流程。 |
| argument-hint | [benchmark paper URL or GitHub repo URL] |
将外部 benchmark 数据集(如论文、开源仓库)集成到 HolyEval 框架中,使其可以通过 python -m benchmark.basic_runner <benchmark> <dataset> 执行评测。
交互原则: 本 skill 采用「分析 → 确认 → 执行」模式。在每个关键决策点,必须通过 AskQuestion 工具向用户展示分析结论并获得确认,确认通过后才继续执行。绝不在未经用户确认的情况下开始写代码。
本 skill 仅通过插件扩展点和数据目录集成新 benchmark,严禁修改框架核心逻辑。文件按修改权限分为三级:
| 文件 | 操作 |
|---|---|
generator/<name>/__init__.py | 新建(空文件) |
generator/<name>/converter.py | 新建(数据转换器) |
benchmark/data/<name>/metadata.json | 新建(数据集元信息) |
benchmark/data/<name>/<dataset>.jsonl | 新建(由 converter 生成) |
evaluator/plugin/eval_agent/<name>_eval_agent.py | 仅 Case B: 新建(EvalAgent plugin) |
evaluator/plugin/eval_agent/__init__.py | 仅 Case B: 追加 import + __all__ + docstring。不得删除/修改已有内容 |
evaluator/core/schema.py 是 Pydantic Discriminated Union 的类型注册文件。由于 Pydantic v2 要求 Union 成员在定义时静态列举,新增配置类型必须在此文件中追加。
允许的操作(纯追加,不改已有代码):
EvalInfo Union 定义之前添加新的 *EvalInfo 配置类(及其依赖的辅助模型)EvalInfo = Annotated[..., Discriminator("evaluator")] 中追加新类型EvalInfo 列表禁止的操作:
Case A(复用现有评估器)完全不需要修改 schema.py。
以下文件为框架核心,任何修改都可能破坏全局功能:
evaluator/core/orchestrator.py — 编排引擎(do_single_test / BatchSession)evaluator/core/bench_schema.py — Benchmark 数据模型(BenchItem / merge_target / bench_item_to_test_case)evaluator/core/interfaces/abstract_*.py — 三类 Agent 抽象基类evaluator/utils/*.py — 通用工具层(llm, benchmark_reader, report_reader, agent_inspector, config)evaluator/plugin/test_agent/ — 已有 TestAgent 插件(manual / auto)evaluator/plugin/target_agent/ — 已有 TargetAgent 插件(llm_api / theta_api)evaluator/plugin/eval_agent/ 中的已有文件 — 不得修改 semantic / healthbench / keyword / preset_answer / indicatorbenchmark/basic_runner.py — 跑分执行器web/ — Web UI如果你发现需要修改 🔴 文件才能完成需求,请停下来通知用户 — 这通常意味着需求理解有误,或框架需要由维护者升级扩展点。绝不"顺手"改一下核心代码来适配新 benchmark。
外部数据集 → Converter → BenchItem JSONL → basic_runner → Orchestrator → TestAgent ↔ TargetAgent → EvalAgent → BenchReport
↑ ↑ ↑ ↑
[需实现] [复用即可] [复用即可] [可能需实现]
| 角色 | 职责 | Benchmark 集成时是否需要新增? |
|---|---|---|
| TestAgent(虚拟用户) | 模拟真实用户发送消息 | 几乎不需要 — 现有 manual/auto 覆盖所有场景 |
| TargetAgent(被测系统) | 封装被测系统的调用 | 原则上不需要 — 现有 llm_api/theta_api 已足够 |
| EvalAgent(评估器) | 评判对话质量 | 可能需要 — 取决于评估方法论是否已有对应实现 |
| 名称 | 类 | 工作方式 | 典型场景 |
|---|---|---|---|
manual | ManualTestAgent | 按序发送 strict_inputs 预设输入,用完自动结束。零 LLM 调用、完全确定性、零成本。轮次 = len(strict_inputs) + 1,忽略 max_turns | 绝大多数 benchmark 都用此类型:标准问答、rubric 评测、答案匹配等 |
auto | AutoTestAgent | 前 N 轮消费 strict_inputs,之后 LLM 自主生成对话。根据 goal/context/finish_condition 判断何时结束 | 需要 AI 模拟多轮追问的开放式对话场景(极少数 benchmark 需要) |
选择原则: 如果 benchmark 数据中包含完整的用户输入文本,一律使用
manual。仅当 benchmark 要求虚拟用户自主生成多轮对话时才考虑auto。
| 名称 | 类 | 工作方式 | 配置字段 |
|---|---|---|---|
llm_api | LlmApiTargetAgent | 通过 do_execute() 统一调用大模型(OpenAI/Gemini/Anthropic/GLM),自动维护多轮对话历史 | model(必填), system_prompt(可选) |
theta_api | ThetaApiTargetAgent | 通过 HTTP API 调用 Theta Health 后端,使用 create_message + list_message 轮询模式 | email(必填), code, agent, language, timezone |
⚠️ 关于自定义 TargetAgent: 对于外部 benchmark 集成,原则上不需要自定义 TargetAgent。
- 如果 benchmark 是评测大模型能力 → 使用
llm_api(运行时通过--target-model指定模型)- 如果 benchmark 是评测 Theta Health 产品 → 使用
theta_api- 如果你判断需要自定义 TargetAgent,这几乎一定意味着理解有误。请务必在 Checkpoint 1 中向用户确认,说明为什么现有 target 不够用,并获得明确同意后才继续。
| 名称 | 适用场景 | LLM | 评估方式 |
|---|---|---|---|
semantic | 通用多维度语义评估 | 是 | LLM 按 criteria 独立打分 → 加权总分 → 对比 threshold → pass/fail |
healthbench | HealthBench rubric 评测 | 是 | LLM 逐条判定 criterion → 按 points 加权计算 → scored(不做 pass/fail) |
keyword | 关键词/规则匹配 | 否 | 按 rules 配置检查对话文本 → 加权计分 → 对比 threshold → pass/fail |
preset_answer | 标准答案比对 | 否 | 数字容差/关键词/精确匹配 → pass/fail |
indicator | 健康指标数据比对 | 是 | 调用 Theta API 获取真实数据 → LLM 比对 → pass/fail |
外部 benchmark 的评估方法论是否已有对应的 EvalAgent?
│
├─ YES → 仅需 Converter + 数据目录 (Case A: 轻量集成)
│ 例:答案匹配类 → 复用 preset_answer
│ 例:关键词检查类 → 复用 keyword
│ 例:多维度语义评估 → 复用 semantic
│
└─ NO → Converter + EvalInfo Config + EvalAgent Plugin + 数据目录 (Case B: 完整集成)
例:HealthBench rubric 评估 → 自定义 healthbench eval
例:MMLU 多选题评估 → 自定义 mcq eval
以下模块完全通用,新增 benchmark 时绝不修改:
benchmark/basic_runner.py — 执行器(基于 BenchItem 架构,自动适配)evaluator/core/orchestrator.py — 编排器(do_single_test / BatchSession)evaluator/core/bench_schema.py — 通用数据模型(BenchItem / BenchMark / BenchReport)evaluator/utils/benchmark_reader.py — 自动发现 benchmark/data/ 目录evaluator/utils/report_reader.py — 自动发现 benchmark/report/ 目录agent_inspector 自动适配新 plugin这是最关键的一步。在写任何代码前,必须彻底理解外部 benchmark。
用户会提供论文 URL 或 GitHub 仓库 URL:
WebFetch 阅读论文内容,重点关注评估方法论章节(Evaluation / Metrics / Scoring)WebFetch 阅读 README、数据格式说明、评估脚本源码(重点:scoring / grading 函数)系统性分析以下三个维度:
数据格式:
user.strict_inputs(用户输入)?history(前置轮次)+ strict_inputs(最后一条用户输入)tags?评估方法论:
对话模式:
history(评测前对话上下文),最后一条 user message 作为 strict_inputsmanual,需生成 → auto)在进入 Phase 1 之前,必须通过 AskQuestion 向用户确认以下所有决策。
先向用户展示一段分析总结文本(Markdown),包含:
然后使用 AskQuestion 工具发起确认:
Question 1: Benchmark 名称
- prompt: "确认 benchmark 目录名(snake_case,用于 benchmark/data/<name>/ 和 generator/<name>/)"
- options: [推荐名称, 备选名称, "自定义(请在下方说明)"]
Question 2: 虚拟用户类型 (TestAgent)
- prompt: "虚拟用户类型 — 基于数据分析的推荐如下"
- options:
- "manual(脚本驱动)— 使用原始数据中的确定性输入,零 LLM 成本【推荐】"
- "auto(LLM 驱动)— 需要 AI 自主生成多轮对话"
Question 3: 被测系统类型 (TargetAgent)
- prompt: "被测系统类型 — 以下选项使用已有 TargetAgent,运行时通过 CLI 参数指定模型"
- options:
- "llm_api — 通用大模型 API(OpenAI/Gemini/Anthropic 等)【推荐】"
- "theta_api — Theta Health 产品 API"
- "⚠️ 需要自定义 TargetAgent(请说明原因)"
Question 4: 评估器类型 (EvalAgent)
- prompt: "评估器类型 — 基于评估方法论分析的推荐如下"
- options:
- 列出可能匹配的已有 eval + "[推荐原因]"
- "需要自定义评估器(Case B)"
Question 5: 数据子集方案
- prompt: "数据子集划分"
- options: [列出原始数据中的子集方案]
- allow_multiple: true
关键规则:
- 如果用户在 Question 3 选择了「需要自定义 TargetAgent」,必须追问具体原因,并尝试用现有方案替代。只有用户二次确认确实无法复用时才执行。
- 如果用户选择了意料之外的选项,主动解释可能的影响。
创建: generator/<benchmark_name>/converter.py + generator/<benchmark_name>/__init__.py
参考实现: generator/healthbench/converter.py
generator/
├── <benchmark_name>/
│ ├── __init__.py # 空文件
│ └── converter.py # 转换器
└── ...
"""
<BenchmarkName> → HolyEval 数据转换器
将 <原始格式> 转换为 HolyEval BenchItem JSONL。
转换映射:
<原始字段A> → strict_inputs(用户输入)
<原始字段B> → history(可选,多轮对话上下文)
<原始字段C> → eval.<评估配置>
<原始字段D> → tags
用法:
python -m generator.<benchmark_name>.converter input_file output.jsonl
"""
import argparse
import json
import logging
from pathlib import Path
from typing import Any, Dict, List, Optional
logger = logging.getLogger(__name__)
def _convert_single(entry: Dict[str, Any], index: int) -> Optional[Dict[str, Any]]:
"""将单条原始数据转换为 HolyEval BenchItem dict
Returns:
BenchItem dict,转换失败返回 None
"""
bench_item: Dict[str, Any] = {
"id": "<prefix>_<unique_id>",
"title": "<生成标题>",
"description": "<描述>",
"user": {
"type": "manual", # Checkpoint 1 确认的类型
"goal": "<评测目标>",
"strict_inputs": [...], # 用户输入列表
},
"eval": {
"evaluator": "<eval_type>", # Checkpoint 1 确认的评估器
# ... 评估器特定配置
},
"tags": [...],
}
# 如果原始数据含多轮对话上下文,添加 history
# history: [{role: "user", content: "..."}, {role: "assistant", content: "..."}]
if history:
bench_item["history"] = history
return bench_item
def convert(
input_path: str | Path,
output_path: str | Path,
limit: int | None = None,
) -> int:
"""批量转换,返回成功条数"""
input_path = Path(input_path)
output_path = Path(output_path)
if not input_path.exists():
raise FileNotFoundError(f"输入文件不存在: {input_path}")
output_path.parent.mkdir(parents=True, exist_ok=True)
converted = 0
skipped = 0
with open(input_path, "r", encoding="utf-8") as fin, \
open(output_path, "w", encoding="utf-8") as fout:
for i, line in enumerate(fin):
line = line.strip()
if not line:
continue
if limit is not None and converted >= limit:
break
try:
entry = json.loads(line)
except json.JSONDecodeError as e:
logger.warning("第 %d 行 JSON 解析失败: %s", i + 1, e)
skipped += 1
continue
bench_item = _convert_single(entry, i)
if bench_item is None:
skipped += 1
continue
fout.write(json.dumps(bench_item, ensure_ascii=False) + "\n")
converted += 1
logger.info("转换完成: %d 条成功, %d 条跳过, 输出: %s", converted, skipped, output_path)
return converted
def main() -> None:
"""CLI 入口"""
parser = argparse.ArgumentParser(
description="将 <BenchmarkName> 转换为 HolyEval BenchItem JSONL",
)
parser.add_argument("input", help="源文件路径")
parser.add_argument("output", help="输出 BenchItem JSONL 路径")
parser.add_argument("--limit", type=int, default=None, help="最大转换条数")
parser.add_argument("-v", "--verbose", action="store_true", help="详细日志")
args = parser.parse_args()
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.INFO,
format="%(levelname)s %(message)s",
)
count = convert(args.input, args.output, limit=args.limit)
print(f"转换完成: {count} 条 BenchItem → {args.output}")
if __name__ == "__main__":
main()
user 配置:
| 场景 | user.type | strict_inputs | max_turns |
|---|---|---|---|
| 单轮问答(最常见) | manual | ["用户提问"] | 不填(自动计算) |
| 多轮预注入 + 提问 | manual | ["背景数据...", "补充信息...", "正式提问"] | 不填 |
| 需要 LLM 自主生成 | auto | [] 或前几轮 | 必填 |
strict_inputs是一个列表(List[str]),manual模式下逐条按序发送,每条都会触发被测系统回复,对话轮次 =len(strict_inputs) + 1。当列表包含多条输入时,前面的条目用于向被测系统预注入上下文信息(如病历、检查指标、用药记录等),中间的回复不影响评估,评估器只关注完整对话的最终质量。这种方式适用于:
- 需要先提供背景数据、再提问的场景(如先发患者病历,再问诊断建议)
- 需要模拟多步交互的流程(如先报告症状,再补充检查结果,最后问治疗方案)
- 不关心中间回复内容、只评估最终对话效果的评测设计
historyvsstrict_inputs:两者都支持多轮对话,但机制不同:
historystrict_inputs(多条)注入方式 作为预加载上下文,双方 Agent 直接"看到",不经过对话循环 逐条发送,被测系统逐条回复,走完整对话循环 被测系统行为 被测系统感知历史对话存在,像"接续"之前的对话 被测系统逐条处理每条输入并生成回复 适用场景 原始数据本身包含多轮已有对话(如 HealthBench 的多轮 prompt) 需要主动向被测系统"灌入"信息再提问 格式 [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]["第一条输入", "第二条输入", ...]两者可以组合使用:
history提供已有对话背景 +strict_inputs在此基础上继续多步交互。Web UI 中
history消息会以半透明样式展示并标注"以上为历史对话",与评测对话视觉区分。
eval 配置(根据 Checkpoint 1 的选择):
| 评估器 | eval 配置示例 |
|---|---|
preset_answer | {"evaluator": "preset_answer", "standard_answer": "42", "match_mode": "number"} |
keyword | {"evaluator": "keyword", "rules": [...], "pass_threshold": 0.7} |
semantic | {"evaluator": "semantic", "criteria": [...], "threshold": 0.7} |
healthbench | {"evaluator": "healthbench", "rubrics": [{"criterion": "...", "points": 10, "tags": [...]}]} |
| 自定义 | {"evaluator": "<new_name>", ...}(需完成 Phase 2) |
id 格式: <2-3字母前缀>_<原始ID或序号>(如 hb_<prompt_id>,mmlu_<subject>_<index>),必须全局唯一。
如果 Checkpoint 1 确认需要自定义评估器,按以下步骤执行。
推荐: 直接调用
add-eval-agentskill 完成此步骤,它会自动处理 schema 修改、plugin 实现和注册。 以下为手动步骤说明,供理解整体流程。
修改: evaluator/core/schema.py
在 EvalInfo Discriminated Union 定义之前添加新的 Pydantic 配置类:
class <Name>EvalInfo(BaseModel):
"""<中文描述> — <评估方法简述>"""
model_config = ConfigDict(extra="forbid", json_schema_extra={"examples": [{...}]})
evaluator: Literal["<name>"] = Field(description="评估器类型")
model: Optional[str] = Field(None, description="LLM 模型")
# ... benchmark 特有的评估配置字段
然后将新类型加入 EvalInfo Union,同时更新 schema.py 文件顶部的 docstring。
创建: evaluator/plugin/eval_agent/<name>_eval_agent.py
核心要点:
AbstractEvalAgent,使用 name="<name>" 注册async def run(self, memory_list, session_info=None) -> EvalResultmemory_list(含 .test_reaction + .target_response),历史上下文通过 self.history 访问evaluator/utils/llm.py 的 do_execute()_cost_meta 和 _display_meta参考实现:
evaluator/plugin/eval_agent/healthbench_eval_agent.py(_build_conversation + 并发 grade + _calculate_score)evaluator/plugin/eval_agent/semantic_eval_agent.pyevaluator/plugin/eval_agent/preset_answer_eval_agent.py修改: evaluator/plugin/eval_agent/__init__.py — 添加 import + __all__ + docstring。
创建: benchmark/data/<benchmark_name>/metadata.json
{
"description": "# <Benchmark 名称>\n\n<Markdown 描述>\n\n## 子集\n\n| 子集 | 数量 | 说明 |\n|------|------|------|\n| ... | ... | ... |\n\n**评估器**: `<evaluator_name>`",
"target": [
{
"type": "llm_api",
"fields": {
"model": {"default": "gpt-4.1", "editable": true, "required": true}
}
}
]
}
字段说明:
description: Markdown 格式,Web UI 渲染展示target: TargetSpec 数组,每个元素定义一种被测系统类型(参考 benchmark/data/healthbench/metadata.json)
type: agent 类型(llm_api / theta_api)fields: 各字段的默认值、是否可编辑(editable)、是否必填(required)--target-type 指定params(可选): 共享参数字典,供 JSONL 条目通过 $ref 引用(见下方说明)当多条用例共享相同的大块数据(如 history 对话上下文)时,在 metadata.json 中定义 params,JSONL 条目通过 {"$ref": "key"} 引用,避免重复:
// metadata.json
{
"target": [...],
"params": {
"diabetic_user_history": [
{"role": "user", "content": "I have type 2 diabetes..."},
{"role": "assistant", "content": "Thank you for sharing..."}
]
}
}
// sample.jsonl — 多条用例引用同一 history
{"id": "case_1", "history": {"$ref": "diabetic_user_history"}, "user": {...}, "eval": {...}}
{"id": "case_2", "history": {"$ref": "diabetic_user_history"}, "user": {...}, "eval": {...}}
规则:
$ref 不处理){"$ref": "key"} 且仅含此一个键才触发替换history参考实现: benchmark/data/history_demo/
uv run python -m generator.<benchmark_name>.converter <input_file> benchmark/data/<benchmark_name>/<dataset>.jsonl
转换完成后,向用户展示:
然后使用 AskQuestion 确认:
Question 1: 转换结果
- prompt: "已转换 N 条数据,上方展示了首条和末条样例。请确认数据映射是否正确"
- options:
- "确认正确,继续验证"
- "有问题,需要调整(请说明)"
uv run python -c "
from evaluator.utils.benchmark_reader import load_bench_items
items = load_bench_items('benchmark/data/<benchmark_name>/<dataset>.jsonl')
print(f'成功加载 {len(items)} 条 BenchItem')
print(f'首条 ID: {items[0].id}')
print(f'评估器: {items[0].eval.evaluator}')
"
uv run python -c "
import evaluator.plugin.eval_agent
from evaluator.core.interfaces.abstract_eval_agent import AbstractEvalAgent
print('已注册 EvalAgent:', list(AbstractEvalAgent.get_all().keys()))
"
uv run python -c "
from evaluator.utils.benchmark_reader import list_benchmarks
for b in list_benchmarks():
print(f'{b.name}: {[d.name for d in b.datasets]}')
"
ruff check generator/<benchmark_name>/ evaluator/core/schema.py evaluator/plugin/eval_agent/
ruff format generator/<benchmark_name>/ evaluator/core/schema.py evaluator/plugin/eval_agent/
所有验证通过后,使用 AskQuestion 确认是否跑端到端测试:
Question 1: 端到端测试
- prompt: "数据加载和 plugin 注册均通过。是否执行小规模端到端测试?(会调用 LLM API,产生少量费用)"
- options:
- "是,跑 3 条端到端测试"
- "是,跑 1 条端到端测试"
- "跳过,我稍后手动测试"
用户确认后,启动 Web 服务并通过浏览器执行(见下方「Web 驱动执行」说明),或用 CLI 快速跑:
uv run python -m benchmark.basic_runner <benchmark_name> <dataset> \
--target-type llm_api --target-model gpt-4.1 \
--limit <N> -v
目的: 用 sample 子集实际跑分,与原始论文/实验公开的基准数据对比,验证迁移后的评测管线是否产出合理且可比的结果。如果分数偏差过大,说明 converter 映射或 EvalAgent 实现有问题。
在 Phase 0 阅读论文/仓库时,就应记录以下信息(如有):
avg_score / pass_rate 如何对应如果论文没有公开基准数据,在 Checkpoint 1 中向用户确认是否有内部参考数据,或标注"无可比基准,仅做冒烟验证"。
重要: CLI 和 Web 是独立的执行通道 — CLI 跑的任务在 Web 上看不到进度。 要获得实时进度可视化,必须通过 Web 执行跑分。
Step 1: 启动 Web 服务
检查 Web 服务是否已在运行。如果未运行,后台启动:
# 后台启动 Web 服务(block_until_ms: 0)
uv run python -m web
等待服务就绪(检查 http://localhost:8000 可访问)。
Step 2: 浏览器打开任务页面
使用 open 命令打开浏览器:
open http://localhost:8000/tasks
Step 3: 通过 Web API 创建跑分任务
通过 POST /api/tasks 创建任务(等效于在 Web UI 上点击「开始评测」):
curl -X POST http://localhost:8000/api/tasks \
-H "Content-Type: application/json" \
-d '{
"benchmark": "<benchmark_name>",
"dataset": "sample",
"target_type": "llm_api",
"target_model": "<与论文对齐的模型>",
"max_concurrency": 5
}'
API 返回 task_id,用户可在浏览器 http://localhost:8000/tasks/{task_id} 实时查看进度。
Step 4: 等待任务完成
轮询任务状态直到完成:
curl http://localhost:8000/api/tasks/<task_id>
响应中的 snapshot.completed == snapshot.total 时表示完成。
--target-model应尽量与论文中的被测模型一致,以便直接对比分数。
跑分完成后,整理以下对比表格向用户展示:
## 迁移验证报告: <Benchmark 名称>
### 测试条件
| 项目 | 原版 (论文) | HolyEval 迁移版 |
|------|-----------|----------------|
| 数据子集 | <子集名> (<N>条) | sample (<M>条) |
| 被测模型 | <model> | <model> |
| Grader 模型 | <model> | <model> |
| 评估器 | <原版实现> | <evaluator name> |
### 分数对比
| 指标 | 原版基准 | HolyEval 结果 | 偏差 | 判定 |
|------|---------|-------------|------|------|
| avg_score | <X> | <Y> | <±Z%> | ✅/⚠️/❌ |
| pass_rate (如有) | <X> | <Y> | <±Z%> | ✅/⚠️/❌ |
偏差判定标准:
- ✅ 偏差 ≤5%: 正常范围(LLM 非确定性 + 采样差异)
- ⚠️ 偏差 5-15%: 需关注,可能因采样数不足或 prompt 微调
- ❌ 偏差 >15%: 需排查,converter 映射或 eval 逻辑可能有误
### 按标签维度对比 (如有)
| 标签 | 原版 | HolyEval | 偏差 |
|------|------|---------|------|
| <tag1> | ... | ... | ... |
### 分析 & 结论
<对偏差的解释,已知差异因素,是否通过验证>
展示上述对比报告后,使用 AskQuestion 确认:
Question 1: 对比结果
- prompt: "上方为 sample 跑分与论文基准的对比报告。请确认迁移结果是否可接受"
- options:
- "结果可接受,迁移完成"
- "偏差较大,需要排查(请说明关注点)"
- "无原版基准数据,冒烟通过即可"
如果用户选择"偏差较大,需要排查",按以下方向排查:
排查修复后重新执行 5.2-5.4,直到用户确认通过。
集成完成后,更新以下文档,确保新 benchmark 在所有入口可见:
| 文件 | 更新内容 |
|---|---|
README.md | 「Benchmark 数据集」表格追加新行 + CLI 示例追加新命令 |
CLAUDE.md | Commands 区 CLI 示例追加 + Benchmark Data 目录树追加 + Data Conversion 追加转换器说明 |
web/guides/run-benchmark.md | 「可用数据集」表格追加新行 + CLI 示例追加 |
web/guides/generate-benchmark.md | 「已内置的转换器」表格追加新行 |
web/guides/overview.md | generator 目录树追加 + 评估能力表追加(仅 Case B 新增 EvalAgent 时) |
Case B 额外更新(新增了 EvalAgent):
文件 更新内容 web/guides/develop-eval-agent.md「现有评估器」表格追加 + 「关键文件」表格追加参考实现 CLAUDE.mdEvalAgent 实现表 + Key Modules 追加说明 README.md「已注册插件」表格 EvalAgent 区域追加新行
| 组件 | 文件 | 作用 |
|---|---|---|
| Converter | generator/healthbench/converter.py | HealthBench JSONL → BenchItem JSONL |
| EvalInfo | evaluator/core/schema.py → HealthBenchEvalInfo | rubrics 配置结构 |
| EvalAgent | evaluator/plugin/eval_agent/healthbench_eval_agent.py | 原版 GRADER_TEMPLATE + scoring |
| 注册 | evaluator/plugin/eval_agent/__init__.py | import 触发注册 |
| 数据 | benchmark/data/healthbench/metadata.json | 元信息(target_configurable: true) |
| 数据 | benchmark/data/healthbench/sample.jsonl 等 | 转换后的 BenchItem 数据 |
数据映射:
HealthBench 原始 → HolyEval BenchItem
─────────────────────────────────────────────────
prompt (多轮对话) → 拆分为 history + strict_inputs
prompt[:-1] (历史轮次) → history [{role, content}](41.7% 用例有多轮)
prompt[-1].content (user msg) → user.strict_inputs[0]
rubrics[].criterion → eval.rubrics[].criterion
rubrics[].points → eval.rubrics[].points
example_tags → tags
prompt_id → id (加 "hb_" 前缀)
user.type = "manual"(预设输入,零 LLM)
target = 不在 BenchItem 中(运行时决定)
评估逻辑:
achieved = Σ(points for rubric where criteria_met=True)
total_possible = Σ(points for rubric where points > 0)
score = clip(achieved / total_possible, 0, 1)
result = "scored"(不做 pass/fail 判定)
BenchItem(数据集用例 — 没有 target):
class BenchItem(BaseModel):
id: str # 唯一标识
title: str # 一句话标题
description: Optional[str] # 补充说明
user: BenchUserInfo # 虚拟用户配置(含 target_overrides)
eval: EvalInfo # 评估配置(Discriminated Union)
history: List[Dict[str, str]] # 可选,评测前历史对话 [{role, content}]
tags: List[str] # 分类标签
运行时转换链:
BenchItem + CLI runtime_target
↓ bench_item_to_test_case()
TestCase(包含 user, target, eval, history, tags)
↓ do_single_test()
TestResult(包含 score, result, feedback, trace, cost)
↓ build_bench_report()
BenchReport
完成集成后,确认以下所有项目:
generator/<name>/__init__.py 存在generator/<name>/converter.py 可正确转换数据benchmark/data/<name>/metadata.json 格式正确benchmark/data/<name>/<dataset>.jsonl 可被 load_bench_items() 加载evaluator/core/schema.py 中新增 EvalInfo 配置类并加入 Unionevaluator/plugin/eval_agent/<name>_eval_agent.py 实现完整evaluator/plugin/eval_agent/__init__.py 注册新 EvalAgentbenchmark_reader.list_benchmarks() 可发现新数据集ruff check 和 ruff format 通过Use when analyzing ESL-Bench evaluation reports - extracting scores by difficulty dimension, comparing methods, checking fail rates, token costs, duration per query. Triggers on keywords like eslbench report, benchmark results, group by difficulty.
Scaffold a new EvalAgent plugin (config + implementation + registration).
Scaffold a new TargetAgent plugin (config + implementation + registration).
引导项目初始化 — 环境安装、配置、验证、启动 Web UI(含 hma-web 公开评测平台)。
审查项目架构健康度 — 检查 GitOps 合规、Plugin 可插拔性、CLI/Web 复用。当用户要求架构审查、代码重构后验证、或新增模块后检查依赖关系时使用。
Run all benchmark test cases or a filtered subset.