评测核心

evaluation 包内 requests、runners、metrics、catalog 与 reporting 如何衔接。

本页内容

简介

本文从内部看 evaluation 包:哪些类型要保持稳定、一次运行由哪个函数接手、reviewer 可以信哪些文件。如果只想从 CLI 追到磁盘,先读 工作流。

包内数据流是单向的:公开契约定义 JSON-safe 形状,执行 runner 产生副作用与 artifact,catalog loader 把 YAML 转为契约,reporting 把 metrics 变成 scorecard。API 模块应保持 import-light;重型 runtime 不应反向泄漏进 evaluation/api/。

模块级查找见 代码库地图。

端到端流程

Evaluate 与仅模型运行进入 evaluate.py 的 run_evaluate()。Model mode 先生成并对齐结果,两种模式随后都由 ExistingResultsRunner 评分并写出产物。Model-plus-benchmark 经 execute_prepared_evaluation() 进入 run_model_benchmark(),官方 suite 评分由 ManifestBenchmarkRunner 执行。

调用图
从 request 到 scorecard
入口
入口运行请求
门面execute_prepared_evaluation()orchestration/service.py:775
委派
委派ContractRunnerorchestration/contract.py:96
委派ExistingResultsRunnerorchestration/existing_results.py:93
委派run_model_benchmark()orchestration/model_benchmark.py:825

副作用只由一个 delegate 负责

compute_sample() / aggregate()
报告
指标compute_sample / aggregate
build_scorecard()
报告scorecard.json + report.md
execute_prepared_evaluation() 负责分发。Evaluate 走 run_evaluate();model-plus-benchmark 直接调用 run_model_benchmark()。

面向用户的 CLI、TUI 与 Workspace 通过 execution/orchestration/service.py 编译成上述 request 类型。五种 intent dataclass、三个规划边界(PreparedEvaluation、RunPlan、EvaluateRunRequest / ModelBenchmarkRunRequest)以及编译入口见 使用界面与编排。前端不能重复实现 generation、artifact materialization、benchmark dispatch 或 metric execution;新增 UX 应增加 intent→request 映射,而非新增 runner。不要再包第四种 recipe executor。

Prepared evaluation 分别记录 generation、data、evaluation、runtime 与 reference fidelity,再由这些字段推导 claim:完全锁定的官方运行才可能是 exact_reproduction;官方 data 与 evaluation 未修改时可为 benchmark_comparable;custom-data 或 metric-only 运行只能是 diagnostic。对于 model × benchmark 计划,仓内 benchmark evidence 还会继续限制 claim 上限:只验证过 bounded component 的 runner 仍然允许执行,但在 catalog 建立完整 official-suite evidence 前,计划必须降级为 diagnostic。调用方布尔参数只能收紧策略,不能把 diagnostic run 提升为榜单候选。score_valid 表示 evaluator 是否产出可用分数;leaderboard_valid 还必须满足可比 provenance 与 benchmark runner evidence。

公开契约

evaluation/api/ 模块定义 runner、CLI、tests、docs 导出与 validation 共用的形状。此处改动应视为 semver 敏感:下游假设 to_dict() / from_dict() 可往返且磁盘 field 名稳定。

样本级,GenerationRequest 携带 ids、task name、inputs、controls 与 expected output schema;对应的 GenerationResult 携带 artifacts、status、errors、timings 与 metadata。模型级,WorldModelRunner 是每个 backend 必须实现的最小接口:from_config()、generate()、cleanup()。Benchmark 级,BenchmarkSpec 聚合 tasks、metrics、splits、tags 与 dataset metadata。Metrics 通过 Metric 接口实现 compute_sample() 与 aggregate()。

这些类型刻意不包含 checkpoint 路径、subprocess 细节或 vendor-specific import。Runner 在 run time 把 catalog YAML 翻译成这些契约。

对运行 request 传入关键字覆盖时,只替换字段,不复制已加载的 runner、指标或嵌套配置对象。原 request 保持不变,执行与清理仍使用调用方传入的实例。

执行路径

