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

# 结果与聚合

`RunResult` 应同时记录执行状态和 Benchmark 判定；所有任务完成后，再将任务级结果汇总为合法的 `MetricResult`。

## 不要混淆状态与分数

| 情况                       | `status`     | `correct`        | `score`     | `error` |
| ------------------------ | ------------ | ---------------- | ----------- | ------- |
| 执行和评测成功，答案正确             | `COMPLETED`  | `True`           | 官方分数        | 空       |
| 执行和评测成功，答案错误或合法零分        | `COMPLETED`  | `False` 或官方定义值   | `0.0` 或官方零分 | 空       |
| Harness 或 Benchmark 执行失败 | `RUN_ERROR`  | `False` 或 `None` | 通常为 `None`  | 执行错误    |
| 执行成功，但验证器崩溃、超时或输出无效      | `EVAL_ERROR` | `False` 或 `None` | 通常为 `None`  | 评测错误    |
| 执行和评测都失败                 | `ERROR`      | `False` 或 `None` | 通常为 `None`  | 两类错误    |

测试没有通过不一定是 `EVAL_ERROR`。例如验证器约定退出码 `1` 表示合法测试失败时，它是一个正常零分；只有验证器无法完成评分时才是评测错误。必须以固定版本的官方验证器契约为准。

## 保留已有执行结果

评测时优先使用 `dataclasses.replace()`，以免遗漏 Harness 已写入的轨迹、产物、Model 输出或 `meta`：

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

from agentcompass.runtime import RunResult, TaskStatus


def apply_verifier_result(result: RunResult, verifier) -> RunResult:
    eval_error = (
        verifier.timed_out or verifier.returncode not in {0, 1}
    )
    if eval_error:
        detail = (verifier.stderr or verifier.stdout).strip()
        status = (
            TaskStatus.ERROR
            if result.status == TaskStatus.RUN_ERROR
            else TaskStatus.EVAL_ERROR
        )
        error = "\n".join(
            part for part in [result.error, detail] if part
        )
        return replace(
            result,
            status=status,
            correct=False,
            score=None,
            error=error or "verifier failed",
        )

    if result.status != TaskStatus.COMPLETED or result.error:
        return replace(result, correct=False, score=None)

    passed = verifier.returncode == 0
    return replace(
        result,
        correct=passed,
        score=1.0 if passed else 0.0,
        metrics={**result.metrics, "pass": float(passed)},
    )
```

不要为了让聚合继续运行而把错误状态改成 `COMPLETED`，也不要用非空 `error` 表示普通错误答案。评测证据过大时，应保存截断后的摘要或文件产物，避免在多个字段中重复写入完整的验证器日志。

## 使用默认二元聚合

`BaseBenchmark.aggregate_metrics()` 默认调用 `aggregate_binary_metrics()`，适合每次尝试都给出布尔 `correct` 的 Benchmark。它生成 `accuracy`，并根据配置处理类别、`k` 以及 `avg@k` 或 `pass@k`。

普通二元 Benchmark 不需要覆盖该方法：

```python theme={"system"}
class ExampleExactMatchBenchmark(BaseBenchmark):
    # load_tasks(), prepare_task(), evaluate() ...
    pass
```

默认聚合读取持久化后的结果字典，而不是内存中的 `RunResult` 对象。自定义实现不要假定字段总在顶层；包含多次尝试的结果可能位于 `result["attempts"]` 中。

## 聚合连续分数

如果官方主指标是连续值，请使用共享辅助函数，并明确指标名称和缺失分数的处理方式：

```python theme={"system"}
from typing import Any

from agentcompass.runtime import RunRequest
from agentcompass.runtime.metrics import MetricResult, aggregate_score_metrics


def aggregate_metrics(
    self,
    results: list[dict[str, Any]],
    req: RunRequest,
    config: Any,
) -> MetricResult:
    _ = req
    return aggregate_score_metrics(
        results,
        metric_name="mean_reward",
        score_key="score",
        missing_score_value=0.0,
        config=config,
    )
```

`missing_score_value=0.0` 会把缺失分数计为零。如果官方规则排除基础设施错误或使用不同分母，就不能直接采用这个默认值；应先按官方规则选择尝试和分母，再构造 `MetricResult`，并在 `counts` 中保留总数、已评测数和错误数。

## 合并多个主指标

如果需要同时报告准确率和平均分，可以组合多个共享辅助函数：

```python theme={"system"}
from agentcompass.runtime.metrics import (
    aggregate_binary_metrics,
    aggregate_score_metrics,
    merge_metric_results,
)


def aggregate_metrics(self, results, req, config):
    _ = req
    accuracy = aggregate_binary_metrics(results, config=config)
    reward = aggregate_score_metrics(
        results,
        metric_name="mean_reward",
        config=config,
    )
    return merge_metric_results(accuracy, reward)
```

只有两个聚合使用相同的任务集合和分母时，才能直接合并。如果涉及类别加权、分层类别、不同的尝试选择规则或多个官方分母，应显式实现相应逻辑，并在 `details` 中说明。

## `MetricResult` 的最低要求

自定义聚合必须返回 `MetricResult`：

| 字段                 | 要求                          |
| ------------------ | --------------------------- |
| `metrics`          | 至少一个名称非空、数值有限的主指标           |
| `counts.total`     | 进入本次聚合的任务总数                 |
| `counts.evaluated` | 成功得到官方分数的任务数，且不得超过 `total`  |
| `counts.error`     | 包含执行或评测错误的任务数，且不得超过 `total` |
| `details`          | 可选的类别、层级或子指标结构              |
| `extra`            | 可选的数据集版本、评测器版本等复现信息         |

自定义逻辑应通过 `attempt_payload()` 读取尝试数据，并返回新的字典或结果，避免直接修改 runtime 传入的持久化结构。共享辅助函数的实现位于 [`runtime/metrics`](https://github.com/open-compass/AgentCompass/tree/main/src/agentcompass/runtime/metrics)。

## 聚合前检查

* 正确答案、错误答案、合法零分、执行失败和评测失败分别生成预期状态。
* `correct`、`score` 与官方主指标含义一致，不用 `score == 0` 推断评测器崩溃。
* 多次尝试的选择规则、`k` 语义和失败分母与官方实现一致。
* 类别汇总不会丢失无分数任务或把一个任务重复计入多个互斥类别。
* `MetricResult` 可以序列化，所有指标为有限数字，计数满足边界约束。
