> ## 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.

# runtime 契约与规划

本页说明配置如何解析为 `RunRequest`、Planner 如何为每次任务尝试生成 `ExecutionPlan`，以及这些类型如何约束组件边界。执行顺序与持久化格式分别由[执行、调度与清理](/zh/developer_guide/architecture/execution_lifecycle)和[结果与复用](/zh/developer_guide/architecture/results_and_reuse)说明。

公开导出集中在 `src/agentcompass/runtime/__init__.py`，具体数据类位于 `src/agentcompass/runtime/models/`，组件接口位于 `src/agentcompass/runtime/base.py`。配置和规划的主要实现文件如下：

```text theme={"system"}
src/agentcompass/runtime/config/loader.py
src/agentcompass/launcher.py
src/agentcompass/runtime/orchestration.py
src/agentcompass/runtime/planner.py
src/agentcompass/runtime/runner.py
```

## 请求与配置解析

`RunRequest` 是单次运行的完整输入，包含八个配置段：

```text theme={"system"}
RunRequest
  ├─ model: ModelSpec
  ├─ benchmark: BenchmarkSpec
  ├─ harness: HarnessSpec
  ├─ environment: EnvironmentSpec
  ├─ execution: ExecutionSpec
  ├─ runtime: RunRuntimeSpec
  ├─ output: OutputSpec
  └─ metadata: RunMetadata
```

| 配置段           | 含义                                          | 主要使用方                                          |
| ------------- | ------------------------------------------- | ---------------------------------------------- |
| `model`       | Model ID、端点、API 密钥、协议、推理参数与密钥封装设置           | Harness 或 `HarnessFreeBenchmark`               |
| `benchmark`   | Benchmark ID 与 Benchmark 专属参数               | 注册表、Benchmark、结果标识                             |
| `harness`     | Harness ID 与 Harness 专属参数                   | 注册表与 Harness；`id="none"` 选择无 Harness Benchmark |
| `environment` | Environment ID、provider 参数、阶段网络策略与评测模式      | Planner 与 Environment provider                 |
| `execution`   | 任务并发、Recipe、分析、Environment 保留和 runtime 重试策略 | Orchestrator、Planner、runtime、分析器               |
| `runtime`     | 当前请求的结果复用控制                                 | `RunStore` 与编排校验                               |
| `output`      | 结果命名空间与指定的运行 ID                             | `RunStore`                                     |
| `metadata`    | 已加载配置路径与受信任的外部 Recipe 目录                    | 启动器、队列序列化、运行级 Recipe 注册表                       |

`ModelSpec` 是值对象，不是注册型组件。系统没有 `MODELS` 注册表；注册表解析 Benchmark、Harness、Environment、Recipe 和分析器，选中的 Harness 或无 Harness Benchmark 直接使用 `req.model`。向 `ModelSpec` 增加字段时，应检查请求构造、脱敏、持久化签名以及使用该字段的 Harness，不要为普通端点配置增加注册表条目。

不要混淆 `RunRuntimeSpec` 和 `ResolvedRuntimeOptions`。前者属于单个请求，目前负责复用设置；后者位于 runtime 的 `models/orchestration.py` 模块，负责结果路径、截止时间、清理宽限期、provider 限制、Environment 打开速率、进度与日志等进程级共享行为。

`load_run_config` 按以下顺序读取实际存在的配置文件：

```text theme={"system"}
用户配置
  -> 最近的项目 config.yaml
  -> 按参数顺序排列的每个显式 config_path
```

`deep_merge` 递归合并映射且不修改任一输入。后出现的标量或列表替换先前值，嵌套映射按键合并。完整字段形式的 `${VAR}` 会从环境变量解析；将 `${VAR}` 嵌入更长字符串会被拒绝。运行配置中的组件配置段是 `benchmarks`、`harnesses` 和 `environments`，每个选中组件的参数直接平铺在其 ID 下。`models` 配置段会被拒绝，因为 Model 通过 `ModelSpec` 提供。

`build_run_request`、`run_evaluation` 与 `run` CLI 等单次运行入口按以下优先级解析，箭头从低优先级指向高优先级：

| 值                                | 解析顺序                                         |
| -------------------------------- | -------------------------------------------- |
| Benchmark、Harness、Environment 参数 | 运行配置中的选中组件条目 → 辅助函数或 CLI 的显式参数               |
| `ExecutionSpec` 字段               | 数据类默认值 → 运行配置 `execution` → 显式非 `None` 参数    |
| 进程 runtime 选项                    | runtime 默认值 → 运行配置 `runtime` → 显式非 `None` 参数 |
| Model                            | 仅使用显式 Model 参数                               |
| 输出与逐请求复用                         | 显式参数；未指定复用时使用配置中的 runtime 复用设置               |

如果调用方把已构建的 `RunRequest` 传给 `run_evaluation_request`，`_merge_request_with_config` 会用请求中的组件参数覆盖配置中对应的选中组件条目，同时保留请求中的 Model、执行设置、输出设置和显式复用值。已加载的配置路径与解析后的 Recipe 目录写入 `RunMetadata`。