三条执行路径覆盖常见形态。匹配任务选路径——不要在分发处堆条件分支,新增一条路径即可。

ContractRunner(contract.py)负责请求归一化、生成和可选的生成缓存复用;评分与报告输出统一委托给 ExistingResultsRunner。自定义指标在线、离线均使用相同的计算和聚合逻辑。

ExistingResultsRunner(existing_results.py)对齐已有结果与请求,统一写出样本记录、scorecard 和报告。scoring.py 分批执行指标,并调用各指标的 aggregate(),保留指标方向、原始与归一化统计、置信区间和跳过信息。Evaluate 入口支持混合传入 benchmark 指标 ID、内置离线指标 ID 和指标对象。请求的数值字段缺失时,留下无效指标记录和跳过原因。

aggregate_mean(...) 接受 Python 和 NumPy 实数标量,均值与有效数量使用相同的数值类型判断。直接计算与从 checkpoint 恢复的分数因此得到一致的聚合结果。

在线和离线路径共用结果转换,保留顶层评分字段及简写 artifact 路径。原始字段合并进 metadata.extra,评分映射内部的字段也会保留,同名冲突时已有 metadata 优先。每个输出指标 ID 只归属一个执行器:已知的重复声明在生成前拒绝,运行时动态输出重复 ID 则终止评分。Embodied 指标组合沿用注册表方向,成功率、奖励等自有指标显式声明方向;未知字段指标不推测方向。

numeric 通配选择在分批评分前,展开为已对齐成功结果中的字段并集。各字段随后使用与显式 numeric:<field> 相同的定义和缺失值处理。展开仅作用于本次运行,调用方可将原指标对象复用于其他数据集。

run_model_benchmark()(model_benchmark.py:825)把 generation 与 benchmark-zoo runner 串联。没有名为 ModelBenchmarkRunner 的类。它解析 benchmark manifest、从 task registry 物化 requests、运行模型、为外部 evaluator 物化 artifact(benchmark_runner.py:870 的 ManifestBenchmarkRunner),再把归一化 metrics 交给 reporting。用于端到端 model-plus-benchmark。

Model mode 与直接调用 ContractRunner 均将生成结果交给同一个评分器。Python request 提供 metric_batch_size(默认 32)和 resume。每个指标批次完成后写入 metrics/checkpoint.jsonl;恢复时比较请求、结果、指标实现、版本及声明的 parameters / config。新增或修改指标独立补算,不要求重新生成。未声明版本的旧 callable 仍可执行,恢复时重新评分。生成复用包含 runner 的参数与配置,并检查本地输出是否存在;需要重新生成的样本同时清除旧评分 checkpoint。

Checkpoint 记录执行器完整的指标选择;报告单独保存每个输出指标的定义。新增无关指标不影响已有指标的可比性,聚合指标的组成变化则会改变其定义。比较时拒绝所选指标的定义不同。选优要求分数有效、记录的指标覆盖完整且方向明确;部分分数仍保留展示。

执行器只返回部分已声明指标时,缺失项会补成覆盖率为零的无效记录,原因为 metric_not_returned,保留在样本分母中并计入 skipped。不完整的指标组合不写入 checkpoint;旧 checkpoint 若缺少已声明输出,恢复时会重新计算。

Embodied 闭环评测在生成前保存全部计划请求,每条 rollout 完成后立即写入并刷新 results.jsonl。取消任务时将生成阶段记为 interrupted,保留已完成结果。分片合并要求所有声明分片都有结果文件,且每个计划请求都有结果;允许已完成的空分片。所有评分入口中,生成失败为 generation_success 贡献 0,质量指标则跳过该样本。

可复现 Planning

Generation 开始前,task-driven run 通过 plan.py 中的 RunPlan 固定 sample ID、split 与 input keys。Plan 连接 task registry、可选 dataset manifest 与 evaluate facade:registry lookup → 物化 requests → EvaluateRunRequest。Plan 上的 fingerprint 使 rerun 与 cache 复用跨机器可预期。

