Appearance
LangChain教程 - 8 LangChain提示词模板
下面介绍一下 LangChain 中的提示词模板。
8.1 消息的简写形式
首先先看一下消息的简写形式。
在上一个章节介绍 LangChain 使用 SystemMessage 、HumanMessage 、AIMessage 来创建消息。
消息还可以使用下面的方式进行简写:
python
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
# 初始化聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 构造消息
messages = [
("system", "请用一句话回答"),
("human", "3加5等于多少?"),
("ai", "等于8"),
("human", "再加5等于多少?"),
("ai", "等于13"),
("human", "再加2等于多少?")
]
# 调用模型,通过 stream 方法提问,流式返回
response = model.stream(input = messages)
for chunk in response:
print(chunk.content, end="", flush=True) # end="" 避免换行,flush=True 及时刷新输出- 在消息列表中,使用的是二元元组,使用
system、human、ai作为元组第一个元素,与SystemMessage、HumanMessage、AIMessage对应,后面写的是消息的内容。
8.2 提示词模板
什么是提示词模板,简单来说,提示词模板就是预先定义好的提示词结构,里面可以包含一些占位符,后续根据需要动态填充内容。
举个栗子:
python
# 创建提示词模板
prompt_template = PromptTemplate.from_template("请把:{content},翻译成{language}")
# 传递参数,生成提示词
prompt = prompt_template.format(content="今天天气怎么样?", language="英语")
# 打印提示词
print(prompt) # 请把:今天天气怎么样?,翻译成英语- 首先创建模板,然后给模板传递数据,生成最终的提示词。
为什么要使用提示词模板,我直接用 f-string 拼接不也一样吗?就像这样:
python
prompt = f"请翻译成{language}:{text}"话是这么说,但在真实项目中,情况会复杂很多。使用提示词模板的好处却很多:
结构化管理:当你的提示词变得越来越复杂时,直接拼接字符串会让代码变得一团糟。而使用提示词模板,可以将提示词结构和具体内容分离,更清晰地组织提示词逻辑,方便团队协作和维护;
动态内容处理:提示词模板可以轻松处理动态内容,支持多个变量占位,可以设置默认值,还支持变量类型检查;
复用性强:定义好的模板可以在多个地方重复使用,避免了代码冗余;
易于扩展:当你需要修改提示词时,只需要修改模板本身,而不需要修改所有使用的地方。
最主要的原因是可以加入 LangChain 的执行链,Chain 链后面再讲。
8.3 PromptTemplate
PromptTemplate 是 LangChain 中最基础的提示词模板类,它允许你创建包含占位符的模板,然后动态填充内容。
PromptTemplate 主要用于“单段文本 Prompt” 的场景,不维护历史对话记录,也就是没有 system / human / ai 的角色区分。
换句话说,如果你只是给模型发送 一整段文本提示词,那 PromptTemplate 就非常适合。
下面来看看 LangChain 中 PromptTemplate 如何使用。
首先需要导入 PromptTemplate,然后就是创建模板,然后将参数传递给模板,生成最终的字符串而已:
python
from langchain_ollama import ChatOllama
from langchain.prompts import PromptTemplate
# ----提示词部分
# 创建一个简单的提示词模板
prompt_template = PromptTemplate.from_template("请把:{content},翻译成{language}")
# 使用模板生成提示词
prompt = prompt_template.format(content="今天天气如何?", language="英文")
# 得到完整提示词:提示词: 请把:今天天气如何?,翻译成英文
print("提示词:", prompt)
# ----模型部分
# 1.创建聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 2.调用模型,通过 stream 方法提问,流式返回
response = model.stream(prompt)
for chunk in response:
print(chunk.content, end="", flush=True) # end="" 避免换行,flush=True 及时刷新输出- 上面的代码是在之前调用大语言模型的基础上,添加了提示词模板而已。
- PromptTemplate 可以用于调用大语言模型或聊天模型,都可以。
但是感觉有点脱裤子放屁,直接使用字符串可能更简单,但是使用提示词模板可以加入 LangChain 的执行力链,在 LangChain 里,模板可以和模型“管道式连接”:
python
from langchain_ollama import ChatOllama
from langchain.prompts import PromptTemplate
# ----提示词部分
# 1.创建一个简单的提示词模板
prompt_template = PromptTemplate.from_template("请把:{content},翻译成{language}")
# 2.创建聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 3.使用 | 组成执行链
chain = prompt_template | model
# 4.通知链条执行,直接传入参数执行
response = chain.stream({"content": "你在做什么?", "language": "英文"})
for chunk in response:
print(chunk.content, end="", flush=True) # end="" 避免换行,flush=True 及时刷新输出- 提示词模板可以加入到执行链条,字符串是不行的,后面我们会学习链条。
8.4 ChatPromptTemplate
ChatPromptTemplate 是 LangChain 中专门用于构建聊天消息的模板类,它支持多轮对话,可以包含不同角色的消息。
ChatPromptTemplate 适用于以下场景:
- 多轮对话,需要维护对话历史
- 聊天机器人、客服助手等交互场景
- 当你需要明确区分系统消息、用户消息和助手消息时
1 简单示例
首先,咱们来看一个简单的 ChatPromptTemplate 示例:
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import ChatOllama
# 1. 创建聊天提示词模板
chat_prompt_template = ChatPromptTemplate.from_messages(
[
("system", "你是一个幽默的助手,用简洁的语言回答问题。"),
("human", "{question}")
]
)
# 2. 生成提示词
prompt = chat_prompt_template.format(question="你是谁?")
print("生成的提示词:", prompt)
# 3. 创建聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 4. 调用模型
response = model.stream(prompt)
for chunk in response:
print(chunk.content, end="", flush=True)2 使用 MessagesPlaceholder
对于需要维护对话历史的场景,可以使用 MessagesPlaceholder 来动态注入历史对话:
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_ollama import ChatOllama
# 1. 创建聊天提示词模板,在模板中使用MessagesPlaceholder占位符
chat_prompt_template = ChatPromptTemplate.from_messages(
[
("system", "你是一位专业的健身教练,回答要简单实用。"),
MessagesPlaceholder("history"),
("human", "{question}")
]
)
# 2. 准备历史对话数据
history_data = [
("human", "我想减肥,有什么建议?"),
("ai", "建议控制饮食,并配合每周3次有氧运动。"),
("human", "我平时中午吃米饭可以吗?"),
("ai", "可以,但建议减少分量,多搭配蔬菜和蛋白质。")
]
# 3. 将历史数据注入模板,生成最终提示词
prompt = chat_prompt_template.invoke(
{"history": history_data, "question": "那我晚饭应该怎么吃?"}
)
print("生成的提示词:", prompt.to_string())
# 4. 创建聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 5. 调用模型
response = model.stream(prompt)
for chunk in response:
print(chunk.content, end="", flush=True)- 使用
MessagesPlaceholder可以方便地将历史对话注入到模板中,实现多轮对话的上下文管理。
8.5 format和invoke方法
上面在使用提示词模板时,使用了两种方法来生成提示词:format 和 invoke。
什么区别呢?
PromptTemplate、ChatPromptTemplate 等模板类都直接或间接继承自 BasePromptTemplate , BasePromptTemplate 定义了 format() 方法, BasePromptTemplate 间接继承了 Runnable,Runnable 定义了 invoke() 方法,所以来源的类是不同的。
1 format方法
format 方法是直接返回一个字符串:
python
from langchain.prompts import PromptTemplate
# 创建模板
prompt_template = PromptTemplate.from_template("请把{text}翻译成{language}")
# 使用format方法
prompt = prompt_template.format(text="你好", language="英语")
print(prompt) # 输出:请把你好翻译成英语- 当你只需要一个字符串形式的提示词时,不需要将模板加入执行链时,可以使用
format()方法,例如快速生成提示词进行测试时。
2 invoke方法
invoke 方法返回的是一个 PromptValue 对象,需要调用 to_string() 方法才能得到字符串:
python
from langchain.prompts import PromptTemplate
# 创建模板
prompt_template = PromptTemplate.from_template("请把{text}翻译成{language}")
# 使用invoke方法
prompt_value = prompt_template.invoke({"text": "你好", "language": "英语"})
prompt = prompt_value.to_string()
print(prompt) # 输出:请把你好翻译成英语- 当需要将模板加入 LangChain 执行链时(只有
invoke方法支持链式调用),需要获取PromptValue对象进行进一步处理,可以使用invoke方法。
整理一下区别:
| 区别 | format | invoke |
|---|---|---|
| 定义 | BasePromptTemplate 中定义的 | Runnable 中定义的 |
| 返回值 | 字符串 | PromptValue 对象 |
| 参数 | .format(text="你好", language="英语"),参数名方式 | .invoke({"text": "你好", "language": "英语"}),字典形式 |
| 解析 | 支持 {} 占位符 | 支持 {} 占位符和 MessagesPlaceholder 结构化占位符 |
3 执行链中的使用
invoke 方法的一个重要优势是可以将模板加入到 LangChain 的执行链中:
python
from langchain_ollama import ChatOllama
from langchain.prompts import PromptTemplate
# 1.创建提示词模板
prompt_template = PromptTemplate.from_template("请把:{content},翻译成{language}")
# 2.创建聊天模型
model = ChatOllama(model="qwen3:1.7b")
# 3.使用 | 组成执行链(这里必须使用invoke方法)
chain = prompt_template | model
# 4.通知链条执行,直接传入参数执行
response = chain.stream({"content": "你在做什么?", "language": "英文"})
for chunk in response:
print(chunk.content, end="", flush=True)- 在执行链中,LangChain 会自动调用模板的
invoke方法来生成提示词,然后将结果传递给模型。 - 下一章介绍执行链。
8.6 Zero-shot与Few-shot
1 什么是Zero-shot
Zero-shot 学习是指不给模型提供任何示例,直接让它完成任务。这种方法依赖于模型在预训练过程中学习到的知识和能力,适用于一些通用的、常见的任务。
例如,如果你想让模型将一段中文翻译成英文,你可以直接告诉它:"请将下面的中文翻译成英文:你好,很高兴认识你",而不需要给它任何翻译示例。
2 什么是Few-shot
Few-shot 学习是指给大模型提供少量示例(通常是几个),让它基于这些示例来理解任务要求并生成相应的输出。这种方法可以帮助模型更好地理解具体的任务格式和期望输出,尤其适用于一些复杂或特定领域的任务。
举个例子,如果你想让模型根据描述生成产品评价,你可以先给它几个示例:
- 描述:"这个手机续航时间很长,屏幕清晰,但是价格有点贵。" 评价:"4星,续航和屏幕表现出色,但价格偏高。"
- 描述:"这家餐厅的菜味道不错,服务也很好,环境干净整洁。" 评价:"5星,菜品美味,服务周到,环境舒适。"
- 描述:"这个软件功能很多,但界面有点复杂,需要时间学习。"
- 评价:"3星,功能丰富但界面不够友好,学习成本较高。"
然后模型就能根据这些示例,为新的描述生成类似格式的评价。
例如我给出描述"这款耳机音质很棒,佩戴舒适,续航也不错,就是价格稍微有点高。",让模型按照示例的形式,给出评价。
3 FewShotPromptTemplate的使用
LangChain 提供了 FewShotPromptTemplate 来实现 Few-shot 学习。
下面介绍一下如何使用它来让大模型基于示例完成回答,基于上面根据产品描述生成评价:
python
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_ollama import ChatOllama
# 1.定义示例的格式模板
example_template = PromptTemplate.from_template(
"描述: {description}\n评价: {review}"
)
# 2.给出示例数据(示例会自动注入到 example_template)
examples_data = [
{
"description": "这个手机续航时间很长,屏幕清晰,但是价格有点贵。",
"review": "4星,续航和屏幕表现出色,但价格偏高。"
},
{
"description": "这家餐厅的菜味道不错,服务也很好,环境干净整洁。",
"review": "5星,菜品美味,服务周到,环境舒适。"
},
{
"description": "这个软件功能很多,但界面有点复杂,需要时间学习。",
"review": "3星,功能丰富但界面不够友好,学习成本较高。"
}
]
# 3.创建 FewShotPromptTemplate,参数是重点,待会介绍一下
few_shot_template = FewShotPromptTemplate(
example_prompt=example_template,
examples=examples_data,
prefix="请根据下面的示例,为产品描述生成评价:",
suffix="描述: {product_description}",
input_variables=["product_description"]
)
# 4.生成最终的提示词
prompt = few_shot_template.invoke(
input={"product_description": "这款耳机音质很棒,佩戴舒适,续航也不错,就是价格稍微有点高。"}
)
print("生成的提示词:", prompt.to_string())
# 5.创建模型
model = ChatOllama(model="qwen3:1.7b")
# 6.调用模型
response = model.stream(prompt)
print("\n模型回答:")
for chunk in response:
print(chunk.content, end="", flush=True)首先介绍一下 FewShotPromptTemplate 的5个参数的意思:
- example_prompt:示例数据的提示词模板,定义了每个示例的格式
- examples:示例数据,list格式,内套字典,每个字典包含示例的键值对
- prefix:在示例数据前输出的内容,用于说明任务要求
- suffix:在示例数据后输出的内容,用于放置用户输入
- input_variables:提示词中的参数列表,需要从外部注入的变量列表
执行结果:
生成的提示词: 请根据下面的示例,为产品描述生成评价: # prefix的内容
描述: 这个手机续航时间很长,屏幕清晰,但是价格有点贵。 # 示例数据
评价: 4星,续航和屏幕表现出色,但价格偏高。
描述: 这家餐厅的菜味道不错,服务也很好,环境干净整洁。
评价: 5星,菜品美味,服务周到,环境舒适。
描述: 这个软件功能很多,但界面有点复杂,需要时间学习。
评价: 3星,功能丰富但界面不够友好,学习成本较高。
描述: 这款耳机音质很棒,佩戴舒适,续航也不错,就是价格稍微有点高。 # suffix的内容
模型回答:
评价: 4星,音质清晰,佩戴舒适,续航优秀,但价格偏高。