提示工程 | | 约 18 分钟 | 6,880 字

自一致性提示 (Self-Consistency)

通过多次采样和投票机制提升推理准确性

什么是 Self-Consistency

我们在前面学过 Chain-of-Thought(CoT),它让 AI 一步步推理。但有个问题:同一个问题,AI 每次推理的路径可能不同,答案也可能不同。

Self-Consistency 的核心思想很简单:让 AI 推理多次,然后对结果投票,选出最一致的答案

就像考试时你不确定一道题的答案,于是用三种不同方法解题,如果三种方法中有两种得出相同答案,那个答案大概率是对的。


为什么 CoT 还不够

单次 CoT 推理有一个根本性问题:推理路径的随机性

问题:一个商店有 23 个苹果,卖掉了一些后还剩 7 个,又进货了 12 个,现在有多少个?

路径 A(正确):23 - 16 + 12 = 19 ✓
路径 B(错误):23 - 7 = 16, 16 + 12 = 28 ✗(误解题意)
路径 C(正确):剩 7 个 + 进货 12 个 = 19 ✓

如果我们只采样一次,有可能恰好走到路径 B。但如果采样三次,投票结果是 19(2票)vs 28(1票),正确答案胜出。


Self-Consistency 的工作流程

整个流程分为三步:

第一步:多次采样

对同一个问题,使用较高的 temperature 生成多条推理路径:

采样 1 → 推理路径 A → 答案: 19
采样 2 → 推理路径 B → 答案: 28
采样 3 → 推理路径 C → 答案: 19
采样 4 → 推理路径 D → 答案: 19
采样 5 → 推理路径 E → 答案: 28

第二步:提取答案

从每条推理路径中提取最终答案:

采样编号推理路径最终答案
1先算卖掉的数量…19
2用总数减去剩余…28
3从剩余开始算…19
4列方程求解…19
5分步计算…28

第三步:多数投票

答案 19:3 票 ✓(胜出)
答案 28:2 票

最终输出答案 19。


API 实现:temperature 和 top_p

Self-Consistency 的关键在于采样多样性。我们需要调整 API 参数让每次生成的推理路径不同。

基础实现

import anthropic
from collections import Counter

client = anthropic.Anthropic()

def self_consistency(question: str, num_samples: int = 5) -> str:
    """使用 Self-Consistency 方法回答问题"""

    prompt = f"""请一步步思考以下问题,展示完整推理过程,最后用 "最终答案:" 开头给出答案。

问题:{question}"""

    answers = []

    for i in range(num_samples):
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            temperature=0.7,  # 关键:较高的 temperature 增加多样性
            messages=[{"role": "user", "content": prompt}]
        )

        text = response.content[0].text
        # 提取最终答案
        answer = extract_answer(text)
        answers.append(answer)
        print(f"采样 {i+1}: {answer}")

    # 多数投票
    counter = Counter(answers)
    best_answer = counter.most_common(1)[0][0]
    confidence = counter[best_answer] / len(answers)

    print(f"\n投票结果: {dict(counter)}")
    print(f"最终答案: {best_answer} (置信度: {confidence:.0%})")

    return best_answer

def extract_answer(text: str) -> str:
    """从推理文本中提取最终答案"""
    for line in text.split('\n'):
        if '最终答案' in line or '答案是' in line or '答案:' in line:
            return line.split(':')[-1].strip().split('。')[0].strip()
    # 如果没找到标记,返回最后一行
    return text.strip().split('\n')[-1].strip()

temperature vs top_p

这两个参数都影响采样多样性,但方式不同:

参数作用Self-Consistency 推荐值
temperature控制输出的随机性,值越高越随机0.5 - 0.8
top_p控制候选 token 的范围0.9 - 0.95
# 方式一:调整 temperature(推荐)
response = client.messages.create(
    model="claude-sonnet-4-20250514",
    temperature=0.7,
    # ...
)

# 方式二:调整 top_p
response = client.messages.create(
    model="claude-sonnet-4-20250514",
    top_p=0.9,
    # ...
)

一般来说,调整 temperature 就够了。temperature 太低(< 0.3)会导致每次采样结果几乎相同,失去 Self-Consistency 的意义;太高(> 1.0)会导致推理质量下降。


进阶:加权投票

简单的多数投票把每条路径视为等权。但实际上,有些推理路径更可靠。我们可以根据推理质量加权:

def weighted_self_consistency(question: str, num_samples: int = 7) -> str:
    """加权 Self-Consistency"""

    prompt = f"""请一步步思考以下问题。
要求:
1. 展示完整推理过程
2. 每一步都要验证
3. 最后用 "最终答案:" 给出答案
4. 用 "置信度:" 给出你对答案的信心(高/中/低)

问题:{question}"""

    results = []

    for i in range(num_samples):
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            temperature=0.7,
            messages=[{"role": "user", "content": prompt}]
        )

        text = response.content[0].text
        answer = extract_answer(text)
        confidence = extract_confidence(text)

        # 置信度映射为权重
        weight_map = {"高": 3, "中": 2, "低": 1}
        weight = weight_map.get(confidence, 1)

        results.append({"answer": answer, "weight": weight})

    # 加权投票
    weighted_votes = {}
    for r in results:
        weighted_votes[r["answer"]] = weighted_votes.get(r["answer"], 0) + r["weight"]

    best_answer = max(weighted_votes, key=weighted_votes.get)
    return best_answer

