> ## Documentation Index
> Fetch the complete documentation index at: https://opencompass-docs-preview-pr-335-0.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 共同契约

先把数据集记录转换为稳定的 `TaskSpec`，再明确哪些字段可以交给 Harness、哪些状态只能用于评测。

## 区分四种数据载体

| 载体 | 主要使用方 | 适合保存 | 不应保存 |
| - | - | - | - |
| `TaskSpec` | Benchmark、规划器、Recipe | 稳定任务 ID、题目、类别、上游元数据、逐任务评测模式和网络策略 | provider 会话或已经打开的 Environment |
| `BenchmarkPlan` | 当前任务尝试中的 Benchmark 与规划器 | 已解析配置、工作区路径、验证器超时、评测器需要的类型化状态 | provider SDK 客户端、可变全局状态 |
| `PreparedTask` | Harness 或 `HarnessFreeBenchmark.run_task()` | 提示词、消息、文件、媒体、工具、工作区和期望输出 | 隐藏答案、参考补丁、私有测试或评分密钥 |
| `RunResult` | Benchmark、runtime、结果使用方 | 执行状态、答案、轨迹、产物、分数和可公开的评测证据 | 无法序列化的对象或凭证 |

Harness 可以读取整个 `PreparedTask`，包括其中的 `ground_truth` 和 `metadata`。不要未经筛选就复制 `TaskSpec.metadata`。

仅供评测使用的数据应留在 `TaskSpec.ground_truth` 或类型化 `BenchmarkPlan` 中，并把 `PreparedTask.ground_truth` 设为 `None`。这些对象仍处于 runtime 和结果审计范围内，因此不能保存凭证或其他禁止持久化的秘密材料。

只有可以随结果公开的参考答案，才能写入 `RunResult.ground_truth`。

## 定义公开配置

Benchmark 参数应使用 `RuntimeBenchmarkConfig` 和 `config_field()`，并在 `__post_init__()` 中尽早规范化类型：

```python theme={"system"}
from dataclasses import dataclass

from agentcompass.benchmarks.config import RuntimeBenchmarkConfig
from agentcompass.runtime.config import config_field, parse_bool


@dataclass(slots=True)
class ExampleExactMatchConfig(RuntimeBenchmarkConfig):
    case_sensitive: bool = config_field(
        default=False,
        description="Compare answers with case sensitivity.",
    )

    def __post_init__(self) -> None:
        RuntimeBenchmarkConfig.__post_init__(self)
        self.case_sensitive = parse_bool(self.case_sensitive, "case_sensitive")
```

不要在模块导入时下载数据、安装依赖或读取凭证。应通过显式加载器或依赖准备流程访问数据；如果版本、数据划分或访问条件不符合要求，请给出包含解决办法的错误信息。

## 加载确定性任务

`load_tasks()` 应固定上游版本并生成稳定的 `task_id`。下面的 `metadata` 只包含可以进入日志和执行输入的复现信息；答案单独放在 `ground_truth` 中：

```python theme={"system"}
def load_tasks(self, req: RunRequest) -> list[TaskSpec]:
    _ = req
    return [
        TaskSpec(
            task_id="capital-france",
            question="What is the capital of France? Answer with only the city name.",
            category="geography",
            ground_truth="Paris",
            metadata={"dataset_revision": "tutorial-v1"},
        )
    ]
```

继承的 `select_tasks()` 已提供 runtime 的通用任务选择逻辑。只有当前 Benchmark 的规则不同于普通 ID 过滤时，才需要覆盖该方法；无论采用哪种规则，都要保证返回顺序确定。

### Harbor 任务与执行要求

通过 `agentcompass.benchmarks.utils.harbor` 中的 `load_harbor_task()`，可将 Harbor 任务目录转换成 `TaskSpec`。除了 network policy 和 resources，adapter 还映射以下执行要求：

