评测核心
evaluation 包内 requests、runners、metrics、catalog 与 reporting 如何衔接。
简介
本文说明 evaluation 包如何串联——不是文件索引,而是职责顺序。端到端 run 故事先看 Workflow;需要判断改动归属哪一层、哪些面必须跨版本保持稳定时再读本文。
包内数据流是单向的:公开契约定义 JSON-safe 形状,执行 runner 产生副作用与 artifact,catalog loader 把 YAML 转为契约,reporting 把 metrics 变成 scorecard。API 模块应保持 import-light;重型 runtime 不应反向泄漏进 evaluation/api/。
模块级查找见 代码库地图。
端到端流程
无论是否加载模型,每次 evaluation run 都经过相同的高层阶段:
# evaluation/tasks/execution/evaluate.py
result = run_evaluate(request)
# _mode() 选择 delegate runner:
if mode == "existing-results":
runner = ExistingResultsRunner(...)
elif mode == "model" and uses_metric_objects:
runner = ContractRunner(...) # model + Metric objects
elif mode == "model" and uses_benchmark:
runner = ModelBenchmarkRunner(...) # model + benchmark
else:
runner = ExistingResultsRunner(...) # model + metric ids
# 各路径最终都汇聚到 metrics + reporting:
runner.generate(...) # 仅 ContractRunner / ModelBenchmarkRunner
metrics = runner.compute_metrics(...)
report = runner.write_scorecard_and_report(metrics)evaluate.py 中的 facade 保持薄:校验输入、选择 delegate、转换结果。所有文件写入、sample ledger 与 manifest 更新都在 delegate runner 内完成。
公开契约
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 翻译成这些契约。
执行路径
三条 delegate runner 覆盖常见执行形态。匹配任务选路径——不要在 facade 里堆条件分支,新增 delegate 即可。
ContractRunner(contract.py)是 model 执行加 Metric 对象的 in-process 参考路径。它归一化 requests、写 execution plan、运行 generation(可选 SQLite cache 复用)、计算 per-sample metrics、聚合后产出 scorecard 与 report artifact。需要最严格 artifact 布局且 metric 对象同进程时使用。
ExistingResultsRunner(existing_results.py)评分磁盘上已有 artifact。从 path 或 inline list 加载 results、对齐 requests、运行 built-in metric id 或 artifact check,写出与完整 model run 相同的 summary 与 scorecard bundle。用于 hosted API 批处理、离线 demo,或 generation 发生在 WorldFoundry 外部的 workflow。
ModelBenchmark runner(model_benchmark.py)把 generation 与 benchmark-zoo runner 串联。解析 benchmark manifest、从 task registry 物化 requests、运行模型、为 external evaluator 物化生成 artifact,再把归一化 metrics 交给 reporting。用于端到端 model-plus-benchmark run。
Model mode 收到 string metric id 而非 Metric 对象时,即使 generation 已在进程内完成,scoring 也会走与 ExistingResultsRunner 相同的路径。见 Workflow — Model Mode 细节。
可复现 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。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 instanceBuilt-in runner 经 builtins.py 与 registry.py 注册;custom target 从 catalog runner_target 字符串解析。manifest.py 与 schema.py 中的 catalog metadata 是 provenance 与 readiness——不能替代可运行 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.jsonExternal benchmark 留在 runner 边界之后:vendor evaluator 产出 raw output,normalizer 转为稳定 metrics,共享 reporting 层写 metrics/summary.json 与 scorecard.json。
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。
改动规则
改 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。 |