反思问的是「我帅不帅」,验证问的是「我有没有穿错鞋」——前者偏主观,后者要经得起对照。
Self-Verification:Agent 如何自我验证
flowchart LR
A["Self-Verification:Agent 如何自我验证"]
A --> B["分类:智能体 (Agents)"]
A --> C["关键词:Agent"]
A --> D["关键词:Self-Verification"]
A --> E["关键词:Verification Chain"]
A --> F["关键词:Critic"]
在第 28 篇 Reflection 里,我们聊过 Reflexion、自我批评与「做 → 评 → 改」的循环。那篇的重点是质量与迭代:模型如何评估自己、如何改得更好。本篇往下挖一层,专门讲 Verification(验证):不是「好不好」,而是「对不对、可不可信、能不能上线」——多步验证链、Critic 架构、代码与事实的客观校验,以及和护栏、宪法式约束怎么配合。
这篇文章会讲什么
| 你可能关心 | 这篇能给你 |
|---|---|
| 反思和验证到底差在哪 | 清晰区分主观评估 vs 客观验证,避免混用术语 |
| 生产里怎么搭「可信」流水线 | 验证链四步、工具选型、何时加重验证 |
| 代码 Agent 怎么不靠「感觉」过关 | 测试、静态分析、类型检查等形式化手段 |
| 回答要有据、要安全 | 事实性验证、RAG 交叉检查、Constitutional AI 与 Guardrail 位置 |
先看定义:读完你会有一套「输出 → 分层验证 → 放行/打回」的地图,而不是只靠「再让模型想一遍」。
先说结论:Verification 不是“再问模型一次”,而是“给输出建立放行机制”
很多系统表面上做了验证,实际只是:
- 先让模型回答;
- 再问同一个模型一句“你确定吗?”;
- 然后希望它更靠谱。
这更像二次自我安慰,不太像验证。真正有工程价值的 Verification,通常有三个特征:
- 有独立标准:schema、测试、检索来源、权限规则;
- 有失败去向:重试、降级、转人工、拒绝放行;
- 有记录:知道失败在哪一层,而不是只看到“这次不行”。
所以更成熟的理解是:
Verification 是输出进入真实世界之前的门禁系统。
它和 Reflection 的关系,不是替代,而是分工:Reflection 负责改进,Verification 负责放行。前者更像教练,后者更像质检员。
1. Reflection ≠ Verification:先分清
| 维度 | Reflection(反思) | Verification(验证) |
|---|---|---|
| 核心问题 | 「我做得好不好?」 | 「我的输出是否正确 / 合规?」 |
| 性质 | 偏主观的质量评估 | 偏客观的符合性检查 |
| 典型手段 | 自评、批评提示、迭代改写 | 规则、测试、外部 API、多模型投票 |
| 与第 05 篇关系 | 第 05 篇主战场 | 本篇主战场 |
先看定义:反思帮你「变更好」,验证帮你「别出错」;Agent 从「好用」到「可信」,验证往往是瓶颈和护城河。
但要克制一点说:Verification 也不是“证明正确”。大多数应用里的验证,更准确地说是在系统性提高置信度、降低明显错误出站概率。只有代码测试、数值重算、权限检查这类强约束环节,才更接近“可证明”的客观验证。
第 05 篇已经铺好了反思与 Reflexion 的语境;本篇假设你愿意为可检验性多付一点延迟和算力——下面所有模式,都建立在「验证可以被定义、被执行、被记录」之上。
2. Verification Chain(验证链):多步验证模式
不要把「验证」想成单次调用。生产里常见做法是 Verification Chain:按成本从低到高、从机械到语义,逐级过滤。
| Step | 关注点 | 典型做法 | 可用工具形态 |
|---|---|---|---|
| 1. 格式验证 | 输出结构是否符合 schema / 协议 | JSON Schema、正则、模板比对 | 规则引擎、Pydantic、自定义校验器 |
| 2. 逻辑验证 | 推理步骤是否自洽、结论是否跟随前提 | 让模型逐步列出依据并检查矛盾 | 第二遍 LLM、结构化 CoT 检查 |
| 3. 事实验证 | 可核查陈述是否有来源、是否与知识库一致 | 检索对齐、引文检查、数值重算 | RAG、搜索引擎 API、计算器 / 代码执行 |
| 4. 安全验证 | 是否涉敏、违规、越狱诱导 | 策略分类器、关键词与语义护栏 | Llama Guard 类模型、自定义安全 LLM |
每一步可以独立失败并短路:格式不过 → 不必跑事实 API;安全不过 → 直接拒绝或脱敏,节省下游成本。
先看定义:验证链 = 分层门禁;越往后越贵,越要留给真正需要的样本。
验证链在流水线里的位置(示意)
用户请求
│
▼
┌──────────┐ 失败 ┌──────────┐ 失败 ┌──────────┐ 失败 ┌──────────┐
│ 格式校验 │ ────────► │ 逻辑校验 │ ────────► │ 事实校验 │ ────────► │ 安全校验 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │
└──────────────────────┴──────────────────────┴──────────────────────┘
│
全部通过 → 放行
任一失败 → 打回 / 改写 / 降级
落地时记得给每一步留 可观测性:记录失败原因、重试次数、最终走的是「自动修复」还是「人工队列」。否则线上出了事故,你只能看到「模型不行」,看不到「哪一层本该拦住」。
3. Critic Agent 模式与 Generator–Verifier
先看定义:专门放一个 Critic Agent 来评 Worker(Generator) 的输出,是工业界最清晰的职责拆分之一。
- Worker:完成任务(写代码、写答案、调工具)。
- Critic:对照规范、测试、风险清单做评判,输出「通过 / 不通过 + 理由」。
这就是 Generator–Verifier 架构:生成与验证解耦,验证逻辑可替换(规则版 Critic、强模型 Critic、混合)。
设计 Critic 时,尽量给它 可执行的量表(rubric),而不是一句「你觉得好不好」。例如:「是否覆盖用户列出的三点需求?」「是否出现未给出来源的百分比?」「代码 diff 是否只触及约定文件?」——量表越像检查清单,验证越像工程,而不是玄学。
先看定义:好的 Critic 不是「更挑剔的聊天」,而是「带标准的审计员」。
LangGraph 风格伪代码(示意)
# 示意:生成 → 批评 → 条件重试
from langgraph.graph import StateGraph, END
def generate(state):
state["draft"] = worker_llm.invoke(state["task"])
return state
def critique(state):
verdict = critic_llm.invoke({
"draft": state["draft"],
"rubric": state["rubric"],
})
state["ok"] = verdict["pass"]
state["feedback"] = verdict["comments"]
return state
def should_retry(state):
return "retry" if not state["ok"] and state["attempts"] < 3 else "done"
graph = StateGraph(dict)
graph.add_node("gen", generate)
graph.add_node("crit", critique)
graph.set_entry_point("gen")
graph.add_edge("gen", "crit")
graph.add_conditional_edges("crit", should_retry, {"retry": "gen", "done": END})
多个 Critic 投票
先看定义:高 stakes 场景可以用 多 Critic 投票(多数决、一致才通过、或加权),降低单一模型盲点;成本与延迟线性上升,适合对外答复、合规审查,不适合每一步中间草稿。
简单对比三种策略:
| 策略 | 何时用 | 备注 |
|---|---|---|
| 多数决 | 三个 Critic 里两个说通过 | 成本适中,适合一般对外场景 |
| 一致才过 | 金融、医疗摘要等 | 假阴性上升,需配套人工兜底 |
| 加权 | 某 Critic 专精安全、某专精事实 | 调权前先离线评估混淆矩阵 |
如果 Generator 和 Critic 其实用的是同家族模型、同样的盲点,投票收益会明显打折。所以高风险链路常见的做法是:
- 生成用通用大模型;
- 事实验证用检索/规则/计算器;
- 安全验证用专门分类模型;
- 必要时再加一个异构 LLM 做最终审查。
这样比“一个模型换三个温度”更像工程验证,而不是自我安慰。
4. Formal Verification:代码场景
对代码而言,「感觉能跑」不够,可执行、可静态证明、可类型推断才是硬验证。
典型链:
- 生成代码 → 2. 运行测试(pytest 等) → 3. 静态分析(lint、复杂度) → 4. 类型检查(mypy、TypeScript + tsc、eslint 规则集)
| 工具 | 角色 |
|---|---|
| pytest / jest | 行为是否符合用例 |
| mypy / tsc | 契约与类型一致性 |
| eslint / ruff | 风格与部分语义陷阱 |
最小闭环示例(Python):Agent 产出补丁后,CI 式地跑 pytest -q,再 ruff check .,再 mypy package/——任何一步非零退出码就回传 stderr 给 Worker 或触发 Reflexion 式重写。把 stderr 结构化(只取最后 N 行、或解析失败用例名)再喂回模型,重试成功率通常高于整页日志糊脸。
SWE-bench 一类基准强调:代理要在真实仓库上修 bug,能否通过现有测试是客观成败标准——这正是验证链在代码领域的价值:论文与排行榜上的增益,往往来自「生成 + 多轮测试反馈」,而非单次生成更大模型。你在内网复刻时,不必追求完整 SWE-bench,先对你业务仓库做「最小测试子集 + 类型检查」就能拦住大量低级错误。
先看定义:代码场景里,验证链尽量工具化;LLM 反思是加分项,测试红灯是硬否决。
另外要提醒一个边界:测试通过不等于改动一定正确。它只说明“被覆盖到的行为没坏”。所以在关键仓库里,通常还要叠:
- 变更范围限制(只允许改声明文件或指定目录);
- 代码所有者审查(CODEOWNERS);
- 安全扫描与依赖审计。
5. 事实性验证(Factual Verification)
先看定义:每个关键断言都应能回答「这句话的依据在哪?」——做不到就降级为猜测或显式标注不确定。
实践要点:
- 引用检查:输出中的事实性句子,是否在上下文中能映射到检索片段、URL 或工具返回值;否则标记为未证实。
- RAG + 交叉验证:同一问题用不同检索查询或不同片段集合,看结论是否稳定;不稳定则触发人工或拒绝生成确定语气。
- 数学与数值:复杂推导交给 计算器 / SymPy / 小段代码 执行,避免纯语言幻觉。
| 场景 | 建议 |
|---|---|
| 医疗、法律、金融 | 强事实链 + 来源强制 |
| 内部脑暴 | 可放宽,但要在 UI 标明「未核实」 |
补充一句接地气的原则:宁可少说,不要胡编。验证链如果发现「检索为空仍下结论」,应强制改成「根据现有资料无法确认」或触发二次检索——这比事后公关容易得多。
验证失败后,系统该怎么反应?
先看定义:验证失败不是只有“重试”一种处理;成熟系统会把失败类型映射到不同动作。
| 失败类型 | 更合适的动作 |
|---|---|
| 格式失败 | 本地重排 / 再生成一次 |
| 事实失败 | 降级为不确定表达、重检索、转人工 |
| 安全失败 | 直接拦截、脱敏、拒答 |
| 多次失败仍不过 | 结束自动化链路,记录 trace 并升级人工 |
把这张表写进系统设计文档,比在 prompt 里写“请尽量正确”有用得多。
6. Constitutional AI 实践(自我约束)
Anthropic 提出的 Constitutional AI 思路可概括为:先有一套原则(constitution),模型在输出前或输出后按原则自我审查,必要时改写,以减少有害内容并提高对齐度。
先看定义:把「公司 / 产品红线」写成可检查的原则列表,让模型扮演「立法 + 自省」的角色——不是替代法律审查,而是降低明显违规的出站概率。
在生产中设计「宪法」时建议:
- 原则要可判定(避免纯形容词堆砌);
- 与 Output verification 联动:自省失败 → 触发重写或拦截;
- 定期用真实 bad case 回归,防止原则与业务脱节。
可以把 Constitutional 流程想成「软验证」:原则列表 相当于规范输入,自我审查 相当于一次额外的 Critic pass,修正输出 相当于带约束的重生成。它和硬规则(正则、分类器)不是二选一,而是叠在一起:硬规则挡致命问题,宪法式自省处理灰区表达。
先看定义:Constitutional AI 是「对齐与表达」上的验证;别指望它替代代码测试或事实引用。
7. Guardrail + Verification:整条链路怎么摆
推荐脑图:
Input guardrail → Agent 处理 → Output verification → Output guardrail
↑ ↑
防注入、防敏感入参 最终合规、PII、政策
- Input guardrail:垃圾进、垃圾出之前先拦一层(提示注入、越权指令)。
- Agent 内部:可嵌 Verification Chain(格式 → 逻辑 → 事实 → 安全)。
- Output verification:面向任务正确性(结构、逻辑、依据)。
- Output guardrail:面向发布安全(NeMo Guardrails 类框架把策略编排成可组合模块;Llama Guard 等可作为专用分类器插在输出侧)。
先看定义:Guardrail 管「能不能说」,Verification 管「说得对不对」;两者叠在一起才接近生产级可信。
若你已经在用 NeMo Guardrails 的 Colang 或 YAML 流程,可以把「事实核查失败」定义成一种 canonical flow:先尝试改写,仍失败则转人工——这样产品、安全、算法对「失败长什么样」有共同语言。
8. 成本与收益权衡
验证会增加 延迟(多轮、多模型)和 费用(额外 token、外部 API)。粗暴量化时,团队内部可以用「单次请求额外延迟 × QPS × 用户容忍度」和「错答一次的平均损失(含品牌、工单、退款)」做一张表,决定是否在某一环上 Critic。
| 值得加重验证 | 可以简化或跳过 |
|---|---|
| 面向用户的最终答复 | 纯内部中间草稿、探索性 brainstorming |
| 会触发自动化执行(下单、改库、发邮件) | 低风险只读查询(且已注明) |
| 合规与品牌敏感行业 | 已有人工终审且量极小 |
工程上常见折中:异步重验证——先给用户一个「已受理」版本,后台再跑完整验证链,不通过则推送更正或撤回。适合允许最终一致的客服、文档类场景;对实时交易则要同步挡在执行前。
先看定义:把验证预算花在「一旦错了代价高」的节点上;在流水线内部用轻量格式检查兜底,避免处处上全套 Critic。
核心概念速查
| 概念 | 一句话 |
|---|---|
| Verification Chain | 格式 → 逻辑 → 事实 → 安全,分层门禁、失败短路 |
| Critic Agent | 专责评判 Worker 输出,Generator–Verifier 解耦 |
| Formal Verification(代码) | 测试 + 静态分析 + 类型检查,客观成败标准 |
| Factual Verification | 断言可追溯、RAG 交叉检查、数值用工具算 |
| Constitutional AI | 原则列表 + 自我审查 + 修正,对齐产品红线 |
| Guardrail | 入站 / 出站策略与分类器,与任务正确性验证互补 |
本篇结构(按需跳转)
| 章节 | 内容 |
|---|---|
| §1 | Reflection 与 Verification 区分 |
| §2 | Verification Chain 四步与短路 |
| §3 | Critic、Generator–Verifier、投票 |
| §4 | 代码形式化验证与 SWE-bench |
| §5 | 事实性验证与 RAG |
| §6 | Constitutional AI |
| §7 | Guardrail 与 verification 分工 |
| §8 | 成本与异步策略 |
延伸阅读
- Reflexion: Language Agents with Verbal Reinforcement Learning —— 反思与评估循环的经典论文,可与本篇「验证」对照阅读
- LangGraph 文档 —— 状态机与条件边,适合落地 Critic 重试图
- SWE-bench —— 软件工程 Agent 基准,强调测试驱动验证
- Constitutional AI: Harmlessness from AI Feedback —— Constitutional AI 的代表性论文,可与本节的“原则列表 + 自我审查”对照阅读
- NVIDIA NeMo Guardrails —— 可编程护栏与对话流编排
- Llama Guard(Meta AI 研究发布页) —— 输入输出安全分类示例
一句话收束:Self-Verification 把 Agent 从「听起来对」推向「查得证、验得过、放得行」;与第 05 篇的反思合在一起,才是完整的自我改进闭环。