编排路径由 `resolve_orchestration` 从 `OrchestrationSpec` 解析每个命名请求：

| 值              | 从低到高的优先级                                                                |
| -------------- | ----------------------------------------------------------------------- |
| 组件参数           | 运行配置中的选中组件条目 → 编排 `defaults` → 命名请求                                     |
| Model 字段       | 编排 `defaults.model` → 命名请求 `model`                                      |
| 任务并发以外的执行字段    | 数据类默认值 → 运行配置 `execution` → 编排 `defaults.execution` → 命名请求 `execution`  |
| 逐请求 runtime 字段 | `RunRuntimeSpec` 默认值与配置中的复用设置 → 编排 `defaults.runtime` → 命名请求 `runtime`  |
| 输出字段           | `OutputSpec` 默认值 → 编排 `defaults.output` → 命名请求 `output`                 |
| 编排 runtime     | runtime 默认值 → 运行配置 `runtime` → 编排文件 `runtime` → SDK/CLI 提供的 runtime 覆盖值 |

全局 `task_concurrency` 单独按“显式解析器参数 → 编排值 → 运行配置中的执行值 → `ExecutionSpec` 默认值”解析。`Orchestration` 的 `from_requests()` 类方法会把解析结果写入每个请求的 `ExecutionSpec`，使单请求与多请求路径保持一致。解析阶段还会拒绝未知编排字段，并校验 Benchmark、Harness 和 Environment ID。

`Orchestration` 包含有序的 `OrchestratedRun`；每个对象都保存稳定的编排键、声明序号、请求名称和完整的 `RunRequest`。单个请求的终态使用 `RequestOutcome` 表示，`OrchestrationResult` 按声明顺序保留所有请求结果。

## 任务与计划契约

Benchmark 按以下流程将数据集内容转换为 runtime 输入：

```text theme={"system"}
BaseBenchmark.load_tasks
  -> TaskSpec
  -> Planner.plan
  -> ExecutionPlan
  -> BaseBenchmark.prepare_task
  -> PreparedTask
```

| 契约              | 生成方                          | 必须表达的含义                                            |
| --------------- | ---------------------------- | -------------------------------------------------- |
| `TaskSpec`      | `BaseBenchmark.load_tasks`   | 稳定的 `task_id`、问题、类别、标准答案、元数据和可选的阶段策略提示             |
| `BenchmarkPlan` | `BaseBenchmark.build_plan`   | Benchmark 私有的逐任务准备与评测设置                            |
| `HarnessPlan`   | `BaseHarness.build_plan`     | 配置校验后的 Harness runtime 设置                          |
| `ExecutionPlan` | `Planner.plan` 与匹配的 Recipe   | 已解析的任务/评测 Environment、阶段策略、子计划、执行设置和已应用的 Recipe ID |
| `PreparedTask`  | `BaseBenchmark.prepare_task` | 面向 Harness 的输入、预期输出、参考答案、类别和元数据                    |

`PreparedTask.input` 是 `TaskInput`，包含提示词，以及可选的系统提示词、媒体、文件、工作区、工具和消息；`PreparedTask.output` 是 `TaskOutput`，包含预期答案与输出文件声明。数据集原始记录应保留在 `TaskSpec.metadata`，只有可执行材料才应放入 `PreparedTask`。

`ExecutionPlan` 表示一次任务尝试的已解析计划，并非整个任务共用的固定计划。执行时，`UnifiedEvaluationRuntime` 的 `_run_attempts` 方法会在语义尝试循环内、runtime 重试循环外调用 `Planner.plan`。因此，每次语义尝试都会重新构建计划，受 `max_retries` 限制的 runtime 重试则复用该次尝试的计划；Recipe 不能依赖上一次规划产生的副作用。具体源码位置与上下游调用链见[源码地图](/zh/developer_guide/architecture/source_map)。

每次规划依次执行以下步骤：

1. 解析评测 Environment 模式。
2. 解析基线、运行与评测阶段的网络策略输入。
3. 深拷贝请求的 `EnvironmentSpec`，得到任务局部配置。
4. 调用 `benchmark.build_plan` 创建 Benchmark 子计划。
5. 调用 `harness.build_plan`；无 Harness Benchmark 则创建基础 `HarnessPlan`。
6. 按注册表顺序应用每个允许且匹配的 Recipe。
7. 使用默认模式为 `public` 的 `NetworkPolicy()` 补齐缺失策略。
8. 根据最终评测模式创建或清除 `evaluation_environment`。

初始评测模式的优先级如下：

```text theme={"system"}
RunRequest.environment.evaluation_environment_mode
  > TaskSpec.evaluation_environment_mode
  > BaseBenchmark.resolve_evaluation_environment_mode(req)
```

每个阶段先采用请求中显式设置的网络策略；请求未设置时使用 `TaskSpec` 提示。匹配的 Recipe 随后可以转换该值，仍缺失时才补为 `public`。Recipe 必须保留兼容的用户显式设置。规划结束后，runtime 会调用 `_resolve_execution_plan_network_policies`，让选中的 provider 解析并校验其实际强制执行的策略；Environment 打开前只持久化脱敏后的审计视图。

