04—为什么不能让 AI 自己评审自己?AI Skill 四层验证体系完整解析

6 阅读14分钟

为什么不能让 AI 自己评审自己?AI Skill 四层验证体系完整解析

系列:SkillSentry · AI Skill 测评体系从零到一(四)

难度:深入

适合读者:想构建可信测评机制的工程师

📌 一句话摘要:让模型自判卷会产生系统性偏差,本文拆解 AI Skill 四层验证体系如何用独立 Grader Agent 和盲测 Comparator 彻底消除自判卷问题。

🏷️ 推荐标签:AI Skill四层验证 LLM自判卷偏差 独立Grader Agent


问题:为什么不能让模型自己评审自己

让模型自己评审自己的输出,会产生「自判卷偏差」——这是 AI Skill 四层验证体系要解决的核心问题。 最朴素的测评思路:让模型执行任务,然后让模型判断结果是否正确。

这有一个根本缺陷:执行者和评审者是同一个模型

实验中观察到的现象:

  • 同一个用例,with_skill 跑出来通过率 100%,without_skill 也是 100%
  • 展开看 evidence,发现很多断言的 evidence 是空的,或者只写了「根据整体输出判断通过」
  • 这说明评审是「感觉通过」,不是「有证据通过」

这就是「自判卷偏差」。


解决思路:四层验证,各司其职

四层验证体系的核心思路是:把执行、精确校验、语义评审、盲测对比四件事彻底分开,每层只负责自己最擅长的部分。 每层解决不同的问题,互相补充:

Layer 0: 执行模式分发(v5.0 新增)
    → 检测 Skill 类型(mcp_based / code_execution / text_generation)
    → 选择对应执行模式,分发给 Layer 1

Layer 1: Executor(执行层)
    → 真实执行 Skill,记录所有证据(transcript + response + metrics)

Layer 2a: 字段精确校验(Ground Truth)
    → 从 transcript 直接提取字段值,assertEqual / 正则匹配
    → 不经 LLM,完全客观

Layer 2b: 独立 Grader Agent(语义评审)
    → 独立 LLM 读 transcript + response,找原文 evidence
    → 执行者和评审者完全分离
    → v5.0:支持 MCP / 代码执行 / 纯文本 三种评审标准

Layer 3: 盲测 Comparator + Analyzer(正常路径 + E2E 必跑)
    → Comparator 不知道哪个是 with_skill,纯质量评分
    → Analyzer 解盲,定位胜负根因

Layer 1:Executor

职责:真实执行 Skill,记录完整证据。没有 Layer 1 的 transcript,后续所有验证层都无法工作。

v5.0 新增 Layer 0 — 执行模式自动分发

在 Layer 1 执行前,系统先检测 Skill 类型并选择对应模式:

Skill 类型执行模式transcript 内容
mcp_based真实 MCP 工具调用完整工具调用记录(入参、返回值、报错)
code_execution真实 Bash/脚本执行命令执行记录 + 输出文件内容
text_generation纯文本模式模型推理过程 + 最终输出(无工具调用)

纯文本模式下,transcript 没有工具调用记录,Grader 直接从 response.md 找证据(见 Layer 2b 说明)。

产出文件

with_skill/outputs/
    transcript.md    ← 完整执行过程(每步工具调用+入参+返回值+推理)
    response.md      ← 最终向用户呈现的内容
    metrics.json     ← 工具调用统计
timing.json          ← 执行耗时 + tokens(来自 task notification,只有这一次机会)

timing.json 格式(v5.0 增强):

{
  "executor_start_ms": 1711234567000,
  "executor_end_ms":   1711234573500,
  "duration_ms":       6500,
  "total_tokens":      2340,
  "input_tokens":      1200,
  "output_tokens":     1140
}

关键设计

  • with_skill 和 without_skill 必须在同一轮同时启动,不能先跑一个再回来跑另一个
  • timing.json 必须在 task notification 到达时立即保存,错过就永久丢失
  • 纯文本模式execution_metrics.total_mcp_calls 填 0,不影响 Grader 判断

Layer 2a:字段精确校验(Ground Truth)

Layer 2a 是四层中最可信的一层,因为它完全不经过任何 LLM,是纯文本匹配——相当于软件测试里的 assertEqual 对可以精确匹配的断言做客观验证,不依赖 LLM 判断。

