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

# Recipe 集成

当 Benchmark 需要根据 Environment 为每个任务确定性地调整 `ExecutionPlan` 时，新增一个 Recipe。

Recipe 属于规划策略。它可以选择镜像、工作区、资源、网络设置或专用的 Benchmark/Harness 计划，但不能打开 sandbox、安装软件包、调用 Model 或 provider、执行任务或进行评分。应把这些副作用放在负责相应生命周期的组件中。

## 选择集成方式

| 方式          | 适用场景                     | 注册契约                                                         |
| ----------- | ------------------------ | ------------------------------------------------------------ |
| 内置 Recipe   | 随 AgentCompass 一同维护的公开行为 | 使用 `@RECIPES.register()` 装饰类，并从 `agentcompass.recipes` 导入其模块 |
| 可信外部 Recipe | 只为指定运行加载的团队专属策略          | 在软件包根模块通过非空 `RECIPE_CLASSES` 列表或元组导出具体类                      |

外部 Recipe 代码在 AgentCompass 进程中执行，不受任务 sandbox 隔离。只能加载经过审查且可信的软件包。

## 实现基础契约

每个 Recipe 都必须继承 `BaseRecipe`、支持无参数构造、具有唯一 `id`，并实现 `matches()` 和 `apply()`：

```python theme={"system"}
from copy import deepcopy

from agentcompass.runtime import BaseRecipe, ExecutionPlan, RunRequest, TaskSpec


class ExampleDockerRecipe(BaseRecipe):
    id = "example_docker"

    def matches(self, req: RunRequest, task: TaskSpec, plan: ExecutionPlan) -> bool:
        _ = task
        return req.benchmark.id == "example_exact_match" and plan.environment.id == "docker"

    def apply(
        self,
        plan: ExecutionPlan,
        req: RunRequest,
        task: TaskSpec,
    ) -> ExecutionPlan:
        _ = req, task
        updated = deepcopy(plan)
        params = updated.environment.params
        params["image"] = str(params.get("image") or "").strip() or "python:3.12-slim"
        params.setdefault("workspace", "/workspace")
        return updated
```

`matches(req, task, plan)` 只能判断 Recipe 是否适用。它接收的当前执行计划已经包含此前匹配 Recipe 所做的变更；该方法不能修改任何参数。

`apply(plan, req, task)` 必须返回新的 `ExecutionPlan`。修改嵌套的 Environment、Benchmark 或 Harness 计划字段前，应深拷贝传入的执行计划。必须保留兼容的用户显式值，通过 `setdefault()` 或等价的后备逻辑补齐缺失字段。显式值不兼容时，应报错并说明解决办法，不能静默替换。

这两个方法都属于确定性规划。不能在其中访问网络、写入文件、启动子进程、安装软件包、创建 sandbox、调用 Model 或产生其他外部可见副作用。

## 注册内置 Recipe

将公开实现放在 `src/agentcompass/recipes/` 下，然后注册：

```python theme={"system"}
from agentcompass.runtime import RECIPES


@RECIPES.register()
class ExampleDockerRecipe(BaseRecipe):
    ...
```

在各级 `__init__.py` 中导入该模块，确保导入 `agentcompass.recipes` 时会执行装饰器。注册表以 `id` 为键并拒绝重复 ID。provider 专属适配应放在 Recipe 中，不能把 Environment 机制移入 Benchmark。

内置 Recipe 只能面向公开 provider 和公开基础设施。组织专属部署策略应放在可信外部软件包中。

## 打包可信外部 Recipe

外部 Recipe 目录必须是 Python 软件包，不能只是单个 Python 文件：

```text theme={"system"}
company_recipes/
├── __init__.py
└── docker_recipe.py
```

定义类时不要使用进程级 `RECIPES` 注册表装饰它：

```python theme={"system"}
# company_recipes/docker_recipe.py
from copy import deepcopy

from agentcompass import BaseRecipe, ExecutionPlan, RunRequest, TaskSpec


class CompanyDockerRecipe(BaseRecipe):
    id = "company_docker"

    def matches(self, req: RunRequest, task: TaskSpec, plan: ExecutionPlan) -> bool:
        _ = task
        return req.benchmark.id == "example_exact_match" and plan.environment.id == "docker"

    def apply(self, plan: ExecutionPlan, req: RunRequest, task: TaskSpec) -> ExecutionPlan:
        _ = req, task
        updated = deepcopy(plan)
        params = updated.environment.params
        params["image"] = str(params.get("image") or "").strip() or "python:3.12-slim"
        params.setdefault("workspace", "/workspace")
        return updated
```

再从软件包根模块导出同一个类：

