# Workflow (/zh/docs/maintainers/architecture/workflow)



## 简介 [#简介]

本文追踪一次 evaluation run 从 CLI 到磁盘 artifact 的完整路径。当你需要知道某个 flag 落在哪段代码、哪个 runner 负责写文件、或 model mode 为何会分叉到 `ContractRunner` 与 `ExistingResultsRunner` 时读这里。面向用户的命令示例见 [评测指南](/zh/docs/evaluation)；本文聚焦执行 plumbing。

## 入口 [#入口]

每条用户可见命令最终都会到达 `evaluation/tasks/execution/evaluate.py` 中的 `run_evaluate()`。控制台入口是 `worldfoundry/cli/main.py`，子命令会分发到以下四种形态之一：

* **evaluate** — 归一化输入、选择 run mode，返回一个 `EvaluateRunResult`。
* **existing outputs** — 通过 `existing_results.py` 评分磁盘上已有 artifact，不加载模型。
* **model run** — 经 `resolver.py` 解析 model runner，调用 `generate()`，再评分归一化结果。
* **model plus benchmark** — 经 `model_benchmark.py` 先生成，再端到端调用 benchmark-zoo runner。

第一个实质分支始终是 mode 选择：本次 run 是否需要在 GPU 上加载权重，还是只消费已有文件。

## Evaluate 主流程 [#evaluate-主流程]

主流程如下：一个 `EvaluateRunRequest` 进入 facade，选定 mode，从 task registry 加载或物化输入，再由 delegate runner 写出标准 artifact bundle。若输出目录缺文件，沿此流程查应由哪个 runner 阶段产出。

```python
# worldfoundry/cli/main.py → evaluation/tasks/execution/evaluate.py
result = run_evaluate(EvaluateRunRequest(...))

mode = _mode(request)
requests, results = load_or_materialize(request)  # task registry / 磁盘路径
runner = pick_delegate_runner(mode, request)

runner.run(requests, results)
# 写入 output_dir/：
write("run_manifest.json")
write("execution_plan.json")
write("requests.jsonl")
write("results.jsonl")
write("sample_ledger.jsonl")
write("metrics/summary.json")
write("scorecard.json")
write("summary.json")
write("report.md")
```

Facade 本身很小。`run_evaluate()` 只做请求校验、模式选择和 runner 分发；真正的文件写入和样本级 accounting 由 delegate runner 负责。

## 模式行为 [#模式行为]

Mode 选择是第一个影响成本与前置条件的分支。`existing-results` 不加载权重，只评分磁盘上已有内容，因此 hosted API 批处理与离线 demo 常用它。`model` 会先解析 runner 并调用 `generate()`；传入的 metrics 类型决定 scoring 留在进程内（`ContractRunner`）还是复用 existing-results 路径（`ExistingResultsRunner`）。

| Mode               | 必需输入                                    | 是否加载模型 | 指标路径                                                                                         | 什么时候用                                |
| ------------------ | --------------------------------------- | ------ | -------------------------------------------------------------------------------------------- | ------------------------------------ |
| `existing-results` | `results` 或 `results_path`；requests 可选  | 否      | Built-in metric ids 或 artifact checks                                                        | Demo、hosted job 或离线脚本已经产出 artifacts。 |
| `model`            | Requests 加 runner config 或 model-zoo id | 是      | 传 Metric objects 时走 `ContractRunner`；传 metric ids/artifact checks 时走 `ExistingResultsRunner` | 希望由框架执行模型。                           |

## Model Mode 细节 [#model-mode-细节]

`runner.generate()` 返回后，`_align_model_results()` 保证每个 request 都有对应 result 行（含显式失败）。下面分叉容易被忽略：传入 `Metric` 对象则整次 run 留在 `ContractRunner`；传入 string metric ids 则 scoring 走与 `existing-results` 相同的代码路径。

```python
runner = resolve_model_zoo_runner(request.model_id)
results = runner.generate(requests)
results = _align_model_results(requests, results)

if isinstance(request.metrics[0], Metric):
    return ContractRunner(...).score(results)          # Metric objects → 进程内
else:
    return ExistingResultsRunner(...).score(results)  # metric ids → existing-results 路径
```

