Skip to content

提示词模板(Prompts)

LangChain V1.x


1、什么是提示词模板

在大模型应用开发中,我们通常需要根据不同的用户输入来构造不同的Prompt。如果每次都手动拼接字符串,不仅代码冗余,还容易出错。提示词模板(Prompt Template)的核心思想是将Prompt中的固定部分与可变部分分离,通过定义模板 + 传入变量的方式,动态生成最终的Prompt。

核心价值

优势说明
复用性一次定义模板,多次使用不同参数
参数化支持变量插值和动态内容生成
标准化统一管理所有提示词,便于维护和版本控制
优化友好独立的模板便于A/B测试和提示词工程

2、提示词模板类型概览

LangChain围绕不同的使用场景,提供了多种提示模板类型。在学习具体类型之前,先从全局视角了解它们的定位:

下面我们按照从简单到复杂的顺序,逐一讲解每种模板。

3、提示词模板工作原理

在深入各类模板之前,先理解它们的统一工作原理。所有提示词模板都遵循相同的处理流程:

变量值 → PromptTemplate → PromptValue → 聊天模型 / LLM

工作流程

  1. 输入:传入变量值(通常以字典形式,如 {"topic": "AI"};若变量已通过partial预先填充,可不传)
  2. 格式化:模板将变量值插入到预定义的占位符位置
  3. 输出:生成 PromptValue 对象(一种中间格式)
  4. 调用PromptValue 可以自动适配聊天模型(转为消息列表)或LLM(转为字符串)

这种统一的输入输出机制,使得所有模板都可以在LCEL链中无缝使用(LCEL将在后续课件中详细介绍)。

4、PromptTemplate

这是最基础的提示词模板类型,适用于简单的文本生成场景——即字符串提示模板。它接收一个包含占位符的字符串模板,通过传入变量值来生成最终的Prompt。

4.1 基本用法

python
from langchain_core.prompts import PromptTemplate

# 方式一:使用from_template
prompt = PromptTemplate.from_template(
    "讲一个关于{topic}{adjective}故事"
)

# 方式二:使用构造方法
prompt = PromptTemplate(
    template="讲一个关于{topic}{adjective}故事",
    input_variables=["topic", "adjective"]
)

# 调用模板
formatted_prompt = prompt.invoke({"topic": "人工智能", "adjective": "有趣的"})
print(formatted_prompt) # 得到一个PromptValue对象
# 输出: text='讲一个关于人工智能的有趣的故事'

4.2 部分变量

当模板中有些变量的值是固定的或可以提前确定时,可以使用 partial 机制预先填充部分变量,减少后续调用时需要传入的参数数量。

python
# 方式一:调用partial方法固定部分变量
prompt = PromptTemplate.from_template(
    "讲一个关于{topic}{adjective}故事"
)
fixed_prompt = prompt.partial(adjective="有趣的")
print(fixed_prompt.invoke({"topic": "编程"}))
# 输出: text='讲一个关于编程的有趣的故事'

# 方式二:创建时直接指定partial_variables
prompt = PromptTemplate(
    template="请解释{concept},使用{style}风格",
    input_variables=["concept"],
    partial_variables={"style": "简单易懂"}
)
print(prompt.invoke({"concept": "递归"}))
# 输出: text='请解释递归,使用简单易懂风格'

# 再次 partial,覆盖 style
advanced = prompt.partial(style="学术严谨")
print(advanced.invoke({"concept": "递归"}))
# 输出: 用学术严谨解释递归

如何选择?

  • 优先用 partial():当"固定值"是在运行时才确定,或需要分阶段逐步补全时
    • 例:来自配置文件/环境变量/用户选择后再固定;或先固定 style,后续再固定 adjective
    • 优点:更灵活,适合链式构建与复用同一个基础模板。
  • 优先用 partial_variables:当"固定值"在定义模板时就确定,且希望模板对象一创建就自带默认常量时
    • 例:文档里明确规定"统一用简单易懂风格";团队约定的固定前缀/固定语气。
    • 优点:模板更"自描述",一眼能看出哪些变量是固定的,适合沉淀为通用模板。
  • 简单决策表
    • 固定值 是否依赖运行时上下文:是 → partial();否 → partial_variables
    • 是否需要 多次派生不同版本(同一模板固定不同值):是 → partial() 更方便
    • 是否想把"默认值/常量"写死在模板定义处:是 → partial_variables

5、ChatPromptTemplate

PromptTemplate 生成的是一个纯字符串Prompt,而在多轮对话场景中,大模型需要接收的是消息列表(包含角色信息的多条消息)。ChatPromptTemplate——即聊天提示模板——正是为此设计的,它可以构建包含 systemhumanai 等不同角色的消息序列。

5.1 基本用法

python
from langchain_core.prompts import ChatPromptTemplate

# 使用from_messages构造(推荐)
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的{role}。"),
    ("human", "请回答关于{topic}的问题。"),
    ("ai", "好的,我会尽力回答。"),
    ("human", "{question}")
])

# 调用模板,生成消息列表
messages = chat_prompt.invoke({
    "role": "Python编程助手",
    "topic": "Python装饰器",
    "question": "什么是装饰器?"
})
print(messages)

