Self-Verification
Self-Verification(Weng et al., 2022)是什么
Self-Verification(自我验证)是一类“先生成多个带CoT的候选解 → 再用验证信号给候选解打分 → 选最好”的方法。它想解决的问题是:单次CoT生成可能会“走错路”,但如果一次生成多条不同推理路径,其中往往有一条是对的;关键在于怎么自动识别更可能正确的那条。
Weng 等人在论文里的核心做法是用一种“遮挡预测(masking)式一致性检验”来给每条候选解打分:
- 生成候选解:对同一问题,用 CoT 方式采样出多条候选方案(不同温度/不同采样种子),得到 [S1, S2, …, Sk]。
- 构造验证任务:把原题 Q 的某些关键信息遮挡(例如一个数字、一个条件、一个实体、一个中间量),得到 Q_mask。
- 基于“其余题干 + 候选解Si”去预测被遮挡内容:再问模型:在看到 Q_mask 和 Si 的情况下,被遮挡的部分应该是什么?
- 打分:如果候选解 Si 能“解释/推导”出被遮挡部分,使模型预测与原题一致,则给更高分。对多个mask重复,累计得分。
- 选择或融合:选得分最高的候选解作为最终答案(或做加权投票/重写)。
直观理解:
- 好的解答应该与题目条件高度一致,能“反推出题目里被遮住的关键条件”。
- 差的解答往往隐含错条件/漏条件/瞎编中间量,导致在遮挡预测时“对不上”。
它与 Self-Consistency(多样本投票)很像,但 Self-Verification 多了“验证打分器”:不是看最终答案多数票,而是看每条推理对题干的一致性支撑力度。
适合的应用场景
- 结构化推理题/数学应用题/逻辑题
- 题干包含多个明确条件(数字、关系、约束),适合遮挡检查。
- 有明确可验证“题干要素”的任务
- 比如:行程规划里“出发时间/预算/人数”等可遮挡字段;
- 规则推断题里“某条规则/限制条件”。
- 需要提高正确率、允许多次推理成本的场景
- 离线批处理、评测、对高价值请求做“高成本高可靠”模式。
- 作为路由器前的质量筛选
- 得分低:触发检索(RAG)/工具计算/人工复核;
- 得分高:直接输出。
不适合的应用场景(或收益较小)
- 纯开放式生成
- 写诗、故事、脑暴没有可遮挡的“唯一正确题干要素”,验证信号弱。
- 题干本身信息不足/含糊
- 题目没给清楚,遮挡预测也很难形成可靠评分。
- 强事实问答但题干没有可推导结构
- “某年诺奖得主是谁”这种不靠题干推导,遮挡预测意义不大(更适合RAG)。
- 延迟/成本严格的在线场景
- 需要生成K条CoT + 多轮mask验证,token成本和延迟都更高。一般要做“只对不确定问题启用”。
怎么写提示词(工程可落地的版本)
你可以把它做成三段式 pipeline:
A) 生成候选解(K条)
- 用相同问题,要求“逐步推理并给最终答案”
- 采样K次(例如K=5~20,视成本)
B) 生成/选择遮挡点(masks)
- 选题干中关键变量/约束做遮挡(数字、比较关系、对象)
- 一般 3~8 个mask 就能提供稳定信号
C) 验证打分(对每个候选解、每个mask)
- 输入:Q_mask + 候选解Si
- 输出:被遮挡内容的预测 + 置信度/理由(用于评分)
- 评分:预测是否与原题一致(完全匹配得1分;允许近似则给部分分)
小技巧:为了减少“看题干猜答案”,可以在验证提示里强调:必须依据候选解Si推导,不要凭常识猜。
实战例子(≥3个,中文,展示写法)
下面给出3套“可直接复制”的提示词链路(你可以在代码里循环调用)。
例子1:数学应用题(遮挡数字条件做验证)
问题Q:
一种彩票每张2元,小王买了若干张,总共花了20元。问他买了多少张?
Step 1:生成K个候选解(同一个Prompt采样多次)
Prompt(Candidate Generation):
请逐步推理并给出最终答案:
问题:一种彩票每张2元,小王买了若干张,总共花了20元。问他买了多少张?
输出要求:
- 写出计算过程
- 最后一行只写“答案:X张”
(用不同随机种子/温度采样得到 S1..Sk)
Step 2:构造mask(遮挡关键数字)
例如遮挡“每张2元”或“总共20元”。
Step 3:对每个候选解做验证
Prompt(Verification 1:遮挡单价):
你将看到一个“被遮挡的题目”和一个“候选解”。
请仅根据候选解中的推理与计算,推断题目中被遮挡的内容应该是什么。不要凭空猜测。被遮挡题目:一种彩票每张[MASK]元,小王买了若干张,总共花了20元。问他买了多少张?
候选解:
{粘贴某个Si}请输出:
- 预测的[MASK]:__
- 置信度:0-100
- 依据:引用候选解中的关键算式/句子(1-2条)
Prompt(Verification 2:遮挡总价):
被遮挡题目:一种彩票每张2元,小王买了若干张,总共花了[MASK]元。问他买了多少张?
候选解:{Si}
输出同上。
评分方法(工程实现):
- 预测MASK等于原题数值 → 通过;否则失败。
- 每通过一个mask记1分,累计得到 score(Si)。
- 选分最高的Si输出其最终答案。
例子2:逻辑/规则题(遮挡约束检查“有没有偷换条件”)
问题Q:
会议室预订规则:每次预订时长最多2小时;同一团队每天最多预订2次。A团队今天已经预订了2次,每次2小时。现在还能再预订1小时吗?
Step 1:生成候选解(K条)
Prompt:
请根据规则逐步推理并回答“能/不能”,并用一句话说明原因:
规则:每次预订最多2小时;同一团队每天最多预订2次。
问题:A团队今天已经预订了2次,每次2小时。现在还能再预订1小时吗?
输出格式:
结论:能/不能
原因:……
Step 2:遮挡关键条件做验证
遮挡“每天最多预订2次” 或 “已经预订了2次”。
Step 3:验证Prompt(示例:遮挡每天次数上限)
被遮挡题目:
会议室预订规则:每次预订时长最多2小时;同一团队每天最多预订[MASK]次。A团队今天已经预订了2次,每次2小时。现在还能再预订1小时吗?候选解:{Si}
请输出:
- 预测的[MASK]:__
- 置信度:0-100
- 依据:候选解中哪些推理必须依赖这个上限?
如果某个Si其实只基于“每次最多2小时”在推理,而忽略“每天次数上限”,它在这里往往会露出矛盾(预测不出MASK或乱猜),得分更低。
例子3:代码题(遮挡规格、验证解答是否真的满足要求)
问题Q:
写一个函数:输入整数数组,返回其中出现次数最多的元素;若并列,返回最小的那个。要求时间复杂度O(n)。
Step 1:生成多份候选代码(K份)
Prompt:
用Python写函数 most_freq_min(nums)。
需求:返回出现次数最多的元素;若并列,返回最小的那个;时间复杂度O(n)。
输出:代码 + 复杂度说明 + 3个示例。
Step 2:遮挡题干关键要求
例如遮挡“若并列返回最小”或“O(n)”。
Step 3:验证(遮挡并列规则)
Verification Prompt:
下面是一个被遮挡的需求说明Q_mask和一份候选实现A。请根据候选实现A推断被遮挡的规则应该是什么。
Q_mask:返回出现次数最多的元素;若出现次数并列,返回[MASK];时间复杂度O(n)。
候选实现A:
{粘贴候选代码Si}输出:
- 预测[MASK]:__
- 置信度:0-100
- 依据:指出代码中体现该规则的具体位置(例如比较逻辑/排序/条件分支)
如果某个实现偷偷用了排序(O(n log n))或在并列时返回了“第一个出现的”,它的重构MASK往往对不上,从而被扣分。
落地建议(简洁但关键)
- K不要盲目大:常用 K=5~10 起步;再用mask验证筛选。
- mask要选“决定性条件”:越关键越能区分好坏解(数字、上限、并列规则、边界条件)。
- 验证提示要“强制基于候选解”:否则模型可能直接从题干猜MASK,降低区分度。
- 把评分字段化:例如输出
{"pred":..., "confidence":..., "evidence":...}方便自动打分。 - 与RAG/工具结合:对事实题,mask验证弱,应该走检索或外部校验。
如果你给我一个你正在做的具体任务(比如:数学题批改、业务规则问答、代码生成、合规文本生成),我可以帮你设计:
- 该任务最有效的mask策略(遮挡哪些字段)
- K和mask次数的推荐范围
- 可直接用于工程的JSON输出与打分规则。