引言

大语言模型在推理任务上的一个痛点是:同一个问题,稍微不同的提问方式或不同的推理路径可能得到不同答案,而且模型本身无法判断哪个答案更可靠。Self-Consistency(自我一致性)技巧通过生成多条推理路径并投票选择最一致的答案,有效解决了这一问题。本文详细介绍该技巧的原理、实现和优化策略。

核心原理

从集成学习借鉴的思想

Self-Consistency的思想来自机器学习中的集成方法:多个独立"专家"的投票结果通常比单个专家的判断更可靠。在CoT场景中,通过使用较高的温度参数生成多条不同的推理链,每条链代表一个独立的"推理专家",然后对最终答案进行投票。

为什么有效

Self-Consistency有效的前提是:正确答案在多条推理路径中出现的频率高于任何单一错误答案。这是因为正确的推理路径更有可能收敛到同一答案,而错误路径往往各不相同(随机错误的多样性)。因此,投票自然地过滤掉了偶发错误。

数学上,假设正确答案的概率为p,共有N条推理链。如果各链独立,则正确答案获得最多票数的概率随N增大而趋近于1。即使推理链之间不完全独立,Self-Consistency仍能显著提升准确率。

基础实现

标准流程

from collections import Counter

def self_consistency(model, prompt, n_samples=5, temperature=0.7):
    """
    Self-Consistency推理
    
    Args:
        model: 语言模型接口
        prompt: 包含CoT触发词的prompt
        n_samples: 采样数量
        temperature: 温度参数(建议0.5-1.0)
    Returns:
        最一致的答案及其置信度
    """
    answers = []
    reasoning_chains = []
    
    for i in range(n_samples):
        response = model.generate(
            prompt + "\n\nLet's think step by step.",
            temperature=temperature,
            top_p=0.95
        )
        answer = extract_final_answer(response)
        answers.append(answer)
        reasoning_chains.append(response)
    
    # 投票
    counter = Counter(answers)
    best_answer, count = counter.most_common(1)[0]
    confidence = count / n_samples
    
    return {
        "answer": best_answer,
        "confidence": confidence,
        "all_answers": answers,
        "reasoning_chains": reasoning_chains
    }

def extract_final_answer(response):
    """从推理链中提取最终答案"""
    # 方法1:正则匹配
    import re
    match = re.search(r'(?:答案|Answer|answer)[::\s]*(.+?)(?:\n|$)', response)
    if match:
        return match.group(1).strip()
    
    # 方法2:取最后一行
    lines = [l.strip() for l in response.strip().split('\n') if l.strip()]
    return lines[-1] if lines else response

参数选择

采样数量N:N越大效果越好但成本越高。研究表明,N=5-10在大多数任务上已能获得显著提升,N=20-40在高难度任务上仍有边际收益。建议从N=5开始,根据任务难度和预算调整。

温度参数:温度过低导致推理链过于相似(失去多样性),温度过高导致推理质量下降。推荐范围0.5-0.8。数学推理建议0.7,常识推理建议0.5。

高级优化策略

自适应采样

固定采样数量可能在简单问题上浪费资源,在困难问题上又不够。自适应采样策略:

def adaptive_self_consistency(model, prompt, 
                                min_samples=3, max_samples=15,
                                confidence_threshold=0.8):
    """自适应采样:达到置信度阈值或最大采样数时停止"""
    answers = []
    
    for i in range(max_samples):
        response = model.generate(
            prompt + "\n\nLet's think step by step.",
            temperature=0.7
        )
        answer = extract_final_answer(response)
        answers.append(answer)
        
        # 达到最小采样数后检查置信度
        if i >= min_samples - 1:
            counter = Counter(answers)
            best_count = counter.most_common(1)[0][1]
            confidence = best_count / len(answers)
            
            if confidence >= confidence_threshold:
                break
    
    counter = Counter(answers)
    best_answer, count = counter.most_common(1)[0]
    return best_answer, count / len(answers)

加权投票

不同推理链的质量可能不同,简单多数投票可能不是最优的。加权投票策略:

基于推理链长度的权重:过长的推理链可能包含错误累积,过短的可能是草率推理。中等长度的推理链赋予更高权重。

基于自评分数的权重:让模型评估自己推理链的质量:

def weighted_self_consistency(model, prompt, n_samples=5):
    chains = []
    
    for i in range(n_samples):
        response = model.generate(prompt, temperature=0.7)
        
        # 自评
        eval_prompt = f"请评估以下推理过程的质量,给出1-10的评分:\n\n{response}"
        score = float(model.generate(eval_prompt, temperature=0.0))
        
        answer = extract_final_answer(response)
        chains.append({"answer": answer, "weight": score, "reasoning": response})
    
    # 加权投票
    weighted_votes = {}
    for chain in chains:
        ans = chain["answer"]
        weighted_votes[ans] = weighted_votes.get(ans, 0) + chain["weight"]
    
    best_answer = max(weighted_votes, key=weighted_votes.get)
    return best_answer

推理链聚类

当答案不是简单的离散值时(如开放性问答),直接投票不可行。此时可对推理链进行聚类:

  1. 对所有推理链生成嵌入向量
  2. 使用聚类算法(如K-Means)将相似推理链分组
  3. 选择最大簇的代表答案

适用场景分析

高收益场景

  • 数学推理:有明确答案,投票效果显著
  • 逻辑推理:正确推理路径收敛,错误路径发散
  • 选择题:离散选项天然适合投票
  • 事实问答:事实性问题有唯一正确答案

低收益场景

  • 开放式生成:没有唯一正确答案,投票意义不大
  • 创意写作:多样性是目标而非缺陷
  • 翻译任务:正确翻译可能有多种,但投票难以处理
  • 简单任务:单次推理已足够准确,额外采样浪费资源

成本优化

级联策略

先用低成本模型推理,仅在不确定时启用Self-Consistency:

def cascaded_inference(model_small, model_large, prompt):
    # 第一步:用小模型快速推理
    answer = model_small.generate(prompt, temperature=0.0)
    confidence = estimate_confidence(answer)
    
    if confidence > 0.9:
        return answer
    
    # 第二步:不确定时用大模型Self-Consistency
    return self_consistency(model_large, prompt, n_samples=5)

缓存与复用

对相同或相似问题的Self-Consistency结果进行缓存,避免重复计算。

结语

Self-Consistency是提升推理可靠性的简洁而有效的方法。它不需要额外的训练或模型修改,仅通过多采样和投票就能显著提升准确率。关键在于根据任务特点选择合适的采样数量、温度参数和投票策略。在需要高可靠性的推理场景中,Self-Consistency应作为标准配置。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。