其中,元组的第一个元素是角色标识,第二个元素是消息内容模板。LangChain支持的角色标识包括:

角色标识对应消息类型用途
"system"SystemMessage设定AI的行为规范和角色
"human"HumanMessage用户输入的消息
"ai"AIMessageAI的回复消息

5.2 使用Message对象

除了元组形式,也可以直接使用Message对象来构造模板。两种方式可以混合使用:

python
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

chat_prompt = ChatPromptTemplate.from_messages([
    SystemMessage(content="你是一个有帮助的AI助手"),    # 固定内容用Message对象
    HumanMessage(content="你好!"),                     # 固定内容
    AIMessage(content="你好!有什么可以帮助你的?"),      # 固定内容
    ("human", "请介绍{topic}")                          # 含变量的用元组形式
])

messages = chat_prompt.invoke({"topic": "LangChain"})
print(messages)

选择建议:如果消息内容是固定的(不包含变量),用Message对象更直观;如果内容包含需要填充的变量,用元组形式更简洁。

6、MessagesPlaceholder

在实际的对话应用中,我们往往需要将历史对话记录动态插入到Prompt中。MessagesPlaceholder 允许你在模板中预留一个"插槽",运行时将一个消息列表整体插入到该位置。

这在构建带记忆的对话系统时尤为常用。

MessagesPlaceholder---->BaseMessagePromptTemplate

PromptTemplate-----> StringPromptTemplate---->BasePromptTemplate

ChatPromptTemplate---->BaseChatPromptTemplate---->BasePromptTemplate

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

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是AI助手"),
    MessagesPlaceholder(variable_name="history"),   # 对话历史插槽
    ("human", "{input}")
])

# 调用时传入历史消息列表
messages = prompt.invoke({
    "history": [
        HumanMessage(content="什么是Python?"),
        AIMessage(content="Python是一种通用编程语言。"),
    ],
    "input": "它有什么特点?"
})
print(messages)

注意:history 变量在格式化的时候一定是一个列表类型

也可以使用更简洁的元组语法实现同样的效果:

python
# 等价写法,使用("placeholder", ...)语法
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是AI助手"),
    ("placeholder", "{history}"),    # 等同于MessagesPlaceholder
    ("human", "{input}")
])

7、FewShotPromptTemplate

前面介绍的模板解决了"如何动态构建Prompt"的问题。但在实际应用中,我们经常需要通过提供示例来引导模型理解任务模式——这就是少样本提示模板FewShotPromptTemplate 将示例数据和格式化模板组合在一起,自动生成包含示例的完整Prompt。

7.1 基本用法

python
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

# 第一步:准备示例数据
examples = [
    {"input": "高兴", "output": "开心"},
    {"input": "难过", "output": "悲伤"},
    {"input": "生气", "output": "愤怒"}
]

# 第二步:定义单条示例的格式化模板
example_formatter = PromptTemplate(
    template="输入: {input}\n输出: {output}",
    input_variables=["input", "output"]
)

# 第三步:创建少样本提示模板
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_formatter,
    prefix="以下是一些同义词转换的例子:",    # 示例前的说明文字
    suffix="\n输入: {input}\n输出:",         # 示例后的实际问题
    input_variables=["input"]
)

# 调用
print(few_shot_prompt.invoke({"input": "兴奋"}))

生成的Prompt结构为:prefix + 示例1 + 示例2 + ... + suffix

7.2 对接LLM

python
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()
# 第一步:准备示例数据
examples = [
    {"input": "高兴", "output": "开心"},
    {"input": "难过", "output": "悲伤"},
    {"input": "生气", "output": "愤怒"}
]

# 第二步:定义单条示例的格式化模板
example_formatter = PromptTemplate(
    template="输入: {input}\n输出: {output}",
    input_variables=["input", "output"]
)

# 第三步:创建少样本提示模板
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_formatter,
    prefix="以下是一些同义词转换的例子:",  # 示例前的说明文字
    suffix="\n输入: {input}\n输出:",  # 示例后的实际问题
    input_variables=["input"]
)

# 第四步:格式化
prompt_value = few_shot_prompt.invoke({"input": "兴奋"})

# 第五步:定义LLM
llm = ChatOpenAI(model="gpt-4o-mini")

# 第六步:调用
res = llm.invoke(prompt_value)

print(res.content)

# 输出:激动

8、提示词模板最佳实践

实践说明示例
清晰的指令明确告诉模型要做什么"请翻译..." → "将以下文本从中文翻译成英文..."
提供示例使用少样本学习引导模型使用 FewShotPromptTemplate
角色设定使用系统消息设定角色"你是一个有10年经验的Python工程师"
约束条件明确限制和约束"不超过100字"、"只回答与Python相关的问题"

小结:介绍了LangChain提供的各类提示词模板。从简单的 PromptTemplate(字符串模板)到 ChatPromptTemplate(聊天模板),再到 FewShotPromptTemplate(少样本模板),它们解决的核心问题是如何灵活、可维护地构建Prompt。有了结构化的Prompt之后,下一个问题自然是:模型返回的结果如何解析为我们需要的结构化数据?这就是输出解析器要讨论的内容。