AI开发-python-langchain框架(1-5 使用 Few-Shot Prompting 实现多跳推理问答:以历史人物寿命比较为例)

   想让大模型回答问题具有推理步骤如何实现?比如问大模型 李白和白居易谁活得的更久?这个问题,我们期望他按照如下这种格式回答:

问:李白去世时的年龄是多少?
答案:李白去世时61岁。
问:白居易去世时的年龄是多少?
答案:白居易去世时74岁。
所以最终答案是:白居易

首先我们直接问大模型看他如何回答
from langchain_openai import ChatOpenAI
import os
from dotenv import load_dotenv


llm = ChatOpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url=os.getenv("DEEP_URL"),  # Deepseek 的 API 基础地址
    model="deepseek-v3:671b",  # Deepseek 对话模型(可选:deepseek-chat-pro 等高级模型)
    temperature=0.7,  # 温度参数(0-1,越低越稳定)
    max_tokens=1024  # 最大生成 tokens
)

response = llm.invoke('李白和白居易谁活得的更久?')
print(response.content)

 结果如下:

李白和白居易的寿命对比如下:

1. **李白(701年-762年)**  
   - 享年约61岁(虚岁62岁)。  
   - 去世原因:普遍认为是病逝,但也有“醉后捞月溺亡”的民间传说。  

2. **白居易(772年-846年)**  
   - 享年74岁(虚岁75岁),在唐代诗人中属长寿。  
   - 晚年生活:辞官隐居洛阳,笃信佛教,生活闲适。  

**结论**:白居易比李白多活约13年,寿命更长。两人虽同属唐代,但白居易出生时李白已去世10年,二者并无交集。

 那么如何引导大模型按照我们期望的结果输出呢?代码如下:

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
import os

# 定义少样本学习(Few-Shot Learning)中的示例列表
# 每个示例包含一个复杂问题及其结构化的多步推理答案
# 目的是教会模型:面对需要多跳推理的问题时,应如何分解问题、逐步追问并整合答案
examples = [
    {
        "question": "乾隆和曹操谁活得更久?",
        "answer": """
这里是否需要跟进问题:是的。
追问:乾隆去世时几岁?
中间答案:乾隆去世时87岁。
追问:曹操去世时几岁?
中间答案:曹操去世时66岁。
所以最终答案是:乾隆
""",
    },
    {
        "question": "小米手机的创始人什么时候出生?",
        "answer": """
这里是否需要跟进问题:是的。
追问:小米手机的创始人是谁?
中间答案:小米手机 由 雷军 创立。
跟进:雷军什么时候出生?
中间答案:雷军出生于 1969 年 12 月 16 日。
所以最终的答案是:1969 年 12 月 16 日
""",
    },
    {
        "question": "乔治·华盛顿的外祖父是谁?",
        "answer": """
这里是否需要跟进问题:是的。
追问:乔治·华盛顿的母亲是谁?
中间答案:乔治·华盛顿的母亲是玛丽·鲍尔·华盛顿。
追问:玛丽·鲍尔·华盛顿的父亲是谁?
中间答案:玛丽·鲍尔·华盛顿的父亲是约瑟夫·鲍尔。
所以最终答案是:约瑟夫·鲍尔
""",
    },
    {
        "question": "《大白鲨》和《皇家赌场》的导演是同一个国家的吗?",
        "answer": """
这里是否需要跟进问题:是的。
追问:《大白鲨》的导演是谁?
中间答案:《大白鲨》的导演是史蒂文·斯皮尔伯格。
追问:史蒂文·斯皮尔伯格来自哪里?
中间答案:美国。
追问:皇家赌场的导演是谁?
中间答案:《皇家赌场》的导演是马丁·坎贝尔。
跟进:马丁·坎贝尔来自哪里?
中间答案:新西兰。
所以最终的答案是:不会
""",
    },
]

# 定义单个示例的格式模板
# 将每个 example 中的 question 和 answer 按照指定格式拼接
example_prompt = PromptTemplate(
    input_variables=["question", "answer"],  # 声明模板中使用的变量名
    template="Question: {question}\n{answer}"  # 实际的文本模板
)

print('---------')