关键点：模型执行和 benchmark scoring 是分开的。Model runner 只输出 `GenerationResult`；结果归一化后才评分。

## Contract Runner 细节 [#contract-runner-细节]

`run_contract()` 是最严格的 in-process path，也是 artifact 布局的参考实现。每个阶段都会写出或更新下游 validation、docs export 与 leaderboard 工具期望找到的文件。调试不完整 run 时按阶段顺序排查：缺少 `metrics/per_sample.jsonl` 通常是 generation 未完成对齐，而非 reporting 失败。

```python
# evaluation/tasks/execution/contract.py → run_contract()
requests = _normalize_requests(request)
write_execution_plan(requests)                # execution_plan.json
write_run_manifest(status="running")          # run_manifest.json

results = run_generation_with_cache(runner, requests)
write_artifacts_jsonl(_artifact_rows(results)) # artifacts.jsonl
write_per_sample_metrics(...)                 # metrics/per_sample.jsonl
summary = _build_summary(...)                 # metrics/summary.json
write_scorecard(summary)                      # scorecard.json
write_run_report_artifacts(summary)           # summary.json + report.md
write_run_manifest(status="finished")         # 最终 run_manifest.json
```

Generation 是最耗时的阶段：runner 异常会变成 failed samples，确定性输出可复用 SQLite generation cache。Reporting 阶段只在每个样本都有对齐 result 行之后才运行。

## Artifact 契约 [#artifact-契约]

这些文件构成 [评测指南](/zh/docs/evaluation#main-outputs) 中的 audit trail。各 run mode 下形态稳定：`existing-results` 仍会写 `sample_ledger.jsonl` 和 `scorecard.json`，便于与同一 benchmark 上的完整 model run 对比。路径均相对 `run_manifest.json` 中记录的 run 输出目录。

| 文件                         | 生产者                                    | 含义                                                                         |
| -------------------------- | -------------------------------------- | -------------------------------------------------------------------------- |
| `run_manifest.json`        | Runner                                 | Run identity、status、model、benchmark、dataset、context metadata、output paths。 |
| `execution_plan.json`      | Runner 或 `RunPlan`                     | Planned stages、sample ids、materialization details、output files。            |
| `requests.jsonl`           | Runner                                 | 每个样本一个归一化 `GenerationRequest`。                                             |
| `results.jsonl`            | Model runner through evaluation runner | 每个样本一个归一化 `GenerationResult`。                                              |
| `sample_ledger.jsonl`      | Runner                                 | 样本级 pass/fail 状态和 stage-level errors。                                      |
| `artifacts.jsonl`          | Runner                                 | 相对 output directory enrich 后的 flattened artifact refs。                     |
| `metrics/per_sample.jsonl` | Metrics layer                          | 样本级 metric output 或 skipped state。                                         |
| `metrics/summary.json`     | Metrics layer                          | Aggregates、failed ids、skipped ids、leaderboard fields。                      |
| `scorecard.json`           | Reporting layer                        | Release/review surface，供 validation 和 docs 消费。                             |
| `report.md`                | Reporting layer                        | 从 scorecard 派生的人类可读摘要。                                                     |

## Task Materialization [#task-materialization]

Task-driven run 在任意模型代码运行*之前*固定 sample id、split 与 input keys，使 rerun 与 cache 复现可预期：相同 task YAML 与 dataset manifest 应在每台机器上产出相同的 `requests.jsonl` 行。下方代码把 catalog task YAML 接到 `run_evaluate()` 已理解的 `EvaluateRunRequest`；YAML 文件位置见 [基准和数据](/zh/docs/maintainers/architecture/benchmarks-data)。

```python
registry = load_task_registry_from_paths(task_yaml_paths)
plan = build_run_plan_from_task_registry(registry, dataset_manifest)
requests = _materialize_requests_from_task(plan)
requests = materialize_generation_requests(requests)
return EvaluateRunRequest(requests=requests, ...)
```

当 sample id、split、input keys、output keys 和 cache policy 需要在 generation 前可复现时，用这条路径。