为什么 Layer 2a 是四层中最可信的:无论模型当天状态如何、temperature 怎么设,同一个 transcript 跑 Layer 2a 永远得到同样的结论。不受模型幻觉、评审偏见、随机性影响。这是 Layer 2b 和 Layer 3 做不到的。

适合验证的断言类型

接口调用次数:saveExpenseDoc 调用了几次(计数)
固定参数值:docStatus == "10"(精确匹配)
链接格式:不含字面占位符 {fdId}(正则)
字段值:fdMonthOfOccurrence 是否等于当前月份计算值(精确匹配)

不适合 Layer 2a 的断言(转交 Layer 2b)

「输出格式是否对用户友好」→ 主观,需要 LLM 评审
「报销主题内容是否合理」→ 语义性,需要 LLM 评审
「错误提示是否清晰」→ 语义性,需要 LLM 评审

产出文件ground_truth.json

{
  "checks": [
    {
      "assertion": "saveExpenseDoc 参数 docStatus=10",
      "method": "transcript_search",
      "passed": true,
      "evidence": "transcript Step5 入参:{\"docStatus\":\"10\",\"expenseType\":\"1\",...}"
    },
    {
      "assertion": "详情链接不含字面占位符 {fdId}",
      "method": "regex",
      "passed": false,
      "evidence": "response.md 第12行链接中仍含 {fdId} 占位符"
    }
  ]
}

这一层的价值:绑定了最可信的 evidence——直接从 transcript 提取的原文,不经过任何 LLM 推断。


Layer 2b:独立 Grader Agent

独立 Grader Agent 通过强制引用原文 evidence,从根本上消除「感觉通过」的评审方式——找不到原文支持,就是 FAIL。 用独立 LLM 评审语义性断言。

与 Layer 2a 的分工

  • Layer 2a 处理:可以精确匹配的断言
  • Layer 2b 处理:需要理解语义的断言

v5.0 新增:三种评审标准按 Skill 类型切换

Grader 收到 skill_type 参数,自动切换对应评审规范:

skill_typeevidence 来源特殊注意点
mcp_basedtranscript 中的工具调用记录验证入参/返回值/调用次数
code_executionBash 调用记录 + 输出文件内容验证命令正确性和文件内容
text_generationresponse.md 原文段落无工具调用,从输出文本找证据

纯文本 Skill 的 evidence 规范

✅ 好的 evidence(纯文本版):
  "response.md 第3段:'本次分析覆盖了以下三个维度:1.性能 2.安全 3.可维护性'
   ——三个维度均已呈现,满足断言"

❌ 不可接受:
  "从整体输出来看,内容比较完整"
  "AI 似乎理解了用户意图"

Grader Agent 的工作方式

Step 1:读取 skill_type,选择评审标准
Step 2:读取 transcript.md 或 response.md(根据类型)
Step 3:对每条断言:找原文 → 判定 PASS/FAIL → 必须 quote 具体文字
Step 4:提取隐含 claims 并验证(幻觉检测)
Step 5:读取 user_notes.md(执行者在运行时记录的疑问)
Step 6:批评断言质量(eval_feedback)
Step 7:读取 timing.json,将耗时/Token 数据写入 grading.json

v5.0 grading.json 新增字段

{
  "skill_type": "text_generation",
  "timing": {
    "executor_duration_ms": 6500,
    "total_tokens": 2340,
    "input_tokens": 1200,
    "output_tokens": 1140
  }
}

user_notes.md:执行层(Layer 1)在运行过程中记录的疑问,例如「Step 3 接口返回了异常状态码但未中断,不确定是否符合预期」。Grader 读取这些注记后可以有针对性地重点评审对应断言。

evidence 强制非空的意义

强制引用原文,消除了「感觉通过」的评审方式。如果找不到原文支持,就是 FAIL。

幻觉检测(最有价值的额外工作)

Grader 不只评审预定义的断言,还会从输出中提取「隐含声明」并逐一核查:

隐含声明:「saveExpenseDoc 调用了一次」
类型:factual
验证结果:true
证据:transcript 中 saveExpenseDoc 出现 1 次(Step5)

隐含声明:「fdMonthOfOccurrence 取当前月份 120260200」
类型:factual
验证结果:false
证据:checkExpenseItem 入参 fdMonthOfOccurrence=120251100(发票月而非提单月)