# 构建完整的少样本提示模板(Few-Shot Prompt Template)
# 该模板会自动将 examples 按 example_prompt 格式拼接,并在末尾追加用户输入的问题
prompt = FewShotPromptTemplate(
    examples=examples,              # 提供的示例列表
    example_prompt=example_prompt,  # 单个示例的格式
    suffix="Question: {input}",     # 用户实际输入问题的位置(占位符为 {input})
    input_variables=["input"],      # 声明整个提示模板接收的输入变量名
)

# 打印生成的完整提示词,用于调试或查看模型实际看到的上下文
print('--------提示词begin--------')
print(prompt.format(input="李白和白居易谁活得的更久?"))
print('--------提示词end--------')


# 配置大语言模型(LLM)参数,使用 DeepSeek 的 API(兼容 OpenAI 接口)
llm = ChatOpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),   # 从环境变量读取 API 密钥(更安全)
    base_url=os.getenv("DEEP_URL"),          # 从环境变量读取 DeepSeek 的 API 基础地址
    model="deepseek-v3:671b",                # 指定使用的模型名称
    temperature=0.7,                         # 控制生成文本的随机性(0~1,值越高越有创造性)
    max_tokens=1024                          # 限制模型最大输出长度(以 token 为单位)
)

# 创建输出解析器,将模型返回的 AIMessage 对象解析为纯字符串
output_parser = StrOutputParser()

# 使用 LangChain 的管道操作符(|)构建处理链:
# 输入 → 提示模板 → 大模型 → 输出解析 → 最终字符串结果
chain = prompt | llm | output_parser

# 调用链式流程,传入用户问题:“李白和白居易谁活得的更久?”
response = chain.invoke({"input": "李白和白居易谁活得的更久?"})

# 打印模型生成的最终回答
print('--------最终回答--------')
print(response)

 --------最终回答--------
这里是否需要跟进问题:是的。
追问:李白去世时几岁?
中间答案:李白去世时61岁。
追问:白居易去世时几岁?
中间答案:白居易去世时75岁。
所以最终答案是:白居易

 

一、核心目标

教会大语言模型(LLM)如何分步思考,解决需要多步推理(Multi-hop Reasoning)的复杂问题

二、关键技术点

1. 少样本提示(Few-Shot Prompting)

  • 概念:在提示词中提供几个“输入-输出”示例,引导模型模仿回答格式和推理逻辑。
  • 作用:无需微调模型,仅通过提示工程(Prompt Engineering)提升复杂任务表现。
  • 实现工具langchain.prompts.few_shot.FewShotPromptTemplate
 

2. 结构化推理模板设计

  • 每个示例包含清晰的推理链条:
    • 判断是否需要追问(“这里是否需要跟进问题:是的。”)
    • 分步提出子问题(“追问:...”)
    • 给出中间答案(“中间答案:...”)
    • 最终整合结论(“所以最终答案是:...”)
  • 目的:让模型学会“先分解问题 → 再逐步求解 → 最后综合答案”的思维模式。
 

3. LangChain 提示模板组合

  • PromptTemplate:定义单个示例的格式(如 "Question: {question}\n{answer}"
  • FewShotPromptTemplate:自动拼接多个示例 + 用户问题,生成完整提示
  • 支持动态插入用户输入(通过 {input} 占位符)
 

4. 大模型调用与安全配置

  • 使用 ChatOpenAI 调用兼容 OpenAI API 的第三方模型(如 DeepSeek)
  • 关键参数
    • temperature=0.7:平衡创造性与稳定性
    • max_tokens=1024:控制输出长度
  • 安全实践:通过 os.getenv() 从环境变量读取 API 密钥,避免硬编码
 

5. 链式处理(Chain)与输出解析

    • 构建数据流管道:
      输入 → 提示模板 → 大模型 → 字符串解析 → 最终结果
    • 使用 | 操作符连接组件(LangChain 的函数式风格)
    • StrOutputParser():将模型返回的结构化消息(如 AIMessage)转为纯文本
到这大家应该感觉到,大模型就是玩提示词(因为大模型本生我们个人是无法左右他的能力,都依赖于大厂,他们发布什么我们用什么),
提示词如何写决定了你AI应用的能力,后面我们会继续玩提示词,敬请期待。

 

posted @ 2026-01-23 10:57  万笑佛  阅读(37)  评论(0)    收藏  举报