| Harbor 声明 | AgentCompass 任务字段 | 生效范围 |
| - | - | - |
| `agent.timeout_sec` | `run_timeout_seconds` | `run_task` / `run_harness` 阶段 |
| `verifier.timeout_sec` | `evaluation_timeout_seconds` | 每次 `evaluate` 调用 |
| `environment.docker_image` | `environment_setup.image` | provider 原生的 registry 镜像选择 |
| `environment.workdir` | `environment_setup.workdir` | 环境内默认的命令执行目录 |
| `environment.build_timeout_sec` | `environment_setup.build_timeout_seconds` | 环境构建和启动，不包含全局创建速率限制的排队时间 |
| `environment.os` | `environment_setup.os` | 分配环境前校验 provider 的 OS 能力 |
| `verifier.environment.network_mode` / `allowed_hosts` | `evaluation_baseline_network_policy` | fresh verifier 启动及基线恢复，与执行阶段策略分离 |
| `environment.env` | `env_variables` | 任务的公共环境变量 |
| `verifier.environment.env` | `evaluation_environment_env_variables` | fresh verifier 的启动环境变量 |
| `verifier.env` | `evaluation_env_variables` | 仅注入评测命令，不注入 agent 命令 |
| `artifacts` | `artifacts` | 文件、目录下载，以及 fresh verifier 中的恢复 |
| `verifier.collect` | `artifact_collect` | 在 agent sandbox 中按顺序执行提交生成命令 |

显式独立的 verifier 环境通过 `evaluation_environment_setup` 提供独立的镜像、工作目录和构建超时基线：未填写的值不会继承 agent 的设置，显式空配置也保持独立。只有 `None`（没有声明独立基线）才继承解析后的运行环境设置，包括 Recipe 默认值。请求中的 `EnvironmentSpec.setup` 和 `evaluation_setup` 覆盖任务默认值；Provider 原生启动选择器不属于公共输入。工作目录、启动超时、环境变量和出站规则只接受通用字段；provider 原生别名会报错。

容器镜像的解析结果统一保存在 `EnvironmentSpec.setup.image`。Harbor 的 `environment.docker_image` 映射到任务 setup；Recipe 读取合并后的 plan setup，只在镜像缺失时向该字段补充默认值，不再读写 `params["image"]`。provider 仅在构建环境配置时将该字段转换为自身参数。请求入口拒绝旧参数 `image` 和 `evaluation_image`，必须直接配置 `setup.image` 和 `evaluation_setup.image`。配置示例： `--env-params '{"setup": {"image": "registry.example/runner:v1"}}'`。

fresh verifier 的网络遵循同样的独立规则：显式 `verifier.environment` 提供自己的基线，空表也使用独立的默认 public 网络；未声明 verifier 环境才继承 agent 基线。请求中的 `evaluation_baseline_network_policy` 优先于公共请求 `baseline_network_policy`，后者优先于任务的 verifier 基线。runtime 使用该基线启动 verifier，在评测时切换到 `evaluation_network_policy`，之后恢复基线，不会用其中一种策略静默替代另一种。可以用 `--env-params '{"evaluation_baseline_network_policy": {"network_mode": "no-network"}}'` 只覆盖 fresh verifier 的基线；该请求字段要求 fresh evaluation。

`workdir` 必须是环境内的 POSIX 绝对路径，用于 `env.exec()` 没有指定 `cwd` 的情况；显式 `cwd` 优先。它不会替换 Benchmark/Harness 显式指定的工作区。SWE-Marathon 使用统一的 workdir 作为工作区，未声明时依次回退到 Dockerfile 的 `WORKDIR` 和配置的工作区根目录。可以用 `--env-params '{"setup": {"workdir": "/app"}}'` 覆盖任务默认值。

这些是分别计时的阶段 deadline，不是整个 task 共用的 wall clock、单次工具调用超时或 sandbox 生命周期。任务字段为 `None` 表示未指定 deadline；指定秒数时必须是有限正数。adapter 只映射显式声明的超时，不引入 Harbor 的隐式默认值。映射构建超时不会让仅支持预构建镜像的 provider 自动获得构建 Dockerfile 的能力。

Benchmark 可用 `BenchmarkPlan.run_timeout_seconds` 和 `evaluation_timeout_seconds` 提供 task/Benchmark 默认值。Planner 先解析请求中的 `execution.run_timeout_seconds` 和 `evaluation_timeout_seconds`，再应用阶段倍率（`run_timeout_multiplier` 或 `evaluation_timeout_multiplier`）或公共 `timeout_multiplier`。阶段倍率替换公共倍率；缺省或 `null` 的覆盖值继承默认值。仅当 task/Benchmark 均未提供执行默认值时，才使用 Harness 回退预算。

