> ## Documentation Index
> Fetch the complete documentation index at: https://agent-compass.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 过滤时，才需要覆盖该方法；无论采用哪种规则，都要保证返回顺序确定。

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

如果评测状态需要结合配置和任务计算，请定义 `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 中。注册成功只说明模块可以导入，不代表数据、凭证、验证器或真实运行已经验证通过。