materialize.py 中的 materialization 把 dataset 行或 task sample 转为 GenerationRequest 行。耗 GPU 前用 worldfoundry-eval task materialize 证明此步——多数“本地可用、CI 失败”来自 sample ID 不一致,而非 model loading。

模型解析

磁盘 YAML 经唯一 front door resolver.py 中的 resolve_model_zoo_runner() 变为可运行 model(:386)。CLI 的 --model-id、Python caller 与 Studio 预览都应在解释 checkpoint 路径前汇聚于此。

# worldfoundry/data/models/catalog/*.yaml
entry = parse_model_zoo_yaml(path)          # schema.py → ModelZooEntry
entry = ModelZooRegistry().resolve(alias)   # alias lookup
manifest = WorldModelManifest.from_entry(entry)
runner = resolve_model_zoo_runner(manifest) # resolver.py
# → WorldModelRunner instance

Built-in runner 经 builtins.py 与 registry.py 注册;custom target 从 catalog runner_target 字符串解析。manifest.py 与 schema.py 中的 catalog metadata 是 provenance 与 readiness——不能替代可运行 runner。

Registry 创建 runner 时不安装推理设置或包装方法。配置式 runner 在恢复与缓存检查确认有待生成样本后,才进入生成执行上下文加载。

WorldFoundryPipelineRunner 保留构造配置,并通过 parameters 提供当前 pipeline target、runtime profile 和生成默认参数。直接传入 runner 对象时,恢复和共享生成缓存均使用这些设置判断是否复用。

Benchmark 集成

Benchmark metadata 走平行的 catalog 路径。Task YAML 描述 per-sample protocol;benchmark-zoo YAML 描述 integration status、external runner 与 metric ID。

# Benchmark-zoo YAML + task YAML registry
entry = parse_benchmark_zoo_yaml(path)      # → BenchmarkZooEntry
entry = BenchmarkZooRegistry().resolve(id)
spec = BenchmarkSpec.from_catalog(entry, task_registry)
raw = ManifestBenchmarkRunner(spec).run()   # external evaluator
metrics = official_normalizers.normalize(raw)
# → metrics/summary.json + scorecard.json

External benchmark 留在 runner 边界之后:vendor evaluator 产出 raw output,normalizer 转为稳定 metrics,共享 reporting 层写 metrics/summary.json 与 scorecard.json。

指标包的声明不依赖可选计算库。公开 registry 列表包含全部内置指标包的声明;计算导出通过共享的 lazy_export 在调用时加载实现。缺少计算依赖不会隐藏指标 ID、别名或方向。

Reporting 链路

Reporting 在 metrics 完成后运行。Scorecard 是机器可读的 eligibility 记录;Markdown report 由 scorecard 派生,非权威来源。

per_sample = read_jsonl("metrics/per_sample.jsonl")
summary = aggregate_metrics(per_sample)     # → metrics/summary.json
scorecard = build_scorecard(summary)        # → scorecard.json
write_report_md(scorecard)                  # → report.md(派生,非权威来源)

Validation 脚本与 docs generator 会 import reporting/validation.py,并期望 scorecard field 稳定。在此重命名 field 会破坏 release gate。具体入口:build_scorecard 在 reporting/scorecard.py:136、write_scorecard 在 :270、build_run_summary 在 reporting/run_report.py:208、_validate_scorecard 在 reporting/validation.py:207。

CLI/TUI/MCP 如何把用户意图编译为这些 runner 消费的 EvaluateRunRequest / ModelBenchmarkRunRequest,见 使用界面与编排。

改动规则

改 evaluation 内部代码前先看此表。它列出其他团队与自动化依赖的兼容面;破坏它们需同步更新 validation、docs export 与示例 scorecard。

  • api/* dataclasses — to_dict() / from_dict() JSON-safe payloads。
  • evaluation/tasks/run_* output writing — 文件名、JSONL row shape、sample_id 对齐、final manifest status。
  • models/resolver.py — Error messages、runner resolution、model-zoo variant selection。
  • evaluation/tasks/official/* schema — Manifest parsing 和 alias lookup behavior。
  • reporting*.py and scorecard.py — Validation、docs 和 release reports 使用的 scorecard fields。