最终 `ExecutionPlan` 将解析后的执行预算 `T` 传给 Harness，将解析后的评测预算传给评测器。runtime 包裹 Harness `execute_task()` 的 watchdog 使用 `T + run_timer_compensation_seconds`，补偿默认 120 秒；无 Harness Benchmark 的 `run_task()` 直接使用 `T`。执行与 `evaluate()` 分别计时，复用 Environment 和 fresh Environment 的规则一致；随后在关闭 session 前通过 `collect_result()` 回收已保存的 Harness 输出，使用 `runresult_collect_timeout_seconds`（默认 60 秒）。回收不得继续执行 agent，也不会清除原始执行错误；执行和评测倍率不影响补偿或回收预算。超时后 runtime 记录阶段错误，并尝试适用的产物采集和清理流程。取消协程本身不能确认远程进程已经停止。

产物准备使用独立的 `artifact_collect_timeout_seconds` deadline（默认 `null`）；下载/恢复使用 `artifact_limits.timeout_seconds`（默认 600 秒）。通过 YAML 的 `execution`、SDK 的 `execution_params` 或 `run` 的 `--execution-params` 配置。这些预算不延长 sandbox TTL，也不覆盖整个运行的取消机制。

未映射的声明保存在 `TaskSpec.load_warnings` 中。runtime 在 `select_tasks()` 之后才打印这些警告，因此被排除的 sample 不产生告警。直接调用 loader 的代码可以自行检查此列表。真正未支持的声明仍会保留告警，不能仅因为原始 metadata 保存了字段，就将其标记为已映射。

`environment` 或 `verifier.environment` 下旧版 `memory`、`storage` 的容量字符串，只有被 Harbor 转换为对应的 MiB 资源字段时才视为已映射。旧字段与新字段冲突时仍会校验失败；被忽略的旧字段值仍保留未映射告警。

任务来源信息保存在 `TaskSpec.metadata` 中：顶层 `source` 映射到 `metadata["source"]`，包含 `task.version` 的包信息映射到 `metadata["task"]`。显式任务声明优先于自由格式 metadata 表中的同名条目。包版本必须是非空字符串，不要求遵循语义化版本；旧版 Harbor 未定义此字段时，由 adapter 进行兼容校验。顶层旧字段 `version` 仍是 `schema_version` 的别名，不代表包版本。原始声明在 `harbor_raw` 中保持不变。

Recipe 应用后的最终 `ExecutionPlan` 是执行时的唯一来源。Harness 和 verifier 不再读取 task TOML、私有 timeout 字段或 metadata 中的 timeout。Recipe 必须修改 `plan.run_timeout_seconds` 和 `plan.evaluation_timeout_seconds`，再由 Planner 将运行超时映射到 Harness 原生字段。

### 任务环境变量

任务和环境的公共契约分别提供公共、运行阶段专用和评测阶段专用的变量：`env_variables`、`run_env_variables` 和 `evaluation_env_variables`。`TaskSpec.evaluation_environment_env_variables` 提供 fresh verifier 独立的启动变量基线：`None` 继承任务公共变量，显式映射则替换它们，空映射也不继承。Harbor 将生效的独立 verifier 环境中的 `env` 表映射到此字段，而不是仅用于命令的阶段变量。计划中保留 `${GRADER_KEY}` 等引用，由 provider 在执行前从启动进程的环境中解析。只需 export 所选任务要求的 key；缺少必需引用时会在分配环境前报错，不打印变量值。同时支持 `${NAME:-default}` 和字符串内嵌引用，不执行 shell 命令展开。

请求级配置按 key 覆盖任务默认值；请求中的阶段变量优先于公共变量，当前阶段变量优先于内部 `env.exec(env=...)` 默认值。不得覆盖的原生协议要求应通过 `env.require_exec_env()` 显式校验；冲突时只报告变量名，不打印值。agent 安装/执行和评测命令使用同时按 session 与异步上下文隔离的临时作用域，成功、失败或取消后均恢复。任务准备、结果回收、Harness 清理、产物生成命令与产物恢复只使用公共变量，不继承 agent 专属变量。provider 支持时，公共变量也会注入 sandbox 启动过程；阶段专用变量只用于命令，不进入镜像 entrypoint。这是注入契约，不是针对复用 sandbox 中残留进程或文件的安全隔离边界。`host_process` 仍继承宿主进程环境。