```python theme={"system"}
# company_recipes/__init__.py
from .docker_recipe import CompanyDockerRecipe

RECIPE_CLASSES = (CompanyDockerRecipe,)
```

加载器要求同时满足以下条件：

* 目录存在且包含 `__init__.py`；
* `RECIPE_CLASSES` 是非空列表或元组；
* 每一项都是具体的 `BaseRecipe` 子类，并具有非空且唯一的 `id`；
* 每个类都支持无参数构造。

相对目录从当前工作目录解析。AgentCompass 会规范化路径并去重，先复制内置注册表作为本次运行的注册表，再追加外部类。如果 ID 重复，注册阶段就会报错，与内置 Recipe 冲突也不例外。

完成 Benchmark 示例和 [Harness 实现教程](/zh/developer_guide/extensions/harness/code_implementation)中的 `example_exact_match` 与 `example_answer` 后，运行对应的确定性任务，同时加载该 Recipe 并将其加入允许列表：

```bash theme={"system"}
uv run agentcompass run example_exact_match example_answer unused-model \
  --env docker \
  --benchmark-params '{"sample_ids":["capital-france"]}' \
  --harness-params '{"answer":"Paris"}' \
  --recipe-dir ./company_recipes \
  --recipe company_docker \
  --task-concurrency 1 \
  --no-enable-analysis
```

`--recipe` 是允许列表，不是强制执行开关；Recipe 仍需让 `matches()` 返回 `True`。CLI、SDK、配置文件和编排的对应方式见 [Recipe](/zh/user_guide/other_features/recipes#可信外部-recipe)。

## 理解应用顺序

当前规划器会为每次任务尝试构建默认执行计划，然后按插入顺序遍历本次运行的 Recipe 注册表：

1. 如果 `execution.enabled_recipes` 非空，跳过注册 ID 不在允许列表中的条目。
2. 无参数构造 Recipe。
3. 使用当前已生成的执行计划调用 `matches()`。
4. 匹配时，将当前执行计划替换为 `apply()` 的返回值，并在 `applied_recipes` 中记录 Recipe `id`。
5. 继续处理下一个注册项；它可以检查更新后的执行计划。

内置 Recipe 保持注册时的插入顺序。外部类追加在内置项之后，先按 `runtime.recipe_dirs` 的顺序，再按各软件包中 `RECIPE_CLASSES` 的顺序处理。所有匹配 Recipe 都会应用；规划器不会自动解决重叠写入。

`BaseRecipe` 当前声明了 `priority` 和 `enabled_by_default`，但规划器不会读取这两个属性。不能声称 `priority` 会改变顺序，也不能把其中任一属性当作启用机制。Recipe 是否参与由注册状态、`execution.enabled_recipes` 和 `matches()` 共同决定。

注册顺序是当前执行语义，但不能代替清晰的职责边界。应避免多个 Recipe 写入相同字段，也不要让正确性依赖无关模块的导入顺序。

## 验证集成

首先确认软件包能加载且 ID 存在。当前没有 `agentcompass list recipe` 命令，因此外部软件包需要直接检查本次运行的注册表：

```bash theme={"system"}
uv run python -c 'from agentcompass.runtime.recipes import build_run_recipe_registry; print(build_run_recipe_registry(["./company_recipes"]).names())'
```

然后使用 `--task-concurrency 1`、`--max-retries 0` 和 `DEBUG` 日志运行一个已知任务，并验证：

* 对无关 Benchmark 或 Environment，`matches()` 返回 `False`；
* `run_info.json` 的 `resolved_execution_plans` 中，相应任务尝试的记录包含预期 ID；终端输出顶层的 `applied_recipes` 列表也包含该 ID；
* 每次保存的任务尝试都对应一份包含预期值的解析后执行计划；
* Recipe 应用后，兼容的显式镜像、工作区、资源或网络值保持不变；
* 所选 Environment 能根据调整后的执行计划构建配置，并在成功和失败后都完成清理。

如果两个 Recipe 可能同时匹配，应验证两种组合，或重新划分职责以消除重叠。PR 所需的代码仓库检查和单任务证据见[测试与验证](/zh/developer_guide/contributing/testing)。

## 完成检查表

* 该行为属于确定性的逐任务规划，而不属于 Benchmark、Harness、Environment 或 runtime 机制。
* `matches()` 和 `apply()` 的结果确定，且不会产生副作用。
* `apply()` 返回复制后的执行计划，并保留用户显式意图。
* Recipe ID 唯一，并能通过正确的内置注册路径或 `RECIPE_CLASSES` 加载。
* 已验证匹配、不匹配、显式覆盖、解析后的执行计划和清理行为。
* 已用中英文记录面向用户的行为和支持组合。
