在这里插入图片描述

接续我们 LangChain 系列博文内容,本节博文将继续围绕提示词模板的深度使用展开。本博文将深入探讨 MessagePlaceholder 和少量样本示例(Few-Shot Learning)的使用方法。

MessagePlaceholder:动态消息占位符

什么是 MessagePlaceholder?

在实际应用中,我们经常会遇到这样的场景:提示词模板中的消息类型和数量不确定,或者需要在运行时动态插入一系列历史对话。MessagePlaceholder 就是为解决这类问题而设计的,它可以在提示词模板的特定位置插入消息列表。

基础用法

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts.chat import MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage

# 创建包含 MessagePlaceholder 的提示模板
chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你的名字叫{name}"),
    MessagesPlaceholder(variable_name="msgs")
])

# 调用时传入消息列表
prompt_value = chat_prompt_template.invoke(input={
    "name": "小智",
    "msgs": [
        HumanMessage(content="我的问题是1+2*3=?"), 
        AIMessage(content="1+2*3=7")
    ]
})

对话历史管理场景

MessagePlaceholder 在处理多轮对话时特别有用:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "you are a helpful assistant"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{question}")
])

# 传入对话历史
prompt_value = prompt.invoke(input={
    "history": [
        ("human", "what is 5+2?"), 
        ("ai", "5 + 2 is 7")
    ],
    "question": "我刚才问的问题是什么?"
})

这种方式让我们能够轻松管理对话上下文,无需手动拼接消息。


少量样本示例:提升模型表现的关键技术

为什么需要 Few-Shot Learning?

少量样本示例(Few-Shot)是一种简单但强大的技术,通过在提示词中提供少量示例,可以显著提升大模型的性能和输出质量。

相比于零样本(Zero-Shot),Few-Shot 能够:

  • 明确输出格式: 让模型理解期望的输出结构
  • 统一风格: 确保输出符合特定的语言风格
  • 提高准确性: 通过示例引导模型更好地理解任务

在 LangChain 中,常用的三项相关 Few-Shot 方法,与 PromptTemplate 以及 ChatPromptTemplate 结合。本博文剩余内容,将围绕这三种方法展开,提供完整示例与解析。

  • FewShotPromptTemplate
  • FewShotChatMessagePromptTemplate
  • Example Selector(示例选择器)

FewShotPromptTemplate:基础文本场景

FewShotPromptTemplate 适合处理基础的文本生成任务,需要与 PromptTemplate 配合使用。

完整示例

import os
import dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate

# 环境配置
dotenv.load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")

chat_model = ChatOpenAI(model="deepseek-chat")

# 1. 创建示例模板
example_prompt = PromptTemplate.from_template(
    template="input:{input}\n output:{output}",
)

# 2. 提供示例数据
examples = [
    {"input": "北京天气怎么样", "output": "北京市"},
    {"input": "南京下雨吗", "output": "南京市"},
    {"input": "武汉热吗", "output": "武汉市"}
]

# 3. 创建 FewShotPromptTemplate
few_shot_template = FewShotPromptTemplate(
    example_prompt=example_prompt,
    examples=examples,
    suffix="input:{input}\n output:",
    input_variables=["input"]
)

# 4. 使用模板
prompt = few_shot_template.invoke(input={"input": "天津会下雨吗"})
result = chat_model.invoke(prompt)

复杂示例:多变量场景

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate

# 创建包含多个变量的提示模板
prompt_template = PromptTemplate.from_template(
    template="你是一个数学专家,算式:{input} 值:{output} 使用:{description}",
)

examples = [
    {"input": "2+2", "output": "4", "description": "加法运算"},
    {"input": "5-2", "output": "3", "description": "减法运算"}
]

few_shot_prompt_template = FewShotPromptTemplate(
    example_prompt=prompt_template,
    examples=examples,
    suffix="你是一个数学专家,算式:{input} 值:{output}",
    input_variables=["input", "output"]
)

prompt = few_shot_prompt_template.invoke(
    input={"input": "2*5", "output": "10"}
)
result = chat_model.invoke(prompt)

FewShotChatMessagePromptTemplate:对话场景优化

对于聊天对话场景,FewShotChatMessagePromptTemplate 是更好的选择,它专门针对聊天消息格式进行了优化。

完整示例

from langchain_core.prompts import (
    ChatPromptTemplate, 
    FewShotChatMessagePromptTemplate
)

# 1. 创建对话格式的提示模板
prompt_template = ChatPromptTemplate.from_messages([
    ("human", "{input}是多少"),
    ("ai", "{output}")
])

# 2. 提供对话示例
examples = [
    {"input": "2+2", "output": "4"},
    {"input": "2*3", "output": "6"}
]

# 3. 创建 FewShotChatMessagePromptTemplate
few_shot_prompt_template = FewShotChatMessagePromptTemplate(
    example_prompt=prompt_template,
    examples=examples
)

# 4. 组合成完整的提示词
final_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个数学奇才"),
    few_shot_prompt_template,
    ("human", "{input}")
])

prompt = final_prompt.invoke(input={"input": "2+4"})
result = chat_model.invoke(prompt)

如何选择?

  • FewShotPromptTemplate:用于简单的文本输入输出场景
  • FewShotChatMessagePromptTemplate:用于需要保留对话结构的场景

Example Selectors:智能示例选择器

为什么需要示例选择器?