`EnvironmentSpec.evaluation_environment_env_variables` 是请求层的 fresh 启动变量覆盖入口，要求 `evaluation_environment_mode="fresh"`。它按 key 覆盖任务 verifier 基线和请求公共变量；执行评测命令时，请求的评测专用变量优先级更高。请求中缺省表示继承，空映射表示不增加覆盖；与任务中的显式映射不同，请求空映射不清空任务基线。

旧 Harness `env` 参数会报错，应迁移到 `environment.run_env_variables`。Harness 适配原生工具配置时从当前 Environment 作用域获取解析后的变量，不修改 `RunRequest` 或宿主 `os.environ`。直接运行在本地的 SDK 继续使用显式 SDK 配置；这些变量只注入经 Environment 执行的命令。

Harbor 的 `solution.env` 默认属于参考解。只有确认这些变量确实也是 agent 任务所需时，Benchmark 才应通过 `solution_env_for_agent=True` 显式启用映射；不能自动把参考解的密钥注入 agent。

### 提交产物与回放

`TaskSpec.artifacts` 是 Benchmark 或格式适配层提供的文件清单。`collect_artifacts = true` 的 Benchmark 始终包含主环境约定目录 `/logs/artifacts/`。Harbor 适配层在加载 task 格式时解析同一目录（包括 Harbor 中的空声明），并添加显式附加路径；原生 Benchmark 在规划时遵循相同规则。`TaskSpec.artifacts = []` 或 `execution.artifacts = []` 表示没有额外路径，并不关闭收集；只有 `collect_artifacts = false` 才会关闭收集。显式声明约定目录时使用该条目的排除配置。目标路径冲突时沿用 Harbor 的先到先保留规则并给出警告，公共 runtime 接收不重叠的清单。

Benchmark 声明提供收集默认值。`execution.artifacts` 指定时会替换 task 专用的额外路径，但收集型 Benchmark 的 `/logs/artifacts/` 始终保留；未指定或为 `null` 时继承，`[]` 表示只收集该约定目录。`execution.artifact_collect` 独立覆盖命令，其中 `[]` 清空命令列表。runtime 使用解析后的列表；只有 `collect_artifacts = false` 才跳过收集。`collect_artifacts` 只是解析后计划中的只读值，不是 CLI、YAML 或 SDK 的执行参数。`execution.save_artifacts` 控制本地持久化：未指定或为 `null` 时，fresh 解析为 `true`，reuse/none 解析为 `false`。fresh 必须保存，显式设置 `save_artifacts=false` 会在创建环境前报错。reuse/none 关闭保存只跳过文件下载，仍执行声明的准备命令；仅开启保存不会增加收集路径。保存文件不会保留 sandbox，环境生命周期仍由 `keep_environment` 控制。答案、轨迹、日志及 Benchmark 专用评测输出不受影响。具备已分类推理快照及完整评分输入时，none/fresh 支持仅评测恢复；reuse 必须重新执行 attempt。

当产物路径依赖 Recipe 最终选定的 workspace 时，可覆盖 `BaseBenchmark.resolve_artifacts(task, req, plan)`。Planner 会在全部 Recipe 之后、最终规范化之前调用它；显式 `execution.artifacts` 仍具有最高优先级，并跳过 Benchmark 默认值。

### 覆盖产物路径和准备命令

`execution.artifacts` 和 `execution.artifact_collect` 分别覆盖 task/Recipe 的额外路径和命令。未指定或为 `null` 时继承对应声明；显式 artifact 列表会替换额外路径，但始终保留 `/logs/artifacts`，包括 `[]`，此时只收集该目录。CLI 列表会替换对应的 YAML 列表；没有 task 专用默认声明的 Benchmark 也可以通过这些参数指定路径或命令，前提是它支持收集。Benchmark 类可以声明 `collect_artifacts = False`，此时显式覆盖任一列表（包括 `[]`）都会在规划阶段报 `unsupported`；未指定或为 `null` 不算覆盖。该能力默认 `True`，不是 Benchmark params 或 execution 的 CLI 参数，Recipe 也不能重新启用。需要保留 task 专用条目再增加自定义条目时，应在替换列表中包含所需的原始条目。

