提示技术系列(四)——自我一致性

什么是提示技术?

        提示技术是实现提示工程目标的具体技术手段,是提示工程中的“工具库”

什么又是提示工程?

        提示工程是指通过设计、优化和迭代输入到大语言模型(LLM)的提示(Prompt),系统性提升模型输出质量(如相关性、准确性、可控性)的实践领域。它是一个覆盖全流程方法论,包括:

  • 明确目标任务(如生成教学内容、问答、翻译);
  • 设计提示结构(如指令、上下文、示例);
  • 选择模型与参数(如温度、top_p);
  • 验证与迭代(根据输出调整提示)。

其核心是“通过工程化方法控制大语言模型(LLM)的行为”


概念

        自我一致性是一种改进链式思维(CoT)提示的提示技术,通过生成多条推理路径选择最一致的答案来提升模型在复杂任务中的准确性

自我一致性旨在:改进链式思维(CoT)提示中使用的贪婪解码

(贪婪解码是一种局部最优的生成策略,模型在每一步解码时只选择当前概率最高的词元(token),并基于该选择继续生成后续内容。)

核心思想:

  • 多路径探索:同一问题可通过不同推理路径解决,模型应尝试多种可能性;

  • 答案聚合:统计多条路径的最终答案,选择出现频率最高的结果(多数投票)。

概念图解

CoT 与 自我一致性提示的图解比较:

应用场景

        自我一致性提示,核心在于​​利用模型随机性探索多种推理路径​​,适用于需要高精度、低容错率的场景。

  1. 医学诊断与决策支持;
  2. 推理与算术问题;
  3. 教育评估与儿童发展分析;
  4. ……

案例实操

医学诊断与决策支持

prompt:

你是一名急诊科医生。请根据以下症状判断可能的疾病:
患者,男性,58 岁,出现胸痛、胸闷和出汗。
提供最可能的诊断及简要依据。格式:【诊断】、【依据】。
请多次分析,生成 3 次独立答案,最终选择最一致的诊断。

运行结果如下:

推理与算术问题

prompt:

“当我6岁时,弟弟是我的一半年龄。现在我45岁,弟弟多大?”
生成3种可能的推理路径,选择最一致的答案。  

运行结果如下:

教育评估与儿童发展分析​

prompt:

小明(5岁)能流利表达需求,但较少主动与同龄人交流,对声音敏感。
请从认知、社交、感觉统合角度分析小明的发展特点,生成5次独立评估后选择最一致结论。 

运行结果如下:

代码实现自我一致性提示

技术栈:Python;LangChain。

文件引用包及版本信息:

pip install langchain_deepseek==0.1.3;

pip install langchain_core==0.3.66;

具体代码如下:

import os
import re
from collections import Counter

from dotenv import load_dotenv
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_deepseek import ChatDeepSeek

# 加载环境变量
load_dotenv()
api_key = os.getenv("DEEPSEEK_API_KEY")

# 初始化DeepSeek模型
llm = ChatDeepSeek(
    model="deepseek-chat",
    temperature=0.7,
    api_key=api_key
)

# 定义提示模板
system_prompt = """
你必须生成包含3种解法的JSON,格式如下:
{{
  "solutions": [
    {{"method": "方法1", "answer": "答案1"}},
    {{"method": "方法2", "answer": "答案2"}},
    {{"method": "方法3", "answer": "答案3"}}
  ]
}}
"""

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "问题:{question}")
])

# 构建LCEL链
chain = (
        RunnablePassthrough.assign(question=lambda x: x["question"])
        | prompt
        | llm
        | StrOutputParser()
)


# 生成多样化解法 (batch_times 控制 LLM 调用次数,一次会生成3种不同的解法)
def generate_solutions(q: str, batch_times=1) -> list:
    solutions = []
    for _ in range(batch_times):
        response = None
        try:
            response = chain.invoke({"question": q})
            if not response.strip():  # 检查空响应
                raise ValueError("响应为空")
            output_parser = JsonOutputParser()
            data = output_parser.invoke(response)
            solutions.extend(data.get("solutions", []))
        except Exception as e:
            print(f"解析失败:{str(e)},响应内容:{response[:100] if response else '无响应'}...")
            continue
    return solutions


# 自我一致性投票
def self_consistency_vote(q: str):
    solutions = generate_solutions(q)
    print("self_consistency_vote param ----------- ", solutions)
    if not solutions:  # 检查是否有候选解法
        print("未生成任何候选解法,请检查提示模板或模型输出。")
        return {
            "question": q,
            "final_answer": None,
            "confidence": "0%",
            "solutions": []
        }

    # 从answer中提取纯数字
    def extract_num(answer):
        num = re.findall(r'\d+', answer)
        return num[-1] if num else answer  # 取最后一个数字

    print("\n候选解法:")
    # print(solutions)
    for i, sol in enumerate(solutions, 1):
        print(f"{i}. {sol['method']} → {sol['answer']}")

    answers = [extract_num(sol["answer"]) for sol in solutions]
    if not answers:  # 检查答案列表是否为空
        print("未生成任何答案,请检查模型输出。")
        return {
            "question": q,
            "final_answer": None,
            "confidence": "0%",
            "solutions": solutions
        }

    final_answer = Counter(answers).most_common(1)[0][0]
    confidence = answers.count(final_answer) / len(answers)

    return {
        "question": q,
        "final_answer": final_answer,
        "confidence": f"{confidence:.0%}",
        "solutions": solutions
    }


# 测试案例
if __name__ == "__main__":
    question = "停车场原有6辆车,先离开2辆又新增5辆,最后剩多少车?"
    print("正在处理问题,请稍候...")
    result = self_consistency_vote(question)

    print("\n" + "=" * 50)
    print(f"问题: {result['question']}")
    print(f"最终答案: {result['final_answer']} (置信度: {result['confidence']})")
    print("=" * 50)

总结与思考

        既然说自我一致性是改进链式思维(CoT)提示中使用的贪婪解码,那么它们之间的定义和原理不得对比分析一下?

维度

链式思考(CoT)

自我一致性(Self-Consistency)

核心思想

通过单次生成多步骤推理链,模拟人类分步思考过程,提升复杂问题的解决能力。

在CoT基础上,多次生成不同推理路径,通过聚合(如投票)选择最一致的答案,降低随机性影响。

推理机制

单路径生成:模型按单一逻辑链推导答案。

多路径生成:模型生成多条独立推理链,最终选择多数一致或置信度最高的答案。

数学基础

依赖单次生成的概率分布(如贪婪解码)。

基于概率集成(如多数投票、置信度加权)。

知道了它们各自的原理,在不同的任务处理过程中,选择合适的提示技术,或者是混合使用它们:

  • CoT作为基础:在自我一致性中,首次生成路径通常使用CoT提示,确保推理逻辑的合理性
  • 动态切换策略:简单任务使用CoT(节省资源),复杂任务切换至自我一致性(提升准确性)。

OK,到此结束。



提示技术系列,接下来分享:生成知识提示;链式提示(Prompt Chaining);思维树(ToT);自动提示工程师(APE);主动提示(Active-Prompt);方向性刺激提示等等

为了方便大家学习,这里给出专栏链接:https://blog.csdn.net/quf2zy/category_12995183.html

希望能和大家一起学习与交流……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值