这里发现的问题,是预定义断言可能遗漏的。

断言质量建议(eval_feedback)

Grader 还会批评断言本身的质量,例如:

「『输出包含报销金额』只检查了存在性,未验证金额与发票一致,幻觉金额也会通过。建议改为:报销金额等于发票识别金额」


Layer 3:盲测 Comparator + Analyzer(正常路径 + E2E 必跑)

盲测 Comparator 通过让评审者不知道哪个是 with_skill,从机制上消除「对好版本更宽容」的评审偏见。 深度比较 with_skill 和 without_skill 的输出质量。

触发规则:正常路径用例(Happy Path)和 E2E 用例完成后必须执行,不可跳过。其他类型用例不触发。

为什么要盲测:Layer 2b 的 Grader 知道哪个是 with_skill,可能存在「对好版本更宽容」的评审偏见。Comparator 不知道 A/B 哪个是 with_skill,只看内容质量打分,消除了这种偏见。

Comparator 评分维度

内容维度(Content):
  正确性(Correctness)  1-5 分
  完整性(Completeness) 1-5 分
  准确性(Accuracy)     1-5 分

结构维度(Structure):
  组织性(Organization) 1-5 分
  格式规范(Formatting) 1-5 分
  可用性(Usability)    1-5 分

综合得分 = (内容均值 + 结构均值) / 2 × 2(换算 1-10 分)

Analyzer 做什么:Comparator 评完分后,Analyzer 解盲(得知哪个是 with_skill),定位胜负根因,生成可操作的改进建议:

{
  "improvement_suggestions": [
    {
      "priority": "high",
      "category": "instructions",
      "suggestion": "将含糊的「处理发票」描述替换为明确的 3 步操作序列",
      "expected_impact": "消除歧义,防止模型自行发挥"
    }
  ]
}

四层之间的关系

四层验证的关系是:Layer 1 是基础,Layer 2a/2b 互补,Layer 3 是深化——每一层都依赖前一层的产出,缺少任何一层都会留下验证盲区。

Layer 1 是基础
    → 没有 transcript,Layer 2 和 3 都无法工作

Layer 2a 和 2b 互补
    → 精确字段 → Layer 2a,语义内容 → Layer 2b
    → 最终的 grading.json 合并两层结果

Layer 3 是深化
    → 只在重要用例(Happy Path / E2E)上执行
    → 发现 Layer 2 发现不了的质量问题

grading.json 中的 method 字段,标注每条断言来自哪一层:

{"text": "docStatus=10", "passed": true, "method": "ground_truth", "evidence": "..."}
{"text": "输出包含报销主题", "passed": true, "method": "grader", "evidence": "..."}

报告中 [ground_truth] 标签的断言最可信,[grader] 标签次之(需要看 evidence 是否有原文)。


与 skill-creator 的对应关系

我们的四层验证体系借鉴并扩展了 skill-creator 的设计:

我们的层skill-creator 对应改进点
Layer 1Step 1(spawn runs)+ Step 3(capture timing)增加 transcript 格式规范
Layer 2a无(我们新增)精确字段校验,来源于软件测试 assertEqual 思路
Layer 2bagents/grader.md汉化,增加 evidence 强制非空约束
Layer 3agents/comparator.md + analyzer.md汉化,增加 E2E 必须执行 Layer3 的规则

小结

解决的核心问题产出可信度触发时机
Layer 0 ✨不同 Skill 类型执行方式不同skill_type 分发决策每次测评启动时
Layer 1没有真实执行记录,评审无原材料transcript + response + metrics + timing.json基础每个用例必跑
Layer 2aLLM 评审精确字段不可靠ground_truth.json最高Layer 1 完成后立即执行
Layer 2b执行者自判卷grading.json(含 skill_type / claims / timing)Layer 1 完成后立即执行
Layer 3评审者知道哪个是「好版本」存在偏见comparison.json + analysis.json高(盲测)仅正常路径 + E2E 用例

✨ = v5.0 新增


工程细节:测评进度的可见性设计

测评进度的可见性设计解决的核心问题是:十几个子步骤如果全部暴露给用户,界面会非常嘈杂,5 个里程碑节点恰好对应用户需要参与决策的关键点。 这套四层验证体系有一个配套的工程细节值得单独说一下。

测评工具在启动时写入 5 个 todo,用户在界面上始终可见:

用户层 todo(5 个)——用户在界面上看到的

1/5】📋 准备阶段:分析 Skill + 收集测评所需信息
【2/5】⚙️ 方案确认:选择模式 + 确认用例清单
【3/5】🚀 执行测评:分批运行所有用例(四层验证)
【4/5】📊 评分分析:汇总指标 + 覆盖率检查 + 质量清单
【5/5】📄 生成报告:输出 HTML 报告 + 解读指引

每完成一个阶段立即标记完成,用户始终知道当前在第几步、下一步需要做什么决策。

这个设计解决的问题:测评流程有十几个子步骤(MCP 检测、规则提炼、用例设计、分批执行……),如果每个步骤都暴露给用户,界面会非常嘈杂。5 个里程碑节点恰好对应「用户需要参与决策的关键点」,其余执行细节由 AI 自动完成,不打扰用户。

下一篇,我们来深入拆解 skill-creator 的源码——它的触发率测评和 description 自动优化循环是怎么实现的。


附录:与 ADK 5 大设计模式的对应关系

SkillSentry 的四层验证体系与谷歌 ADK 的 Reviewer 模式直接对应(独立评审、权责分离),Pipeline 模式驱动整个测评流水线。完整分析见第八篇。

ADK 模式SkillSentry 对应核心解决的问题
ReviewerGrader/Comparator/Analyzer 三个独立 Agent执行者自判卷
Pipeline阶段零→六的流水线 + 量化准出标准信息不完整时跳步
Invokereferences/ 文件精确触发条件漏读规则或全量读浪费 Token
Tool Wrapper8 种异常标准话术表MCP 不可用时 AI 自由发挥
Generator报告前置检查 + 章节强制校验AI 跳过关键章节

FAQ:关于 AI Skill 四层验证,用户常问的问题

为什么不能让模型自己评审自己的输出?

让执行者和评审者是同一个模型,会产生「自判卷偏差」。实验中可以观察到:同一个用例,with_skill 和 without_skill 的通过率都是 100%,但展开看 evidence 发现大量断言的 evidence 是空的,说明模型在「感觉通过」而不是「有证据通过」。这种偏差会让测评结论完全失去可信度,无论跑多少用例都没有意义。

四层验证体系各层分别解决什么问题?

四层各有分工:Layer 1(Executor)负责真实执行并记录完整 transcript,是其余三层的原材料来源;Layer 2a(Ground Truth)用精确文本匹配校验可量化的字段,不经过任何 LLM,是最可信的一层;Layer 2b(独立 Grader Agent)用独立 LLM 评审语义性断言,强制引用原文 evidence;Layer 3(盲测 Comparator)让评审者在不知道哪个是 with_skill 的情况下打分,消除评审偏见。四层合并的结论比任何单一验证机制都可信。

什么是 Ground Truth 精确校验,和 LLM 评审有什么区别?

Ground Truth 精确校验(Layer 2a)是纯文本匹配,相当于软件测试里的 assertEqual——直接从 transcript 提取字段值,做计数、精确匹配或正则匹配,完全不经过任何 LLM。LLM 评审(Layer 2b)则是让独立 Grader 理解语义、判断断言是否成立。前者的结论不受模型随机性影响,同一个 transcript 永远得到相同结论;后者更灵活,能处理语义性的断言,但可信度依赖 evidence 是否有原文支撑。两者互补,不可替代。

盲测 Comparator 是如何消除评审偏见的?

Comparator 在评分时不知道 A/B 哪个是 with_skill 输出,只看内容质量本身,从六个维度(正确性、完整性、准确性、组织性、格式规范、可用性)独立打分。评分完成后,Analyzer 才解盲——得知哪个是 with_skill——再定位胜负根因并给出改进建议。这种「先盲评,后解盲」的机制,确保评分过程不受「我知道这个是好版本」的主观预期影响。

evidence 字段为什么必须引用原文?

evidence 强制非空是对抗「感觉通过」的核心机制。如果允许 Grader 写「根据整体输出判断通过」这类无来源的评语,那这条断言的判定结果就完全依赖模型当天的状态,不具备可重复性和可审计性。强制引用原文意味着:找到了原文 → PASS;找不到原文支持 → FAIL。这让每一条断言的判定结果都有据可查,报告中的通过率才是真实可信的数字。