```bash theme={"system"}
agentcompass run deepswe claude_code "$MODEL_NAME" \
  --env docker \
  --model-base-url "$MODEL_BASE_URL" \
  --model-api-key "$MODEL_API_KEY" \
  --execution-params '{
    "save_artifacts": true,
    "artifacts": [
      {"source": "/app/submission", "destination": "submission", "exclude": ["*.tmp"]},
      {"source": "/app/result.json", "destination": "result.json"}
    ],
    "artifact_collect": [
      {"command": "mkdir -p /app/submission && printf example > /app/submission/note.txt", "timeout_seconds": 60}
    ]
  }'
```

`source` 是 agent sandbox 内的绝对路径，可以指向文件或目录。`destination` 相对于当前 attempt 的本地 `artifacts/` 目录：上例 `/app/submission` 保存到 `artifacts/submission/`，排除 `*.tmp`；另一个文件保存为 `artifacts/result.json`。源路径不存在时会记录缺失状态，不会使收集失败。目标存储路径重叠会在执行前报错。fresh 评测将文件恢复到原始 `source` 路径。

只执行解析后的命令列表，按列表顺序完成后才下载文件；覆盖命令时不会自动先执行 Benchmark 的原始命令。CLI 命令使用 `timeout_seconds`，Harbor `task.toml` 使用 `timeout_sec`。准备和传输预算作用于解析后的列表。reuse/none 下 `save_artifacts=false` 仍执行命令；fresh 必须保存。示例命令生成演示文件，并替换 Benchmark 的原始命令列表。替换列表中应保留 verifier 所需的准备命令，否则可能无法生成评测所需的提交内容。

Recipe 可以调整解析后的路径。`None` 和 `[]` 表示没有解析后的路径，不再作为 Harbor 原始声明处理。调整后重新校验路径；关闭整条收集流程应使用 execution 开关。`host_process` 的绝对来源路径指向宿主文件系统。

默认目录是可选输出：来源不存在时记录为 `missing`，空目录成功下载后记录为 `collected`，内容字节数为零。两种情况都不会阻止评测或 checkpoint 创建；空目录会保留用于 fresh 恢复，缺失条目不会上传文件。权限错误、异常祖先路径、传输失败、超时和超限仍属于采集错误，不会伪装成无产物，既有失败处理保持不变。空采集本身不证明任务能够独立评测，回放仍需具备 verifier 要求的全部输入。

`ArtifactSpec` 位于 `agentcompass.runtime.artifacts`。字符串声明表示 sandbox 中的绝对源路径；对象声明还可指定产物存储区内的相对 `destination` 和 `exclude` 模式。默认目标路径是去掉源路径开头的斜杠。采集支持文件、二进制数据和目录，排除规则使用 GNU tar 模式；目标路径重叠、路径或链接越界、特殊文件以及非主服务声明都会显式报错。

runtime 先执行声明的收集命令（如果有）。关闭收集开关时跳过整条流程；否则没有命令就跳过准备，仍可收集已有文件。持久化开启时，在释放 agent 环境前复制选定的产物。二进制内容保存在结果目录的 `artifacts/` 下，`RunResult.artifacts.declared_artifacts` 只记录相对路径、状态、大小和校验和。迁移运行结果时需要连同该目录一起保留。复用结果会先校验并复制引用的产物字节，再保存复用的 detail 或终态 attempt checkpoint；产物缺失或损坏时，该结果会重新运行。不同 run 的产物文件不会通过硬链接共享。源文件缺失或被完全排除时会记录状态，由 verifier 评分；传输错误和超限会让采集失败。

runtime 在 agent sandbox 中按顺序执行 `ExecutionPlan.artifact_collect`；没有命令就跳过准备，不调用 Benchmark 回退钩子。公共 `download_artifacts()` 在持久化开启且清单非空时负责打包、传输、校验和本地存储。解析后的空路径列表不会禁止声明命令执行。

