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

# 通过制与计分制评估

> 用 defineEval 与 defineScoreEval 编写通过制和计分制评估，调用即登记 Assertion。

[NiceEval](https://niceeval.com/) 提供两种评估题型。`defineEval` 回答一次运行是否满足要求，默认报告读通过率；`defineScoreEval` 回答完成了多少，默认报告读累计分数。两种题型都调用即登记 Assertion，handle 只配置同一条 entry。

## 必须做到的事用 `defineEval`

```ts theme={null}
import { defineEval } from "niceeval";
import { commandSucceeded, includes } from "niceeval/expect";

export default defineEval({
  async test(t) {
    const turn = await t.send("修复测试并说明原因。");

    t.check(turn.message, includes("原因")).label("说明失败原因");

    const tests = await t.sandbox.runCommand("pnpm", ["test"]);
    await t.check(tests, commandSucceeded()).label("测试通过").orStop();
  },
});
```

Boolean `matched` 进入 Verdict；`mismatched` 使最终 Verdict 为 `failed`，但不会阻止其它 Assertion 继续登记和结算。需要让后续代码依赖这条结果时，`await handle.orStop()`。

## 连续质量线

`similarity(...)` 这类 Match 产生 `[0, 1]` 的 measurement。通过制评估必须用 `.atLeast(n)` 给它阈值：

```ts theme={null}
t.check(turn.message, similarity(expected))
  .atLeast(0.8)
  .label("回答接近期望内容");
```

低于 `atLeast` 时，这项要求失败。只想留下不影响判定的说明时用 `t.diagnostic(...)`，不要登记无消费的测量值。

## 走完三步也要记三分

分步骤任务适合 `defineScoreEval`。Assertion 默认只保存 evaluation，不计分；`.score(n)` 才让该项贡献分数。Boolean matched 贡献 `n`，mismatched 贡献 `0`；measurement `m` 贡献 `m * n`。

```ts theme={null}
import { defineScoreEval } from "niceeval";
import { commandSucceeded, includes, similarity } from "niceeval/expect";

export default defineScoreEval({
  description: "安装并启动 DB-GPT",
  async test(t) {
    const turn = await t.send("把 DB-GPT 装起来并通过健康检查。");

    t.sandbox.fileChanged("db-gpt/.env").score(1).label("配置运行环境");

    const health = await t.sandbox.runCommand("curl", ["-s", "localhost:5670/health"]);
    t.check(health, commandSucceeded()).score(1).label("健康检查可达");
    t.check(health.stdout, includes("ok")).score(1).label("健康检查内容正确");

    t.check(turn.message, similarity("说明安装步骤和验证结果")).score(2).label("说明质量");

    t.score(1).label("代码精简");
  },
});
```

`t.score(n)` 直接登记 contribution，`n` 必须 finite 且不小于零，返回的 handle 只能配置 `key` 与 `label`。同一个 Assertion 可以同时配置 `.score(n)` 与 `.atLeast(n)`，evaluator 只求值一次，顺序可互换。

`test` 正常返回时，NiceEval 自动封口。没有计分项也是有效结果，得到正式 `score: 0`；这表示评估成功形成了零分，不是执行失败或证据不足。

## 两种题型的结果

| 题型                | 成功状态                | 明确要求失败           | 证据无法取得                         | 执行或 evaluator 出错             |
| ----------------- | ------------------- | ---------------- | ------------------------------ | ---------------------------- |
| `defineEval`      | `passed`            | `failed`         | `errored`                      | `errored`                    |
| `defineScoreEval` | `scored`，可排名的 score | 正常不失效；score 照常累计 | 已配置 score 或 control 的项不可用时不可排名 | `errored`，只保留 `partialScore` |

计分制的 `scored` 可以是 0 分。零分说明评估成功形成了分数，不等于执行失败或证据不足。计分制没有 Attempt Verdict。

## Judge 也是 measurement

Judge recipe 直接登记 measurement Assertion。先声明 `judge` capability，再在同一 handle 上配置阈值或分数：

```ts theme={null}
export default defineScoreEval({
  judge: true,
  async test(t) {
    const turn = await t.send("说明这项变更的动机和风险。");
    turn.judge.autoevals.closedQA("说明是否具体、准确？")
      .score(20)
      .atLeast(0.7)
      .label("说明质量");
  },
});
```

同一条 Judge Assertion 可以同时配置 `.score(n)` 与 `.atLeast(n)`，evaluator 只运行一次。Judge 没有单独的消费 API。

## 代码任务用真实命令验收

```ts theme={null}
await t.check(
  await t.sandbox.runCommand("pnpm", ["test"]),
  commandSucceeded(),
).label("项目测试通过");
```

判分标准本身是一份文件时，用 `loadText` 读取隐藏测试、参考实现或跑测脚本。文件改动会触发对应评估重跑，详见[隐藏测试判分](/docs/zh/tutorials/criteria-files)。

## 实用建议

* 把每个必须成立的条件登记为 Boolean Assertion，让一次 Attempt 收集完整失败信息。
* 后续步骤依赖某条结果时，`await handle.orStop()`。
* 任务存在有意义的部分完成度时使用 `defineScoreEval`；`test` 正常返回时自动收尾。
* 开放式语义用 Judge；可精确检查的文件、命令与结构化输出优先用确定性 Match。