编排试运行会解析配置、校验组件兼容性并打印完整请求，但不会加载任务或执行 `Planner.plan`。要检查逐任务计划，可读取 `run_info.json` 的 `resolved_execution_plans`：先按 `task_id` 定位任务，再进入 `attempts` 并选择尝试编号；也可以订阅 `execution_plan_resolved` 进度事件。持久化视图只保留 Environment ID、阶段策略、评测模式和已应用的 Recipe ID。如需增加调试信息，应向 `_resolved_execution_plan_payload` 增加安全字段，不能直接保存完整数据类。

## Recipe 规划

内置 Recipe 通过 `src/agentcompass/runtime/registry.py` 中的 `RECIPES` 注册。`src/agentcompass/runtime/recipes.py` 中的 `build_run_recipe_registry` 将这些条目复制到本次运行的注册表，再追加从受信任的 `RunMetadata.recipe_dirs` 目录中加载并校验的 Recipe 类。

`ExecutionSpec.enabled_recipes` 控制候选集合：

* 空列表表示考虑本次运行注册表中的全部 Recipe，再由 `matches` 选择适用项；
* 非空列表是 Recipe ID 白名单；
* 每个匹配的 Recipe 接收上一个 Recipe 返回的计划，其 ID 会追加到 `ExecutionPlan.applied_recipes`。

Planner 按注册表插入顺序迭代，不会对候选项排序。不要让相互重叠的 Recipe 依赖隐式顺序才能正确工作；两个适配必须组合时，应明确关系并测试组合后的计划。

`BaseRecipe` 提供两个方法：

```python theme={"system"}
def matches(self, req: RunRequest, task: TaskSpec, plan: ExecutionPlan) -> bool: ...

def apply(
    self,
    plan: ExecutionPlan,
    req: RunRequest,
    task: TaskSpec,
) -> ExecutionPlan: ...
```

`matches` 与 `apply` 在规划期间运行，不能打开 Environment、安装软件、调用 Model、修改任务文件或评测答案。`apply` 应返回复制后的计划，并保留兼容的用户显式值。可参考 `src/agentcompass/recipes/swebench_verified/` 下 `common.py` 中的 `clone_execution_plan`。

Recipe 只负责读取 `TaskSpec` 或 Benchmark 子计划中的稳定要求，调整计划里的 Environment 参数和 Benchmark/Harness 执行细节。Environment provider 负责 sandbox 创建与策略强制执行，Benchmark 负责评分。

## Environment 会话契约

`BaseEnvironment.open` 返回 `EnvironmentSession`。该会话提供异步命令执行、上传与下载、文本 I/O、目录传输、端点发现、文件检查和可选的动态网络切换；具体方法签名见 `src/agentcompass/runtime/base.py` 中的 `EnvironmentSession`。

命令参数的约束是明确的：`exec(..., shell=False)` 接受 `list[str]`，`exec(..., shell=True)` 接受字符串。各 provider 应保持 `ExecResult.returncode`、`stdout`、`stderr` 和 `timed_out` 的统一语义。Environment 的打开、复用和清理顺序见[执行、调度与清理](/zh/developer_guide/architecture/execution_lifecycle)。

## 兼容性与结果类型边界

`RunResult` 表示一次执行或评测尝试，不是请求级汇总。Harness 负责记录状态、答案、轨迹、产物、执行错误和诊断 `telemetry`；Benchmark 声明 `MetricContract`，其 `evaluate` 只把已声明观测写入 `RunResult.metrics`，并负责评测错误。runtime 会按 Contract 校验每次 attempt，应用选定的 strategy 和 reducer，再把 `MetricReport` 交给 `Benchmark.aggregate_metrics` 完成官方跨任务聚合。之后 runtime 把 attempts 整理为任务详情和请求摘要，Orchestrator 则用 `RequestOutcome` 与 `OrchestrationResult` 表示命名请求及整组编排的终态。

`TaskStatus.COMPLETED`、`RUN_ERROR`、`EVAL_ERROR` 和 `SKIPPED` 含义不同。`TaskStatus.ERROR` 序列化为 `run_error_or_eval_error`，表示无法进一步确定阶段的错误。规范化时不能把有效的 `score=0` 当作错误，也不能丢失错误阶段。各层的持久化结构见[结果与复用](/zh/developer_guide/architecture/results_and_reuse)。

修改共享契约时，应检查以下边界：

* runtime 数据类的构造、校验和公开导出；
* CLI、SDK 与编排解析生成请求和结果对象的位置；
* Benchmark、Harness、Environment、Recipe 和分析器对共享对象的生成与使用；
* `RunRequest.to_task_payload`、`to_persistence_params`、明细整理、脱敏和复用加载；
* 对已有结果目录进行分析与重新汇总时的反序列化。

共享 schema 的变更必须明确，并在生产者和持久化边界完成校验。不要把混合字段或旧的 attempt 指标字段静默转换成当前 Contract。