Harbor 的 `verifier.collect` 映射到 `TaskSpec.artifact_collect`，由 Planner 复制，并在 Recipe 调整后再次校验。每条声明映射 `command`、`timeout_sec` → `timeout_seconds`（默认 60 秒）以及 `service`（默认 `main`）。命令使用 `bash -c` 按顺序执行，沿用运行阶段的网络策略，但只使用公共环境变量，发生在评测及环境释放之前；不注入 verifier 专属变量，变量引用在 sandbox 中展开，不在任务加载时展开。每条命令具有独立的有限正数超时，还受可选的收集阶段总 deadline 限制。暂不支持 sidecar 服务和命令级 `user` 覆盖，加载时会明确报错；未知命令字段也会明确报错。

仅关闭 `save_artifacts` 时，声明的命令仍会执行；也可以只指定路径而不声明命令。路径描述已有或预期的提交物，不描述如何生成它们。任务已提供 collect 命令时，会完全绕过 Benchmark 钩子。例如：

```toml theme={"system"}
artifacts = ["/logs/artifacts/result.txt"]

[[verifier.collect]]
command = "mkdir -p /logs/artifacts && cp /app/result.txt /logs/artifacts/result.txt"
timeout_sec = 300.0
```

采集清单以 `submission-*.manifest.json` 的形式原子写入提交目录旁边。后续操作失败时，已成功校验的文件仍保留在磁盘中。`ArtifactDownloadError.manifest` 返回 `complete=false` 的部分记录，区分失败、取消和未采集条目；runtime 将其保留在 `declared_artifacts` 中，并在 telemetry 的 `post_run_errors` 中分别记录准备和传输错误，不覆盖原始运行错误。准备失败后仍尝试采集已有文件，但准备或传输失败都会阻止该次尝试进入评测及生成可续跑 checkpoint。显式取消继续向上传播，磁盘清单保留用于诊断。进度事件包含当前操作、已完成的字节和条目、已知的归档大小及剩余预算；provider 下载接口不提供连续的逐字节进度。

fresh evaluation 会先验证清单和校验和，再将产物恢复至原 sandbox 源路径，然后调用 `evaluate()`。目录恢复会替换目标目录的内容，清除旧文件和隐藏条目，但保留目录本身以兼容挂载工作区。恢复时先暂存完整产物，安装失败时尝试回滚；中断后保留恢复暂存区，直到环境清理。reuse evaluation 不会覆盖现场工作区。旧结果中的内联文本产物仍可兼容，但必须覆盖全部声明的输出。`ExecutionPlan.artifact_limits` 默认限制每次采集或恢复为 16 GiB、100,000 个文件系统条目、600 秒，Recipe 可以调整这些类型化限制。清理临时目录前，会等待本地文件操作完成或响应取消。

父路径先于子路径恢复，不受声明或 manifest 顺序影响，因此显式采集的子路径不会被父目录的排除规则覆盖。同一源路径存在不同排除规则时，fresh 计划会报错；同源副本的采集状态、内容和权限必须在上传前校验一致，相同副本只恢复一次。

同一个逻辑 attempt 重跑 agent 前，runtime 会将上一轮产物、结果和 checkpoint 归档到 `retries/<id>/`，并更新诊断记录中的产物引用。新的实际运行从空产物目录开始；仅恢复评测时保留已有输入。

DeepSWE v1.1 的锁定版本声明了 `verifier.collect` 命令，提取 base commit 到 `HEAD` 的差异，因此需要 agent 自行提交改动。runtime 不会自动提交或执行旧版 `pre_artifacts.sh`。公共下载器传输声明的 patch，SWE-Marathon 的目录声明使用同一套下载器。

Harbor adapter 只映射 Harbor 官方字段。SWE-Marathon 直接使用 `load_harbor_task()`，不支持其自定义的 `verifier.type` 和 `grader.restore_paths`。原始声明仍保留在任务 metadata 中，runtime 仅对选中的任务输出未映射字段告警。AgentCompass 不校验或执行这两个扩展：它们既不会选择 verifier 实现，也不会触发文件恢复。SWE-Marathon 的正常评测仍在复用的 agent 环境中执行 `tests/test.sh`。checkpoint 选择和评测续跑属于独立的 runtime 职责，不属于任务格式映射。

