## “我已经完成了”不是证据

Agent 修改代码后说“测试已通过”，不代表测试真的运行过；生成一份报告后说“内容完整”，不代表必填章节都存在；调用发布工具后说“发布成功”，也不代表外部系统真的返回了文章地址。

模型擅长生成合理的语言，但任务完成是关于现实状态的判断。

因此，Harness 的最后一个核心部分不是输出答案，而是**验证与评估**：先检查这次任务是否真的完成，再用一批代表性任务衡量整个 Agent 系统是否持续有效。

如果把 Agent 比作施工队，最终回复只是施工队的口头报告；验证是现场验收，评估则是长期分析这支队伍在不同项目中的质量、速度和成本。

本文是《[把 Harness 讲清楚：Agent 背后的运行系统](https://www.ittt.cc/articles/15)》八个核心部分的第八篇。

## 验证和评估不是一回事

### 验证

发生在一次具体任务中，回答“这次是否满足完成标准”。例如测试是否通过、文件是否生成、文章是否能在线访问。

### 评估

发生在一组任务和一段时间上，回答“这个 Agent 系统总体表现怎样”。例如代码修复成功率、误操作率、平均成本和人工接管率。

验证保证单次交付，评估推动系统迭代。没有验证，最终回复可能只是自信陈述；没有评估，团队只能凭几个漂亮 Demo 判断产品质量。

## 完成标准必须在任务开始时定义

如果直到任务结束才决定怎样验收，标准很容易被当前结果影响。

任务契约应该提前写出可检查条件：

```json
{
  "objective": "修复登录页无限刷新",
  "completion_criteria": [
    "能够稳定复现原问题",
    "新增回归测试覆盖会话过期场景",
    "修复后相关测试退出码为 0",
    "没有修改数据库结构"
  ],
  "required_evidence": [
    "changed_files",
    "test_command",
    "test_exit_code"
  ]
}
```

完成标准应该描述可观察结果，而不是“认真处理”“尽量优化”或“给出高质量答案”。

## 验证应该尽量检查外部世界

最弱的验证方式是询问模型：“你完成了吗？”模型只能根据自己的上下文回答，很容易把计划、尝试或部分结果当成完成。

更可靠的证据来自任务对象本身：

| 任务 | 更可靠的验证 |
| --- | --- |
| 修改代码 | 读取差异、运行测试、静态检查 |
| 生成文件 | 检查文件存在、格式、内容和渲染效果 |
| 发布文章 | 校验接口通过、发布回执、公开页面可访问 |
| 写数据库 | 查询目标记录与约束 |
| 发送消息 | 获取平台消息 ID 和目标会话 |
| 数据分析 | 重算关键指标、检查样本和边界条件 |

原则可以概括为：**验证世界，而不是验证 Agent 的自我报告。**

## 一次任务的验收流程

```text
Agent 提出“可以结束”
          ↓
读取任务完成标准
          ↓
为每条标准选择验证器
          ↓
运行确定性检查或独立评审
          ↓
汇总证据
   ├─ 全部通过 → 标记完成
   ├─ 可修复失败 → 把反馈送回 Agent Loop
   └─ 无法验证或高风险 → 请求人工验收
          ↓
生成带证据的最终回复
```

验证失败不一定意味着任务立刻失败。它可以成为下一轮的高质量反馈，例如“单元测试通过，但类型检查在 `auth.ts:42` 失败”。

## 确定性检查优先

只要能用程序明确判断，就不要先让另一个模型打分。

```python
def verify_code_change(contract, workspace):
    evidence = {}

    evidence["diff"] = git_diff(workspace)
    evidence["forbidden_paths_untouched"] = check_scope(
        evidence["diff"],
        contract.scope,
    )
    evidence["tests"] = run(contract.required_test_command)

    passed = (
        evidence["diff"].has_changes
        and evidence["forbidden_paths_untouched"]
        and evidence["tests"].exit_code == 0
    )

    return Verdict(passed=passed, evidence=evidence)
```

确定性验证包括 schema 校验、退出码、文件哈希、数据库约束和 HTTP 状态。它们可重复、容易审计，也不受评审模型随机性影响。

## 什么时候需要模型评审

有些标准难以用布尔规则表达，例如文章是否通俗、客服回复是否礼貌、需求分析是否遗漏关键场景。

这时可以使用模型评审，但要控制它的角色：

- 提供清楚的评分量表；
- 给出任务输入、候选结果和必要证据；
- 不让评审模型看到不相关的生成过程；
- 对高风险决策保留人工复核；
- 用人工标注样本校准评审结果；
- 关注模型偏好长度、文风或位置的偏差。

一个简单量表比“请评价质量”更稳定：

```text
准确性：0-2 分
  0 = 存在关键事实错误
  1 = 基本正确，但有次要问题
  2 = 关键事实均有依据

完整性：0-2 分
  0 = 缺少核心要求
  1 = 覆盖大部分要求
  2 = 所有明确要求均被覆盖

可执行性：0-2 分
  0 = 不能直接使用
  1 = 需要少量人工修改
  2 = 可以直接交付
```

## 不要让生成者同时做最终裁判

让同一个模型生成结果后，再问它“你的答案正确吗”，可以发现部分明显问题，却不构成独立验证。

更稳妥的层级是：

1. 生成 Agent 自检格式和遗漏；
2. Harness 运行确定性验证；
3. 必要时由独立模型按量表评审；
4. 高风险或主观任务由人最终确认。

独立不一定要求换一家模型，但评审请求应隔离生成时的自我辩护，并以原始任务和证据为准。

## 建立离线评估集

评估集不是随便收集一批 Prompt。它应该代表真实用户任务和重要风险。

可以按下面步骤建立：

```text
收集真实任务与失败案例
          ↓
按任务类型、难度和风险分层
          ↓
定义期望结果、允许变化和评分规则
          ↓
准备可重复环境与验证器
          ↓
固定 Agent、模型和工具版本运行
          ↓
汇总质量、延迟、成本和安全指标
          ↓
抽样人工复核并分析失败原因
```

评估集应包含正常案例、边界案例和对抗案例。只测最容易成功的任务，会得到漂亮但无用的分数。

## 应该记录哪些评估指标

### 结果质量

- 完成率；
- 每条完成标准通过率；
- 首次通过率；
- 人工返工率；
- 严重错误率。

### 工具与行为

- 工具调用成功率；
- 无效或重复调用率；
- 越权尝试与策略阻止率；
- 未知副作用比例；
- 平均 Step 数。

### 体验与效率

- 总延迟和首次有效进度时间；
- token 与金额成本；
- 用户取消率；
- 审批等待时间；
- 人工接管率。

单个总分很容易掩盖问题。完成率提高 3%，但误操作率翻倍，并不是可接受的升级。

## 回归测试要固定什么

Agent 系统会同时受模型、提示词、工具、检索和策略变化影响。评估结果必须记录版本：

```json
{
  "agent_version": "2026.09.03",
  "model": "provider/model-version",
  "prompt_revision": "p-184",
  "toolset_revision": "tools-72",
  "policy_revision": "policy-19",
  "dataset_version": "coding-eval-v6"
}
```

否则分数变化时无法判断原因。对有随机性的模型，还应运行多次或设置足够样本，报告波动范围，而不是过度解读一次结果。

## 线上评估和离线评估互相补充

离线评估可重复、适合发布前比较版本，但无法覆盖所有真实环境变化。线上数据能看到真实用户任务，却更难获得完整标准答案。

一个健康闭环是：

```text
线上失败、用户纠正和人工接管
              ↓
脱敏后沉淀为评估案例
              ↓
离线复现并加入回归集
              ↓
修复模型、提示词、工具或 Harness
              ↓
离线通过后小流量发布
              ↓
继续观察线上结果
```

评估的目的不是做排行榜，而是定位系统哪一层需要改进。

## 失败归因比一个分数更重要

同样是任务未完成，原因可能完全不同：

- 任务契约漏掉完成标准；
- 上下文没有找到关键文件；
- 模型选择了错误方案；
- 工具参数或返回设计不清楚；
- 安全策略误伤；
- 状态恢复重复了副作用；
- 验证器本身存在 Bug。

评估报告应该把失败映射回 Harness 模块。否则团队看到“成功率 72%”，却不知道下一周该改什么。

## 常见的失败方式

### 用模型的最终文字判断是否完成

模型可能诚实但判断错误。应读取真实文件、执行测试或查询外部系统。

### 只准备十几个漂亮案例

样本太少且没有失败场景，无法预测真实效果。

### 指标只有平均分

高风险任务中的一次严重误操作，不能被大量简单成功案例平均掉。

### 每次评估的环境不同

依赖版本、数据和工具状态变化会污染结果。需要可重复环境和版本记录。

### 发现失败却没有沉淀

线上问题修完就结束，下次改动还会再次出现。真实失败应转化为回归案例。

## 验证与评估检查清单

- 完成标准是否在任务开始前定义？
- 每条标准是否有对应验证方法和证据？
- 是否优先使用确定性检查？
- 外部写入是否查询真实回执或目标状态？
- 模型评审是否使用明确量表并经过校准？
- 高风险结果是否保留人工验收？
- 评估集是否覆盖真实、边界和对抗案例？
- 是否同时衡量质量、行为、体验、成本和安全？
- 运行结果是否记录模型、提示词、工具、策略和数据集版本？
- 线上失败是否进入离线回归集？
- 失败能否归因到具体 Harness 模块？

## 最后理解验证与评估

Agent 的最终文本只是一次声明，现实证据才决定任务是否完成。

验证把单次交付从“听起来正确”变成“已经检查”，评估则把团队从凭感觉调 Prompt，带到可以比较、回归和持续改进的工程流程。

一句话总结：**不要问 Agent 是否完成，要检查目标世界是否已经变成我们期望的样子。**
