> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 评估套件

> AgentEye 评估套件文档。

AgentEye 通过向**客户自有的评估服务**发送 POST 请求，将完整的事件记录提交，以对已完成的 agent 会话进行评分。评估服务可直接返回评分结果，或返回一个 `job_id` 供 AgentEye 轮询。评分结果将被存储并展示在仪表盘中。

本文档涵盖以下内容：

1. 会话完成的检测方式。
2. 评估服务必须实现的 HTTP 协议规范。
3. AgentEye 服务器的配置方法。
4. 查看评估结果。
5. 故障排查。

如需使用已实现上述协议规范的 Python 辅助库，请参阅
[PyPI 上的 `agenteye-evaluator` 包](https://pypi.org/project/agenteye-evaluator/)。

***

## 工作原理

```text theme={null}
ingest /events  ──▶  AgentEye  ──── POST /evaluate ────▶  评估服务
   (agent_end)        server   ◀──── done | pending ────
                          │
                          │     GET /evaluate/{job_id} ─────▶
                          │     ◀──── done ──────────────
                          ▼
                     evaluations  (终态结果)
```

当 AgentEye SDK 为某个会话发出 `agent_end` 事件时，服务器会调度一次评估任务，并将完整的事件记录以 POST 请求发送至评估服务。评估服务可以：

* **直接返回结果**，格式为 `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`。结果将追加至该会话的评估时间线中。`reasoning` 和 `summary` 为可选字段。
* **延迟处理**，返回 `{"status":"pending", "job_id":"abc-123"}`。AgentEye 随后会调用 `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123`，直至评估服务返回 `{"status":"done", ...}` 或 `{"status":"error", "error":"..."}`。

  轮询频率以单个任务为单位：`pending` 响应中可包含 `next_poll_secs` 来覆盖默认值；否则 AgentEye 使用 `GET /config` 中的 `default_poll_interval_secs`；再次兜底则使用服务器的 `EVALUATOR_POLLING_INTERVAL_SECS`（默认 10 秒）。所有值均限定在 \[1s, 1h] 范围内。

对于从未发出 `agent_end` 事件的会话（例如 agent 进程崩溃），同样可以触发评估：评估服务的 `GET /config` 可返回 `{"inactivity_timeout_secs": 1800}`，AgentEye 将对闲置时间超过该值的会话发起评估。将该字段设为 `null` 或省略可禁用此兜底机制。

若未设置 `EVALUATOR_ENDPOINT`，整个评估管道将完全空操作。

一个会话可以随时间积累**多个终态评估结果**：每个 `agent_end` 事件（以及每次从仪表盘手动触发的重新评估）都会追加一条新的评估记录。这是评估已恢复对话的标准方式：用户结束 agent 后，稍后返回继续发送事件，再次结束 agent，第二次评估将针对更新后的完整记录运行。仪表盘将最新一次评估作为主要显示内容，历史评估以可折叠时间线的形式呈现。当某会话有评估正在运行时，该会话的后续 `agent_end` 事件将被忽略；等当前评估完成后，下一个 `agent_end` 事件才会正常入队新的评估任务。

闲置兜底机制在已恢复的会话中同样生效：如果在已有终态评估的情况下又有新事件到来，且会话随后闲置超过 `inactivity_timeout_secs`，则会触发新的评估任务入队。

瞬时错误（5xx、429、超时、网络错误）将以指数退避方式重试，最多重试 `EVALUATOR_MAX_ATTEMPTS` 次；4xx 响应为终态错误。AgentEye 支持多实例水平扩展，任务会分区处理，同一会话不会被并发派发两次。

***

## HTTP 协议规范

所有需要认证的路由均使用 **Bearer Token 认证**，双方必须配置相同的令牌值：

* AgentEye 服务器：环境变量 `EVALUATOR_TOKEN`
* 评估服务：以相同方式配置（`agenteye-evaluator` SDK 按惯例读取 `EVALUATOR_TOKEN`）

若未设置 `EVALUATOR_TOKEN`，服务器发送请求时不携带 `Authorization` 头；评估服务可选择接受匿名请求，这在纯内部网络环境下可行，但不建议在公网上使用。

### 评估服务必须实现的路由

| 路由                   | 请求体/参数             | 响应                                                                                           |
| -------------------- | ------------------ | -------------------------------------------------------------------------------------------- |
| `GET /health`        | 无                  | `{"status":"ok"}`（开放，无需认证）                                                                   |
| `GET /config`        | 无                  | `{"inactivity_timeout_secs": <int> \| null, "default_poll_interval_secs": <int> \| omitted}` |
| `POST /evaluate`     | `EvalRequest` JSON | `{"status":"done", ...}` 或 `{"status":"pending", "job_id":"..."}`                            |
| `GET /evaluate/{id}` | 无                  | 与 `/evaluate` 相同的响应结构                                                                        |

### 服务器发送的 `EvalRequest` 请求体

```json theme={null}
{
  "schema_version": "1",
  "session_id":     "session-abc123",
  "agent_id":       "planner",
  "environment":    "production",
  "started_at":     "2026-05-10T12:00:00Z",
  "ended_at":       "2026-05-10T12:05:00Z",
  "events": [
    { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } },
    ...
  ]
}
```

### 响应格式

**同步（直接返回结果）：**

```json theme={null}
{
  "status": "done",
  "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 },
  "reasoning": {
    "helpfulness": "answered the question directly with citations",
    "tool_efficiency": "called list_files three times when one would have done"
  },
  "summary": "strong answer quality, weak tool selection"
}
```

`reasoning`（每个评分维度的解释说明映射）和 `summary`（整体总结段落）均为可选字段。`reasoning` 中的键应与 `scores` 中的键对应；仪表盘会在每个评分条下方渲染对应的解释内容。只返回 `scores` 的旧版评估服务无需修改仍可正常使用；`reasoning` 和 `summary` 字段在缺失时读取为 null，对应的界面元素将不显示。

**异步（延迟处理）：**

```json theme={null}
{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 }
```

`next_poll_secs` 为可选字段；若省略，服务器将依次回退至评估服务 `/config` 中的 `default_poll_interval_secs`，再回退至自身的 `EVALUATOR_POLLING_INTERVAL_SECS` 环境变量。

**评估服务侧终态错误：**

```json theme={null}
{ "status": "error", "error": "model service unavailable" }
```

服务器将任何其他 2xx 响应体视为协议错误，并为该会话记录终态 `error`。

***

## 使用 SDK 编写评估服务

`agenteye-evaluator` Python 包提供了一个带类型的 FastAPI 封装，已实现上述 HTTP 协议规范。从 PyPI 安装：

```bash theme={null}
pip install agenteye-evaluator
```

最简评估服务示例：

```python theme={null}
import os
from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse

app = Evaluator(token=os.environ["EVALUATOR_TOKEN"])

@app.evaluator
def run(req: EvalRequest) -> EvalResponse:
    # 检查 req.events（完整的会话记录）并返回评分。
    tool_calls = sum(1 for e in req.events if e.event_type == "tool_use")
    return EvalResponse(
        scores={"tool_calls": float(tool_calls)},
        reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"},
        summary="tight tool loop" if tool_calls < 5 else "agent looped on tools",
    )
```

`app` 实例为 ASGI 可调用对象，使用 `uvicorn module:app` 即可运行。

对于需要延迟处理耗时任务的评估服务，可返回 `JobPending` 并注册 `@app.job_lookup` 处理函数；AgentEye 服务器将轮询 `GET /evaluate/{job_id}`，直至返回终态状态或达到 `EVALUATOR_MAX_POLL_DURATION_SECS` 上限（默认 1 小时）。

完整 API 参考文档、异步模式说明及事件 schema 请参阅 `agenteye-evaluator` 的 README，该文件随每个发布包附带于
[agenteye-enterprise releases 页面](https://github.com/agenteye-enterprise/releases)，也可在该包的 PyPI 页面查阅。

***

## 在 Kubernetes 上运行评估服务

评估服务是**您自己的服务**：AgentEye 不提供默认的评估服务容器。发布包中包含 `deploy/examples/evaluator/` 目录下的 Kubernetes 参考清单，替换镜像地址和共享 Bearer Token 后即可直接应用。

### 1. 将评估服务容器化

评估服务的最简 Dockerfile：

```dockerfile theme={null}
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir agenteye-evaluator uvicorn
COPY my_evaluator.py .
RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \
    && chown -R evaluator:evaluator /app
USER evaluator
EXPOSE 9000
CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"]
```

设置 `runAsNonRoot`（UID 10001）可使容器兼容 Pod Security 受限配置文件。

### 2. 创建共享 Bearer Token

```bash theme={null}
kubectl -n agenteye create secret generic evaluator-token \
  --from-literal=token="$(openssl rand -hex 32)"
```

该值需与 AgentEye 服务器上的 `EVALUATOR_TOKEN` 保持一致。服务器每次请求均会发送 `Authorization: Bearer <token>`；SDK 使用 `hmac.compare_digest` 进行常量时间校验，不匹配时返回 HTTP 401。

### 3. 应用示例清单

```bash theme={null}
# 先编辑 deploy/examples/evaluator/deployment.yaml，
# 将 `image:` 指向您的镜像仓库，然后执行：
kubectl apply -k deploy/examples/evaluator/
```

示例清单包含：

* 2 副本的 Deployment，配置了 `runAsNonRoot`、只读根文件系统、删除所有 capabilities，以及基于 `/health` 的存活探针和就绪探针
* 端口 9000 的 ClusterIP Service
* `secret.example.yaml` 模板（已从 Kustomization 中排除，请通过带外方式创建真实 Secret，避免令牌提交到 git）

### 4. 将 AgentEye 连接到评估服务

在 AgentEye 服务器上设置：

```bash theme={null}
EVALUATOR_ENDPOINT=http://evaluator:9000
EVALUATOR_TOKEN=<上面生成的值>
```

服务器会向所有评估服务 Pod 并发发送 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` 个请求（默认值：`2 × 4 = 8`）。请根据这些服务端参数同步调整 `replicas` 和每个 Pod 的资源限制。

### 验证

```bash theme={null}
kubectl -n agenteye port-forward svc/evaluator 9000:9000
curl -s http://localhost:9000/health   # → {"status":"ok"}
```

在 agent 完整运行一次后，AgentEye 服务器上的 `GET /evaluations` 应返回一条 `status: "done"` 的记录，其中包含评估服务产生的评分。

***

## 配置 AgentEye 服务器

在服务器进程上设置以下环境变量：

| 环境变量                               | 说明                                                                                                       |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `EVALUATOR_ENDPOINT`               | 评估服务的基础 URL（如 `http://evaluator:9000`）。未设置时评估管道禁用。                                                       |
| `EVALUATOR_TOKEN`                  | Bearer Token，必须与评估服务配置的值完全一致。                                                                            |
| `EVALUATOR_WORKERS`                | 每个服务器实例的工作任务数（默认 2）。                                                                                     |
| `EVALUATOR_CLAIM_BATCH`            | 每次工作节拍认领的任务行数（默认 4）。批次内任务**并发**处理；对评估服务端点的实际并发数为 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`。            |
| `EVALUATOR_POLL_IDLE_SECS`         | 无待评估任务时，工作线程在两次派发尝试之间的休眠时长（默认 2 秒）。                                                                      |
| `EVALUATOR_POLLING_INTERVAL_SECS`  | 当单次响应中无 `next_poll_secs` 且评估服务也未设置 `default_poll_interval_secs` 时，`GET /evaluate/{id}` 的兜底轮询间隔（默认 10 秒）。 |
| `EVALUATOR_REQUEST_TIMEOUT_MS`     | 单次请求超时时间（默认 30000 毫秒）。                                                                                   |
| `EVALUATOR_MAX_ATTEMPTS`           | 瞬时错误累计达到此次数后，结果记录为终态 `error`（默认 5 次）。                                                                    |
| `EVALUATOR_CONFIG_REFRESH_SECS`    | `GET /config` 的刷新间隔（默认 300 秒）。                                                                           |
| `EVALUATOR_MAX_POLL_DURATION_SECS` | 会话在轮询队列中可停留的最长挂钟时间，超出后记录为 `timeout`（默认 3600 秒）。防止评估服务持续返回 `pending` 的情况。                                 |

若要为整个实例启用自动评分，请创建包含上述两个键的 `agenteye-evaluator` Secret。在附带的 Kubernetes 清单中，服务器从该可选 Secret 中读取 `EVALUATOR_ENDPOINT` 和 `EVALUATOR_TOKEN`。请通过组织的标准密钥管理流程创建该 Secret，然后重启服务器 Deployment 使配置生效。

上述调优参数默认不在 Deployment 清单中配置；如需覆盖默认值，请在服务器容器的 Deployment 清单中显式添加对应的环境变量。

完整环境变量列表请参阅 [deployment.md](/zh/agenteye/deployment)。

***

## API 参考

| 方法     | 路径                                  | 所需权限                  | 用途                                                                                                                                                                                                                                                                                                                                                                                                                   |
| ------ | ----------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/evaluations`                      | `evaluations:read`    | 查询终态结果。支持以下过滤参数：`session_id`、`agent_id`、`environment`、`status`（`done`/`error`/`timeout`）、`ts_from`、`ts_to`、`cursor`、`limit`、`score_filters`、`latest_per_session`。`limit` 默认为 50，上限为 200（注意与 `/events` 不同，后者上限为 1000）。`environment` 支持逗号分隔的多值列表（如 `environment=prod,staging`）；单个值仍然有效。使用 `latest_per_session=true` 时，响应中每个 `session_id` 最多返回一条记录（按 `completed_at` 取最新），供会话列表页面将会话的评估时间线折叠为当前主要结果。默认为 false（返回完整历史记录）。 |
| `GET`  | `/evaluations/aggregate`            | `evaluations:read`    | 对过滤后的数据集进行汇总统计：总数、done/error/timeout 分布、各评分键的统计指标（在任意 `scores` 键上计算 count/avg/min/max/p50）以及按时间分桶的趋势数据。接受与 `/evaluations` 相同的过滤参数，另外支持 `featured_keys`（评分键的 CSV 列表，用于趋势展示）和 `latest_per_session`。为仪表盘功能提供数据支持；指标在整个匹配数据集上精确计算，不进行采样。                                                                                                                                                                                 |
| `GET`  | `/evaluations/environments`         | `evaluations:read`    | 返回 `evaluations` 表中所有不同的 environment 值，用于填充评估数据范围内的过滤下拉框。                                                                                                                                                                                                                                                                                                                                                            |
| `GET`  | `/evaluation-jobs`                  | `evaluations:read`    | 查看进行中的评估任务。可按 `status`（`pending`/`polling`）过滤。                                                                                                                                                                                                                                                                                                                                                                       |
| `GET`  | `/events`                           | `events:read`         | 流式获取会话的原始事件。支持以下参数：`session_id`、`agent_id`、`event_type`（CSV）、`environment`（CSV）、`ts_from`、`ts_to`、`cursor`、`limit`、`order`。`order` 为 `desc`（最新优先，默认）或 `asc`（最旧优先）；不识别的值回退为 `desc`。通过响应中的 `next_cursor`（事件 id）进行游标分页：将其作为 `cursor` 传入可获取下一页；`asc` 模式下返回该 id 之后的事件，`desc` 模式下返回该 id 之前的事件。`limit` 默认为 50，上限为 1000。                                                                                                     |
| `GET`  | `/sessions/:session_id/export`      | `events:read`         | 返回评估服务针对该会话所接收的完整 JSON 请求体，以名为 `session-<id>.json` 的可下载附件形式提供。适用于将生产环境会话通过 `agenteye-evaluator` 进行离线回放测试。返回的字节与评估管道实际发送的内容完全一致。                                                                                                                                                                                                                                                                                      |
| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | 为会话入队一次新的评估任务；无论之前是否已有评估结果均可触发。新结果将**追加**至会话的评估时间线，而非覆盖之前的结果，历史评分仍可查看。入队成功返回 `202`，会话不存在返回 `404`，已有评估任务进行中返回 `409`。适用于部署新评估服务后的重新评估，或对从未发出 `agent_end` 的会话进行手动评估。                                                                                                                                                                                                                                                    |

### 按分数范围过滤：`score_filters`

`GET /evaluations` 接受可选的 `score_filters` 参数，可根据 `scores` 对象中的数值进行精确筛选。该参数为逗号分隔的 `key:min..max` 条目列表；上下界均可省略。多个条目以逻辑与（AND）方式组合。指定键不存在或值非数字的记录将被排除。单次请求最多支持 20 个过滤条目，超出时返回 HTTP 400。

示例：

```text theme={null}
# helpfulness 在 [0.5, 0.8] 范围内
GET /evaluations?score_filters=helpfulness:0.5..0.8

# tool_efficiency 不超过 0.3（无下界）
GET /evaluations?score_filters=tool_efficiency:..0.3

# helpfulness >= 0.5 且 factuality >= 0.9
GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9..
```

每个 `/evaluations` 响应对象包含以下字段：

| 字段              | 类型                    | 说明                                                       |
| --------------- | --------------------- | -------------------------------------------------------- |
| `evaluation_id` | string (UUID)         | 本次终态评估的规范标识符。每次终态评估生成一个新的 UUID；单个会话可包含多个。                |
| `id`            | string (UUID)         | 向后兼容别名，值与 `evaluation_id` 相同。                            |
| `session_id`    | string                | 本次评估所对应的会话。一个会话在时间线中可有多次评估记录。                            |
| `agent_id`      | string                | 产生该会话的 agent 标识。                                         |
| `environment`   | string                | 从会话复制的环境标签。                                              |
| `status`        | enum                  | `"done"`、`"error"`、`"timeout"` 之一。                       |
| `scores`        | object \| null        | 评估服务返回的评分。                                               |
| `reasoning`     | object \| null        | 评估服务返回的可选评分维度解释映射，键通常与 `scores` 中的键对应。仪表盘在每个评分条下方渲染对应内容。 |
| `summary`       | string \| null        | 评估服务返回的可选整体总结段落。仪表盘在各评分细目上方将其作为评估结果的主标题显示。               |
| `error`         | string \| null        | 仅在 `"error"` / `"timeout"` 状态时填充。                        |
| `attempt_count` | integer               | 派发尝试次数（≥ 1）。                                             |
| `duration_ms`   | integer \| null       | 最后一次尝试的耗时。                                               |
| `completed_at`  | string (ISO 8601 UTC) | 终态结果记录的时间。结果按 `completed_at` 降序排列（最新在前）。                 |
| `created_at`    | string (ISO 8601 UTC) | 与 `completed_at` 时间戳相同（一次性写入语义）。                         |

***

## 权限

| 权限                    | 授权范围                                                                 |
| --------------------- | -------------------------------------------------------------------- |
| `evaluations:read`    | 查看评估结果、在仪表盘中查看评分、加载仪表盘健康指标。                                          |
| `evaluations:trigger` | 通过 `POST /sessions/:session_id/re-evaluate` 或仪表盘的重新评估按钮，手动为会话入队评估任务。 |
| `dashboards:read`     | 查看已保存的仪表盘（同时需要 `evaluations:read` 权限才能加载指标数据）。                       |
| `dashboards:write`    | 创建和编辑仪表盘。                                                            |
| `dashboards:delete`   | 删除仪表盘。                                                               |

引导管理员（`ADMIN_KEY`、`ADMIN_EMAIL`）自动获得上述所有权限。

***

## 查看结果

* **`/sessions/<id>`**：事件时间线 + 右侧面板，显示会话评分及派发尝试中的错误信息。若您的密钥具有 `evaluations:trigger` 权限，导出按钮旁将出现**重新评估**按钮，适用于从未发出 `agent_end` 的会话，或在部署新评估服务后刷新评分。仪表盘会轮询新结果，在结果返回时更新右侧面板。
* **`/sessions`**：可过滤的会话列表；评分列一目了然地显示每个会话的评估状态和评分。
* **`/dashboards`**：已保存的评估健康视图（详见下方[仪表盘](#dashboards)章节）。

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/sessions-list.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=10de161665eef64465d3d100e80b643f" alt="会话列表，显示每个会话的评估状态标签和颜色编码的评分徽章（helpfulness、factuality、tool_efficiency、safety、coherence）" width="2880" height="1800" data-path="agenteye/images/sessions-list.png" />

*会话列表一目了然地展示每次运行的评估状态和评分；红/黄/绿徽章使低分一眼可辨。*

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/session-detail.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=63cc2480e8124a05ea6a0a92d5f20690" alt="会话详情页，右侧面板显示评估评分和派发状态" width="2880" height="1800" data-path="agenteye/images/session-detail.png" />

*打开会话后，完整时间线与评估评分及派发器错误信息同时显示在右侧面板中。*

***

## 仪表盘

**仪表盘**页面（`/dashboards`）允许您将评估过滤条件组合保存为具名可复用视图，一目了然地监控该评估数据切片的整体状况。仪表盘在**整个组织内共享**，所有具有 `dashboards:read` 权限的用户可看到相同的内容。

每个仪表盘固定以下配置：

* **过滤条件**：与会话页面相同的控件，包括环境、状态、agent、滚动时间窗口和分数范围过滤器（`key:min..max`）。
* **展示配置**：选择要展示的评分键、绿/黄/红健康阈值、显示哪些面板，以及是否折叠为每个会话的最新评估结果。

每张卡片显示匹配的会话数、done/error/timeout 分布、各展示评分的平均值，以及一个小型趋势迷你图。打开仪表盘后可查看完整大图面板；点击**在会话页面打开**可跳转至会话页面并预置对应的过滤条件。指标通过 `GET /evaluations/aggregate` 在服务端对全量匹配数据集精确计算，结果不进行采样。

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/dashboard-quality.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=0cbe5452995b2ff187f72b8978716bb3" alt="评估健康仪表盘，包含各评估维度的平均分条形图、工具成功/失败分布、热门工具列表及每小时事件量趋势" width="2880" height="1800" data-path="agenteye/images/dashboard-quality.png" />

**权限说明：** 查看需要同时具备 `dashboards:read` 和 `evaluations:read`；创建和编辑需要 `dashboards:write`；删除需要 `dashboards:delete`。引导管理员自动获得所有上述权限。

***

## 故障排查

**会话已存在但未生成任何评估结果。** 请确认 `EVALUATOR_ENDPOINT` 已在服务器进程上设置，服务器与评估服务使用相同的 `EVALUATOR_TOKEN` 值，且评估服务的 `/health` 端点可从服务器正常访问。未设置 `EVALUATOR_ENDPOINT` 时评估管道为空操作。

**进行中的评估任务大量积压。** 通过 `GET /evaluation-jobs` 查看进行中的任务队列。检查每条记录上的 `attempt_count`、`next_attempt_at` 和 `last_error`。常见原因：评估服务不可达或持续返回 5xx（将以退避方式重试）、`EVALUATOR_TOKEN` 错误（401 为终态错误），或异步评估服务持续返回 `pending`（见下文）。

**会话已完成但无终态评估结果。** 执行 `GET /evaluation-jobs?status=polling` 查询；任务可能仍在进行中。若任务卡在 `pending` 状态，说明服务器无法正常访问评估服务；请检查评估服务是否正常运行以及 `EVALUATOR_TOKEN` 是否匹配。

**`HTTP 401 from evaluator: invalid bearer token`。** 服务器上的 `EVALUATOR_TOKEN` 与评估服务配置的值不一致，两者必须完全相同。

**异步评估服务持续返回 `pending`。** 服务器将持续轮询 `GET /evaluate/{job_id}`，直至评估服务返回 `done` 或 `error`，或达到 `EVALUATOR_MAX_POLL_DURATION_SECS` 上限（默认 1 小时）。超过上限后，评估结果记录为 `timeout` 并从进行中队列中移除。若您的评估服务合理地需要超过默认时长，请适当增大 `EVALUATOR_MAX_POLL_DURATION_SECS`。