`runtime.checkpoint` 保存已分类的推理与准备输入快照、网络策略和产物完整性信息，支持 none／fresh 评测恢复；失败评分不能污染保存的输入。

v4 checkpoint 恢复 `PreparedTask` 和推理结果，包括 issues、轨迹与用量；每轮评分使用独立副本。driver 输入文件按保存的路径与摘要校验，缺失或发生变化时拒绝恢复。client/session 对象和未校验的远端媒体 URL 不能形成可恢复快照。旧版仅产物 checkpoint 仍可读取，但缺少跨 run 物化所需的已分类快照，可能需要重新执行；`prepare_evaluation(task, req, plan)` 保留为可支持的旧版 fresh checkpoint 的回退。详见[评测 checkpoint](/zh/user_guide/other_features/results/run_records#evaluation-checkpoints)。

## 为每次尝试建立类型化计划

如果评测状态需要结合配置和任务计算，请定义 `BenchmarkPlan` 子类，并在 `build_plan()` 中为当前尝试解析一次：

```python theme={"system"}
from dataclasses import dataclass

from agentcompass.runtime import BenchmarkPlan, EnvironmentSpec, RunRequest, TaskSpec


@dataclass(slots=True)
class ExampleExactMatchPlan(BenchmarkPlan):
    expected: str = ""
    case_sensitive: bool = False


def build_plan(
    self,
    task: TaskSpec,
    req: RunRequest,
    environment: EnvironmentSpec,
) -> ExampleExactMatchPlan:
    _ = environment
    config = self.build_config(req)
    if not isinstance(config, ExampleExactMatchConfig):
        raise TypeError("example_exact_match requires ExampleExactMatchConfig")
    return ExampleExactMatchPlan(
        expected=str(task.ground_truth),
        case_sensitive=config.case_sensitive,
    )
```

`build_plan()` 不应打开 Environment、调用 Model 或修改 `RunRequest`。初始 `ExecutionPlan` 建立后，Recipe 会按照自身契约调整计划，因此 Benchmark 文档不能假定 runtime 统一保证某种 Recipe 字段优先级。需要映射 provider 时，请在对应的 [Recipe 集成](/zh/developer_guide/extensions/recipe_integration)中说明并测试字段保留规则。

## 准备执行输入

`prepare_task()` 可以在任务 Environment 中创建工作区或上传公开材料，但返回值只能包含执行阶段可见的内容：

```python theme={"system"}
async def prepare_task(
    self,
    task: TaskSpec,
    env: EnvironmentSession,
    req: RunRequest,
    plan: BenchmarkPlan,
) -> PreparedTask:
    _ = env, req
    self._require_plan(plan)
    return PreparedTask(
        task_id=task.task_id,
        category=task.category,
        ground_truth=None,
        input=TaskInput(prompt=task.question),
        output=TaskOutput(answer="Return only the city name."),
        metadata={"dataset_revision": task.metadata["dataset_revision"]},
    )
```

需要创建文件或目录时，请使用传入的 `EnvironmentSession`，不要绕过 Environment 直接调用 provider SDK。重试时可能再次调用该方法，因此准备过程必须能够安全重复；否则，应在执行前明确清理自己创建的工作区。

## 注册与依赖

使用 `@BENCHMARKS.register()` 注册实现，并在 `src/agentcompass/benchmarks/__init__.py` 中导入模块：

```python theme={"system"}
from .example_exact_match import ExampleExactMatchBenchmark
```

在仓库根目录检查组件发现和参数结构：

```bash theme={"system"}
uv run agentcompass list benchmark
uv run agentcompass config docs benchmark example_exact_match
```

框架运行所必需的依赖应加入默认项目依赖。只有某个 Benchmark 使用的 Python 驱动，应加入单独的可选依赖组并声明 `DependencySpec`。任务或验证器需要的 runtime 依赖，则应固定在对应的 Environment 中。注册成功只说明模块可以导入，不代表数据、凭证、验证器或真实运行已经验证通过。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.