实战案例:代码逻辑判断

Self-Consistency 在代码相关的推理中特别有用。来看一个例子:

question = """
以下 Python 代码的输出是什么?

x = [1, 2, 3, 4, 5]
y = x[1:4]
y[0] = 99
print(x)
print(y)
"""

# 采样 5 次的结果可能是:
# 采样 1: x=[1,2,3,4,5], y=[99,3,4]  → 正确(切片创建新列表)
# 采样 2: x=[1,99,3,4,5], y=[99,3,4] → 错误(误以为是引用)
# 采样 3: x=[1,2,3,4,5], y=[99,3,4]  → 正确
# 采样 4: x=[1,2,3,4,5], y=[99,3,4]  → 正确
# 采样 5: x=[1,2,3,4,5], y=[99,3,4]  → 正确

# 投票:正确答案 4:1 胜出

什么时候 Self-Consistency 特别有效

场景效果原因
数学推理很好答案唯一,投票容易收敛
逻辑推理很好多条路径可以交叉验证
代码输出预测答案明确,容易比较
常识推理一般答案可能有多种合理表述
开放式问题不适用没有唯一正确答案

成本与准确性的权衡

Self-Consistency 的代价是成本线性增长。采样 N 次意味着 N 倍的 API 调用费用。

采样次数 vs 准确率提升

根据论文和实践经验,准确率提升呈递减趋势:

采样次数    准确率提升(相对单次 CoT)
1           基线
3           +5% ~ +10%
5           +8% ~ +15%
10          +10% ~ +18%
20          +12% ~ +20%
40          +13% ~ +21%(边际收益很小)

实用建议

def smart_self_consistency(question: str, budget: str = "medium") -> str:
    """根据预算选择采样次数"""

    sample_config = {
        "low": 3,      # 低预算:3 次采样,成本 3x
        "medium": 5,    # 中预算:5 次采样,成本 5x(推荐)
        "high": 10,     # 高预算:10 次采样,成本 10x
    }

    num_samples = sample_config[budget]
    return self_consistency(question, num_samples)

经验法则:5 次采样是性价比最高的选择。3 次太少(2:1 的投票不够稳定),10 次以上边际收益递减。


与其他技巧的组合

Self-Consistency + Few-Shot CoT

prompt = """以下是一些推理示例:

问题:小明有 10 元,买了 3 元的笔,还剩多少?
推理:10 - 3 = 7
答案:7 元

问题:{actual_question}
推理:"""

先用 Few-Shot 提高单次推理质量,再用 Self-Consistency 提高整体准确性。这是目前效果最好的组合之一。

Self-Consistency + 角色扮演

roles = [
    "你是一个数学教授",
    "你是一个工程师",
    "你是一个逻辑学家",
]

# 每次采样使用不同角色,增加推理路径的多样性
for role in roles:
    prompt = f"{role},请一步步解决以下问题:\n{question}"
    # ...

不同角色会倾向于使用不同的推理方法,天然增加了路径多样性。


常见问题

Q:所有采样结果都一样怎么办?

说明 temperature 太低,或者问题太简单不需要 Self-Consistency。把 temperature 调到 0.7 以上试试。

Q:投票结果是平票怎么办?

两种处理方式:

  1. 增加采样次数(用奇数次采样可以避免)
  2. 选择推理步骤更详细的那个答案

Q:对于非数值答案怎么投票?

需要做答案归一化。比如 “19个”、“19”、“十九” 应该视为同一个答案:

import re

def normalize_answer(answer: str) -> str:
    """归一化答案用于比较"""
    # 去除单位和标点
    answer = re.sub(r'[个元只条件份]', '', answer)
    answer = answer.strip('。,、')

    # 中文数字转阿拉伯数字
    cn_num = {'零':0, '一':1, '二':2, '三':3, '四':4,
              '五':5, '六':6, '七':7, '八':8, '九':9, '十':10}
    for cn, num in cn_num.items():
        answer = answer.replace(cn, str(num))

    return answer.strip()

总结

维度说明
核心思想多次采样 + 多数投票
适用场景有唯一正确答案的推理问题
推荐采样次数5 次(性价比最高)
temperature0.5 - 0.8
成本N 倍于单次调用
与 CoT 的关系是 CoT 的增强版,不是替代品

Self-Consistency 是目前提升 LLM 推理准确性最简单有效的方法之一。它不需要修改 Prompt,不需要微调模型,只需要多调几次 API 然后投票。

一个人可能会犯错,但一群人同时犯同样的错,概率就小得多。Self-Consistency 就是让 AI 成为”一群人”。

评论

加载中...

相关文章

分享:

评论

加载中...