在前面的方法中,无论输入什么问题,都会包含全部示例。但在实际开发中,这可能导致:

  • Token 消耗过大: 所有示例都传递给模型
  • 相关性不足: 某些示例与当前问题无关
  • 效果不佳: 无关示例可能干扰模型判断

Example Selectors 可以根据当前输入,从大量候选示例中智能选择最相关的子集。

三种选择策略

1. 语义相似选择(Semantic Similarity)

通过余弦相似度等方式,选择与输入语义最接近的 k 个示例。

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# 准备示例数据
examples = [
    {"input": "北京天气怎么样", "output": "北京市"},
    {"input": "上海会下雨吗", "output": "上海市"},
    {"input": "广州今天热吗", "output": "广州市"},
    {"input": "深圳的温度是多少", "output": "深圳市"},
]

# 创建语义相似度选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,                           # 候选示例列表
    OpenAIEmbeddings(),                 # 用于生成向量的嵌入模型
    Chroma,                             # 向量数据库类
    k=2                                 # 选择最相似的2个示例
)

# 创建提示模板
example_prompt = PromptTemplate.from_template("input:{input}\n output:{output}")

# 组合成 FewShotPromptTemplate
few_shot_prompt = FewShotPromptTemplate(
    example_selector=example_selector,   # 使用选择器而非固定示例
    example_prompt=example_prompt,
    suffix="input:{input}\n output:",
    input_variables=["input"]
)

# 使用时会自动选择最相关的示例
prompt = few_shot_prompt.invoke(input={"input": "杭州的气候如何"})
result = chat_model.invoke(prompt)

SemanticSimilarityExampleSelector 参数解析:

  • examples:候选示例列表,每个示例是一个字典
  • embeddings:嵌入模型,用于将文本转换为向量(如 OpenAIEmbeddings 中应用 OpenAI Embedding 模型:text-embedding-ada-002
  • vectorstore_cls:向量数据库类,如 Chroma、FAISS
  • k:选择返回的示例数量
  • input_keys:(可选)指定用于计算相似度的输入键

2. 长度选择(Length-Based Selection)

根据输入文本长度选择匹配的示例,适合对响应速度要求高的场景。

from langchain_core.example_selectors import LengthBasedExampleSelector

examples = [
    {"input": "天气", "output": "短问题"},
    {"input": "今天北京的天气怎么样啊", "output": "中等问题"},
    {"input": "能否详细描述一下今天北京的天气情况,包括温度、湿度等", "output": "长问题"}
]

example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=50  # 根据长度限制选择示例
)

3. 最大边际相关选择(MMR)

在保证语义相似的同时,避免选择同质化内容,增加示例多样性。

from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector

example_selector = MaxMarginalRelevanceExampleSelector.from_examples(
    examples,
    OpenAIEmbeddings(),
    Chroma,
    k=2,
    fetch_k=10  # 先获取10个候选,再通过MMR选择2个
)

使用 FAISS 的完整示例

FAISS 是 Facebook 开发的高效向量检索库,特别适合大规模示例场景。

# 安装依赖
# pip install faiss-cpu

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

# 准备示例
examples = [
    {"question": "苹果是什么颜色", "answer": "红色或绿色"},
    {"question": "天空是什么颜色", "answer": "蓝色"},
    {"question": "草地是什么颜色", "answer": "绿色"},
    {"question": "香蕉是什么颜色", "answer": "黄色"},
    {"question": "橙子是什么颜色", "answer": "橙色"},
]

# 创建示例选择器(使用 FAISS)
example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,
    OpenAIEmbeddings(),
    FAISS,
    k=2
)

# 创建提示模板
example_prompt = PromptTemplate(
    input_variables=["question", "answer"],
    template="问题:{question}\n答案:{answer}"
)

# 组合成 FewShotPromptTemplate
few_shot_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="请回答以下问题:",
    suffix="问题:{input}\n答案:",
    input_variables=["input"]
)

# 使用
prompt = few_shot_prompt.invoke(input={"input": "西红柿是什么颜色"})
# 系统会自动选择与"西红柿"最相关的示例(如苹果、橙子)

result = chat_model.invoke(prompt)

最佳实践建议

1. 选择合适的工具

  • 简单任务: 直接使用 FewShotPromptTemplate
  • 对话应用: 使用 FewShotChatMessagePromptTemplate
  • 大量示例: 使用 Example Selectors 动态选择
  • 历史管理: 使用 MessagePlaceholder

2. 优化示例质量

  • 示例要具有代表性和多样性
  • 避免示例之间过于相似
  • 确保示例格式一致
  • 定期更新和维护示例库

3. 控制 Token 消耗

  • 使用 Example Selectors 减少无关示例
  • 根据任务复杂度调整 k 值
  • 考虑使用长度选择器控制总长度

4. 性能与效果平衡

  • 语义相似度选择最准确但计算开销大
  • 长度选择速度快但可能不够精确
  • MMR 在准确性和多样性间取得平衡

总结

LangChain 的提示词工程工具为我们提供了强大而灵活的能力:

  • MessagePlaceholder 解决了动态消息插入的问题
  • FewShotPromptTemplate 系列让少量样本学习变得简单
  • Example Selectors 实现了智能示例选择,优化性能和效果

掌握这些工具,可以帮助我们构建更加智能、高效的大语言模型应用。在实际项目中,建议根据具体场景选择合适的方法,并通过实验不断优化提示词策略。


2025.10.05 G930 北京朝阳

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