文章目录
- Prompt tempates(提示词模板)
- 什么是提示词模板?
- 创建一个提示词模板(prompt template)
- 聊天消息提示词模板(chat prompt template)
- MessagesPlaceholder
- 提示词追加示例(Few-shot prompt templates)
- 使用示例集
- 将示例和格式化程序提供给`FewShotPromptTemplate`
- 使用示例选择器
- 将示例提供给ExampleSelector
- 将示例选择器提供给`FewShotPromptTemplate`
- 源码地址
- 参考资料
Prompt tempates(提示词模板)
语言模板以文本作为输入 - 这个文本通常被称为提示词(prompt)。在开发过程中,对于提示词通常不能直接硬编码,不利于提示词管理,而是通过提示词模板进行维护,类似于开发过程中遇到的短信模板、邮件模板等等。
什么是提示词模板?
提示词模板本质上跟平时大家使用的邮件模板、短信模板没什么区别,就是一个字符串模板,模板可以包含一组模板参数,通过模板参数值可以替换模板对应的参数。
一个提示词模板可以包含下面内容:
- 发给大语言模型(LLM)的指令。
- 一组问答示例,以提醒AI以什么格式返回请求。
- 发给语言模型的问题。
创建一个提示词模板(prompt template)
可以使用PromptTemplate
类创建简单的提示词。提示词模板可以内嵌任意数量的模板参数,然后根据参数值格式化模板内容
from langchain.prompts import PromptTemplate# 定义一个提示词模板,包含adjective 和 content两个模板变量,模板变量使用{}包括起来
prompt_template = PromptTemplate.from_template("给我讲一个关于{content}的{adjective}笑话。"
)# 通过提示词模板参数格式化提示模板
prompt = prompt_template.format(content="猴子", adjective="冷")
print(prompt)
模板输出结果:
给我讲一个关于猴子的冷笑话。
聊天消息提示词模板(chat prompt template)
聊天模型(Chat Model)以聊天消息列表作为输入,这个聊天消息列表的消息内容也可以通过提示词模板进行管理。这些聊天消息与原始字符串不同,因为每个消息都与“角色(role)”相关联
例如,在OpenAI的Chat Completion API中,Openai的聊天模型,给不同的聊天信息定义了三种角色类型,分别是助手(assiatant/ai)、人类(human/user)或系统(system)角色:
- 助手(assiatant/ai)或AI 消息指的是当前消息是AI回复的内容
- 人类(human/user)消息指的是你发给AI的内容
- 系统(system)消息通常是用来给AI身份进行描述。
创建聊天消息模板例子
from langchain_core.prompts import ChatPromptTemplate # 通过一个消息数组创建聊天信息模板
# 数组每一个元素代表一条消息,每个消息元祖,第一个元素代表消息角色(也成为消息类型),第二个元素代表消息内容
# 消息角色,system代表系统消息,human代表用户消息,ai代表模型回复的消息
# 下面消息定义了2个模板参数name和user_input
chat_template = ChatPromptTemplate.from_messages( [ ("system", "你是一位人工智能助手,你的名字是{name}"), ("human", "你好"), ("AI", "我很好,谢谢!"), ("human", "{user_input}"), ]
) # 通过模板参数格式化模板内容
messages = chat_template.format_messages(name="Bob", user_input="你的名字叫什么?")
print(messages) # 输出:
# [SystemMessage(content='你是一位人工智能助手,你的名字是Bob', additional_kwargs={}, response_metadata={}), HumanMessage(content='你好', additional_kwargs={}, response_metadata={}), AIMessage(content='我很好,谢谢!', additional_kwargs={}, response_metadata={}), HumanMessage(content='你的名字叫什么?', additional_kwargs={}, response_metadata={})]
另外一种消息格式例子:
from langchain.prompts import HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate# 使用langchain定义的SystemMessage、HumanMessagePromptTemplate等工具类定义消息,跟前面的例子类
chat_template = ChatPromptTemplate.from_messages([SystemMessage(content=("你是一个乐于助人的助手,可以润色内容,使其看起来更简单易读")),HumanMessagePromptTemplate.from_template("{text}")]
)# 使用模板参数格式化模板
messages = chat_template.format_messages(text="我不喜欢吃难吃的东西")
print(messages)
MessagesPlaceholder
这个提示词模板负责在特定位置添加消息列表。在上面的ChatPromptTemplate中,我们看到了如何格式化两条消息,每条消息都是一个字符串,如果我们希望用户传入一个消息列表,我们将其插入到特定位置,该怎么办?
这就是使用MessagesPlaceholder的方式。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessageprompt_template = ChatPromptTemplate.from_messages([("system", "You are a helpful assistant"),# 可以传入一组消息MessagesPlaceholder("msgs")])
result = prompt_template.invoke({"msgs": [HumanMessage(content="hi!"), HumanMessage(content="hello")]})
print(result)
这将生成两条消息,第一条是系统消息,第二条是传入的HumanMessage。如果我们传入了5条消息,那么总共会产生6条消息(系统消息加上传入的5条消息)。这对于将一系列消息插入到特定位置非常有用。另一种实现相同效果的替代方法是,不直接使用MessagesPlaceholder
类,而是:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessageprompt_template = ChatPromptTemplate.from_messages([("system", "You are a helpful assistant"),("placeholder", "{msgs}") # <-- 这是修改的部分
])
result = prompt_template.invoke({"msgs": [HumanMessage(content="hi!"), HumanMessage(content="hello")]})
print(result)
提示词追加示例(Few-shot prompt templates)
提示词中包含交互样本的作用是为了帮助模型更好地理解用户的意图,从而更好地回答问题或执行任务。小样本提示模板是指使用一组少量的示例来指导模型处理新的输入。这些示例可以用来训练模型,以便模型可以更好地理解和回答类似的问题。
例子:
Q: 什么是蝙蝠侠?
A: 蝙蝠侠是一个虚构的漫画人物。Q: 什么是torsalplexity?
A: 未知。Q: 什么是语言模型?
A:
告诉模型根据,Q是问题,A是答案,按这种格式进行回答交互。
下面讲解的就是LangChain针对在提示词中插入少量交互样本提供的工具类
使用示例集
下面定义一个examples示例数组,里面包含一组问答样例。
from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplateexamples = [{"question": "谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?","answer":"""这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里"""}, {"question": "乔治·华盛顿的祖父母中的母亲是谁?","answer":"""这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball"""}, {"question": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?","answer":"""这里需要跟进问题吗:是的。跟进:《大白鲨》的导演是谁?中间答案:《大白鲨》的导演是Steven Spielberg跟进:Steven Spielberg来自哪里?中间答案:美国跟进:《皇家赌场》的导演是谁?中间答案:《皇家赌场》的导演是Martin Campbell。跟进:Martin Campbell来自哪里?中间答案: 新西兰。所以最终答案是:不是"""}
]example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\\n{answer}")prompt = FewShotPromptTemplate(examples=examples,example_prompt=example_prompt,suffix="问题,{input}",input_variables=["input"]
)print(prompt.format(input="乔治·华盛顿的父亲是谁"))
创建小样本示例的格式化程序
通过PromptTemplate
对象,简单的在提示词模板插入样例。
from langchain.prompts.prompt import PromptTemplateexamples = [{"question": "谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?","answer":"""这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里"""}, {"question": "乔治·华盛顿的祖父母中的母亲是谁?","answer":"""这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball"""}, {"question": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?","answer":"""这里需要跟进问题吗:是的。跟进:《大白鲨》的导演是谁?中间答案:《大白鲨》的导演是Steven Spielberg跟进:Steven Spielberg来自哪里?中间答案:美国跟进:《皇家赌场》的导演是谁?中间答案:《皇家赌场》的导演是Martin Campbell。跟进:Martin Campbell来自哪里?中间答案: 新西兰。所以最终答案是:不是"""}
]example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\\n{answer}")print(example_prompt.format(**examples[0]))
返回:
问题:谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?\n这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里
将示例和格式化程序提供给FewShotPromptTemplate
通过FewShotPromptTemplate
对象,批量插入示例内容。
# 接收examples示例数组参数,通过example_prompt提示词模板批量渲染示例内容
# suffix和input_variables参数用于在提示词模板最后追加内容,input_variables用于定义suffix中包含
prompt = FewShotPromptTemplate(examples=examples,example_prompt=example_prompt,suffix="问题,{input}",input_variables=["input"]
)print(prompt.format(input="乔治·华盛顿的父亲是谁"))
问题:谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?\n这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里问题:乔治·华盛顿的祖父母中的母亲是谁?\n这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball问题:《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?\n这里需要跟进问题吗:是的。跟进:《大白鲨》的导演是谁?中间答案:《大白鲨》的导演是Steven Spielberg跟进:Steven Spielberg来自哪里?中间答案:美国跟进:《皇家赌场》的导演是谁?中间答案:《皇家赌场》的导演是Martin Campbell。跟进:Martin Campbell来自哪里?中间答案: 新西兰。所以最终答案是:不是问题,乔治·华盛顿的父亲是谁
使用示例选择器
将示例提供给ExampleSelector
上下文有限,所以要只选择一部分
这里重用前一部分中的示例集和提示词模板(prompt template)。但是,不会将示例直接提供给FewShotPromptTemplate
对象,把全部示例插入到提示词中,而是将它们提供给一个ExampleSelector
对象,插入部分示例。
这里我们使用SemanticSimilarityExampleSelector
类。该类根据与输入的相似性选择小样本示例。它们使用嵌入模型计算输入和小样本示例之间的相似性,然后使用向量数据库执行相似搜索,获取跟输入相似的示例。
- 提示:这里涉及向量计算、向量数据库,在AI领域这两个主要用于数据相似度搜索,例如:查询相似文字内容、相似的图片、视频等等,这里先简单了解下就行。
# 相似度匹配示例,将question与examples进行相似度匹配,输出最接近问题的样本
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings# 安装 pip install chromadbexamples = [{"question": "谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?","answer":"""这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里"""}, {"question": "乔治·华盛顿的祖父母中的母亲是谁?","answer":"""这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball"""}, {"question": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?","answer":"""这里需要跟进问题吗:是的。跟进:《大白鲨》的导演是谁?中间答案:《大白鲨》的导演是Steven Spielberg跟进:Steven Spielberg来自哪里?中间答案:美国跟进:《皇家赌场》的导演是谁?中间答案:《皇家赌场》的导演是Martin Campbell。跟进:Martin Campbell来自哪里?中间答案: 新西兰。所以最终答案是:不是"""}
]
# 使用语义相似性示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(# 这是可供选择的示例列表examples,# 这是用于生成嵌入的嵌入类,该嵌入用于衡量语义相似性OpenAIEmbeddings(), # 使用默认"text-embedding-ada-002"模型# 这是用于存储嵌入和执行相似性搜索的VectorStore类Chroma,# 这是要生成的示例数k=1
)
# 选择最相似的样本 修改question可以查看相似度匹配的各种结果
question = "大白鲨导演"
selected_examples = example_selector.select_examples({"question": question})
print(f"最相似的示例:{question}")
for example in selected_examples:print("\\n")for k, v in example.items():print(f"{k}: {v}")# 会输出和question对应的答案
将示例选择器提供给FewShotPromptTemplate
最后,创建一个FewShotPromptTemplate
对象。根据前面的example_selector示例选择器,选择一个跟问题相似的例子。
from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings# 安装 pip install chromadbexamples = [{"question": "谁的寿命更长,穆罕默德·阿里还是艾伦·图灵?","answer":"""这里需要跟进问题吗:是的。跟进:穆罕默德·阿里去世时多大?中间答案:穆罕默德·阿里去世时74岁。跟进:艾伦·图灵去世时多大?中间答案:艾伦·图灵去世时41岁。所以最终答案是:穆罕默德·阿里"""}, {"question": "乔治·华盛顿的祖父母中的母亲是谁?","answer":"""这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball"""}, {"question": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?","answer":"""这里需要跟进问题吗:是的。跟进:《大白鲨》的导演是谁?中间答案:《大白鲨》的导演是Steven Spielberg跟进:Steven Spielberg来自哪里?中间答案:美国跟进:《皇家赌场》的导演是谁?中间答案:《皇家赌场》的导演是Martin Campbell。跟进:Martin Campbell来自哪里?中间答案: 新西兰。所以最终答案是:不是"""}
]examples_selector = SemanticSimilarityExampleSelector.from_examples(# 这是可供选择的示例列表examples,# 这是用于生成嵌入的嵌入类,该嵌入用于衡量语义相似性OpenAIEmbeddings(),# 这是用来存储嵌入和执行相似性搜索的VectorStore类Chroma,# 这是要生成的示例数k=1
)question = "乔治·华盛顿的父亲是谁"
select_examples = examples_selector.select_examples({"question": question})
examples_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\\n{answer}")prompt = FewShotPromptTemplate(example_selector=examples_selector,example_prompt=examples_prompt,suffix="问题:{input}",input_variables=["input"]
)print(prompt.format(input=question))
返回:
问题:乔治·华盛顿的祖父母中的母亲是谁?\n这里需要跟进问题吗;是的。跟进:乔治·华盛顿的母亲是谁?中间答案:乔治·华盛顿的母亲是Mary Ball Washington。跟进:Mary Ball Washington的父亲是谁?中间答案:Mary Ball Washington的父亲是Joseph Ball。所以最终答案是:Joseph Ball
源码地址
https://github.com/lys1313013/langchain-example/tree/main/02-prompt
参考资料
B站:2025吃透LangChain大模型全套教程(LLM+RAG+OpenAI+Agent)第2集
OpneAI 官方 API 文档