Model I/O 之 PromptTemplate
Prompt Template:(提示词模板) 就是一个可复用的“提示词样板”,它允许你将提示词中固定的部分和变化的部分分离开。你可以把它理解为一个填空题或者带有占位符的字符串。
有几种不同类型的提示模板:
PromptTemplate:LLM提示模板,用于生成字符串提示。它使用 Python 的字符串来模板提示。
ChatPromptTemplate:聊天提示模板,用于组合各种角色的消息模板,传入聊天模型。
XxxMessagePromptTemplate:消息模板词模板,包括:SystemMessagePromptTemplate、HumanMessagePromptTemplate、AIMessagePromptTemplate、ChatMessagePromptTemplate等。
FewShotPromptTemplate:样本提示词模板,通过示例来教模型如何回答。
PipelinePrompt :管道提示词模板,用于把几个提示词组合在一起使用。
自定义模板 :允许基于其它模板类来定制自己的提示词模板。
1、PromptTemplate
PromptTemplate:最基本的模板,生成普通字符串提示词,用于单次对话。
使用场景:
- 简单的问答任务
- 文本转换(翻译、摘要、改写)
1.1 使用说明
PromptTemplate类,用于快速构建 包含变量的提示词模板,并通过传入不同的参数值生成自定义的提示词。
主要参数介绍:
- template:定义提示词模板的字符串,其中包含文本和变量占位符(如{name}) ;
- input_variables: 列表,指定了模板中使用的变量名称,在调用模板时被替换;
- partial_variables:字典,用于定义模板中一些固定的变量名。这些值不需要再每次调用时被替换。
函数介绍:
- format():给input_variables变量赋值,并返回提示词。利用format() 进行格式化时就一定要赋值,否则会报错。当在template中未设置input_variables,则会自动忽略。
1.2 两种实例化方式
1.2.1 使用构造方法
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(
template="你是一个{role},你擅长{skill}",
input_variables=["role"]
)
prompt_value = prompt.format(role="程序员", skill="写代码")
print(prompt_value)输出:
你是一个程序员,你擅长写代码1.2.2 ⭐使用from_template()
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}"
)
prompt_value = prompt.format(role="程序员", skill="写代码")
print(prompt_value)输出和上面一致。
方式二对比方式一,方式二可以自动提取变量,不需要配置 input_variables,更简洁,推荐使用
1.3 部分提示词模板
在 LangChain 中,partial_variables 用于在创建模板时预先填充部分变量,这样在格式化模板时就不需要再为这些变量提供值。这在你有一些固定不变的变量,或者想提前设置一些变量的值时非常有用。
1.3.1 使用 partial_variables
prompt = PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}",
partial_variables={"skill": "写代码"}
)
prompt_value = prompt.format(role="程序员")
print(prompt_value)输出结果:
你是一个程序员,你擅长写代码1.3.2 使用partial()
prompt = PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}",
partial_variables={"skill": "写代码"}
)
prompt_value = prompt.partial(skill="改bug")
prompt_format = prompt_value.format(role="程序员")
print(prompt_format)1.4 组合提示词(了解)
prompt = (PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}")
+ ",你的年龄{age}"
)
prompt_value = prompt.format(role="程序员", skill="写代码", age=18)
print(prompt_value)1.5 提示词模板赋值
LangChain中,提示词模板有两种常用的方法来填充变量:format 和 invoke。
1.5.1 format() 方法
返回类型: 字符串(String) 用途: 直接生成格式化后的提示词字符串
示例略:以上测试都是用 format() 进行变量填充的
1.5.2 invoke() 方法
prompt = PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}"
)
prompt_value = prompt.invoke({"role": "程序员", "skill": "写代码"})
print(prompt_value)
print(type(prompt_value))输出结果:
text='你是一个程序员,你擅长写代码'
<class 'langchain_core.prompt_values.StringPromptValue'>1.5.3 两种方式区别
| 特性 | format() | invoke() |
|---|---|---|
| 返回类型 | 字符串(String) | PromptValue 对象 |
| 参数格式 | 关键字参数 | 字典参数 |
| 使用场景 | 需要直接字符串结果时 | 需要传递给模型时 |
1.6 LLM 调用
chat_model = ChatOpenAI(model=model)
prompt = PromptTemplate.from_template(
template="你是一个{role},你擅长{skill}"
)
prompt_value = prompt.invoke({"role": "程序员", "skill": "写代码"})
response = chat_model.invoke(prompt_value)
print(response.content)输出示例:
你好!作为程序员,我很乐意帮你解决编程问题或探讨技术话题。
我可以协助你:
- 编写特定功能的代码片段
- 调试和优化现有代码
...2、ChatPromptTemplate
ChatPromptTemplate 是创建聊天消息列表的提示模板。它比普通 PromptTemplate 更适合处理多角色、多轮次的对话场景。
特点:
支持 System / Human / AI 等不同角色的消息模板
对话历史维护
**参数类型:**列表参数格式是tuple类型( role :str , content :str 组合最常用)
元组的格式为:(role: str | type, content: str | list[dict] | list[object])
其中 role 是:字符串(如 "system" 、"human" 、"user"、"ai"、"assistant" )
2.1 两种实例化的方式
2.1.1 使用构造方法
prompt = ChatPromptTemplate(
messages=[
("system", "你是一个{role},请用{style}风格来回答问题"),
("human", "{question}"),
("ai", "好的,我会以{style}风格回答问题"),
("human", "{follow_up_question}")
], input_variables=["role", "style", "question", "follow_up_question"]
)
prompt_value = prompt.invoke({"role": "厨师", "style": "幽默", "question": "如何煮意大利面?", "follow_up_question": "需要煮多久?"})
print(prompt_value)
response = chat_model.invoke(prompt_value)
print(response.content)输出:
messages=[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={}), AIMessage(content='好的,我会以幽默风格回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='需要煮多久?', additional_kwargs={}, response_metadata={})]
煮意大利面的时间就像等快递——你盯着锅看的时候它永远不熟,一转身回个消息它就烂成糊了!通常包装上写8-12分钟,但最靠谱的方法是捞一根甩墙上,要是能粘住不掉,恭喜你获得"米其林贴墙认证"!记得煮的时候要像对待前任一样——保持适当距离(加盐),偶尔搅合防止纠缠(粘锅)。最后别忘滤水,毕竟没人喜欢泡澡的意大利面,除非你想做意式汤面!2.1.2 ⭐使用 from_messages()
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{role},请用{style}风格来回答问题"),
("human", "{question}"),
("ai", "好的,我会以{style}风格回答问题"),
("human", "{follow_up_question}")
])
prompt_value = prompt.invoke({"role": "厨师", "style": "幽默", "question": "如何煮意大利面?", "follow_up_question": "需要煮多久?"})
print(prompt_value)
response = chat_model.invoke(prompt_value)
print(response.content)输出和上面一样
2.2 模板调用方式
| 方法名 | 适用模板类型 | 输入参数格式 | 输出类型 | 输出说明 |
|---|---|---|---|---|
format() | PromptTemplate ChatPromptTemplate | 关键字参数 text="hello" | str | 直接返回格式化后的字符串 |
format_messages() | ChatPromptTemplate | 关键字参数 role="助手" | List[BaseMessage] | 返回消息对象列表,可直接传递给聊天模型 |
format_prompt() | PromptTemplate ChatPromptTemplate | 关键字参数 text="hello" | PromptValue (StringPromptValue ChatPromptValue) | 返回中间对象,可转换为字符串或消息列表 |
invoke() | PromptTemplate ChatPromptTemplate | 字典 {"text": "hello"} | PromptValue (StringPromptValue ChatPromptValue) | LCEL风格调用,返回结构化对象,支持链式操作 |
invoke() 和 format() 前文已经介绍过,这里不做演示
format_messages()
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{role},请用{style}风格来回答问题"),
("human", "{question}")
])
prompt_value = prompt.format_messages(role="厨师", style="幽默", question="如何煮意大利面?")
print(prompt_value)
print(type(prompt_value))输出:
[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={})]
<class 'list'>format_prompt()
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{role},请用{style}风格来回答问题"),
("human", "{question}")
])
prompt_value = prompt.format_prompt(role="厨师", style="幽默", question="如何煮意大利面?")
print(prompt_value)
print(type(prompt_value))输出:
[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={})]
<class 'langchain_core.prompt_values.ChatPromptValue'>类型转换补充
format_prompt() 和 invoke() 可以通过方法进行消息类型转换
to_string() 转换提示词类型为字符串,示例如下
prompt_value = prompt.format_prompt(role="厨师", style="幽默", question="如何煮意大利面?").to_string()
print(prompt_value)
print(type(prompt_value))
# 输出
System: 你是一个厨师,请用幽默风格来回答问题
Human: 如何煮意大利面?
<class 'str'>to_messages() 转换提示词类型为列表,示例如下:
prompt_value = prompt.format_prompt(role="厨师", style="幽默", question="如何煮意大利面?").to_messages()
print(prompt_value)
print(type(prompt_value))
# 输出
[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={})]
<class 'list'>2.3 更丰富的参数化实例类型
前面讲了ChatPromptTemplate的两种创建方式。我们看到不管使用构造方法,还是使用from_messages(),参数类型都是列表类型 。列表中的元素可以是多种类型,前面我们主要测试了元组类型。
源码:
def __init__(self,
messages: Sequence[BaseMessagePromptTemplate | BaseMessage | BaseChatPromptTemplate | tuple[str | type, str | list[dict] | list[object]] | str | dict[str, Any]],
*,
template_format: Literal["f-string", "mustache", "jinja2"] = "f-string",
**kwargs: Any) -> None源码:
@classmethod def from_messages(cls,
messages: Sequence[BaseMessagePromptTemplate | BaseMessage | BaseChatPromptTemplate | tuple[str | type, str | list[dict] | list[object]] | str | dict[str, Any]],
template_format: Literal["f-string", "mustache", "jinja2"] = "f-string")
-> ChatPromptTemplate结论:参数是列表类型,列表的元素可以是字符串、字典、字符串构成的元组、消息类型、提示词模板类型、消息提示词模板类型等
2.3.1 str类型
chat_template = ChatPromptTemplate.from_messages([
"Hello, {name}!" # 等价于 ("human", "Hello, {name}!")
])2.3.2 dict类型
prompt = ChatPromptTemplate.from_messages([
{"role": "system", "content": "你是一个{role}."},
{"role": "human", "content": ["复杂内容", {"type": "text"}]},
])
print(prompt.format_messages(role="教师"))2.3.3 Message类型
chat_prompt_template = ChatPromptTemplate.from_messages([
SystemMessage(content="我是一个贴心的智能助手"),
HumanMessage(content="我的问题是:人工智能英文怎么说?")
])2.3.4 BaseChatPromptTemplate类型
使用 BaseChatPromptTemplate,可以理解为 ChatPromptTemplate 里嵌套了 ChatPromptTemplate。
nested_prompt_template1 = ChatPromptTemplate.from_messages([("system", "我是一个人工智
能助手")])
nested_prompt_template2 = ChatPromptTemplate.from_messages([("human", "很高兴认识你")])
prompt_template = ChatPromptTemplate.from_messages([
nested_prompt_template1,nested_prompt_template2
])2.3.5 BaseMessagePromptTemplate类型
LangChain 提供不同类型的 MessagePromptTemplate。最常用的是 SystemMessagePromptTemplate 、 HumanMessagePromptTemplate 和AIMessagePromptTemplate ,分别创建系统消息、人工消息和AI消息,它们是ChatMessagePromptTemplate的特定角色子类。
system_template = "你是一个专家{role}"
system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)
human_template = "给我解释{concept},用浅显易懂的语言"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
# 组合成聊天提示模板
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt,
human_message_prompt])2.4 插入消息列表 MessagesPlaceholder
当你不确定消息提示模板使用什么角色,或者希望在格式化过程中 插入消息列表 时,该怎么办? 这就需要使用 MessagesPlaceholder,负责在特定位置添加消息列表。
使用场景:多轮对话系统存储历史消息以及Agent的中间步骤处理此功能非常有用。
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant"),
MessagesPlaceholder("msgs")
])
prompt_value = prompt.format_messages(msgs=[HumanMessage("hi")])
print(prompt_value)输出:
[SystemMessage(content='You are a helpful assistant', additional_kwargs={}, response_metadata={}), HumanMessage(content='hi', additional_kwargs={}, response_metadata={})]3、提示词样本
在构建 prompt 时,可以通过构建一个少量示例列表去进一步格式化 prompt,这是一种简单但强大的指导生成的方式,在某些情况下可以 显著提高模型性能 。
3.1 FewShotPromptTemplate
# 1. 定义示例数据 - 展示输入输出的对应关系
examples = [
{"input": "北京天气怎么样", "output": "北京市"},
{"input": "南京下雨吗", "output": "南京市"},
{"input": "武汉热吗", "output": "武汉市"}
]
# 2. 创建单个示例的模板 - 定义每个示例的显示格式
example_prompt = PromptTemplate.from_template("Input: {input}\nOutput: {output}")
# 3. 创建少样本提示模板 - 组合所有示例
prompt = FewShotPromptTemplate(
examples=examples, # 使用的示例数据
example_prompt=example_prompt, # 每个示例的格式模板
input_variables=["input"], # 最终提示词需要的外部变量
suffix="Input: {input}\nOutput:" # 在示例后面添加的固定内容
)
# 4. 使用模板生成提示词
prompt_value = prompt.invoke({"input": "内蒙古多少度"})
response = chat_model.invoke(prompt_value)
print(prompt_value)
print(response.content)输出:
text='Input: 北京天气怎么样\nOutput: 北京市\n\nInput: 南京下雨吗\nOutput: 南京市\n\nInput: 武汉热吗\nOutput: 武汉市\n\nInput: 内蒙古多少度\nOutput:'
内蒙古自治区3.2 FewShotChatMessagePromptTemplate
除了FewShotPromptTemplate之外,FewShotChatMessagePromptTemplate是专门为聊天对话场景 设计的少样本(few-shot)提示模板,它继承自 FewShotPromptTemplate ,但针对聊天消息的格式进行了优化。
特点:
- 自动将示例格式化为聊天消息( HumanMessage / AIMessage 等)
- 输出结构化聊天消息( List[BaseMessage] )
- 保留对话轮次结构
# 1. 定义示例数据 - 展示输入输出的对应关系
examples = [
{"input": "北京天气怎么样", "output": "北京市"},
{"input": "南京下雨吗", "output": "南京市"},
{"input": "武汉热吗", "output": "武汉市"}
]
few_shot_chat_template = FewShotChatMessagePromptTemplate(
examples=examples,
# 定义每个示例的格式:用户输入 -> AI回复
example_prompt=ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}")
])
)
# 3. 创建完整的聊天提示词
final_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个地名提取助手,从用户的问题中提取规范的地名"),
few_shot_chat_template,
("human", "{input}")
])
messages = final_prompt.format_messages(input="内蒙古多少度")
response = chat_model.invoke(messages)
print(messages)
print(response.content)输出:
[SystemMessage(content='你是一个地名提取助手,从用户的问题中提取规范的地名', additional_kwargs={}, response_metadata={}), HumanMessage(content='北京天气怎么样', additional_kwargs={}, response_metadata={}), AIMessage(content='北京市', additional_kwargs={}, response_metadata={}), HumanMessage(content='南京下雨吗', additional_kwargs={}, response_metadata={}), AIMessage(content='南京市', additional_kwargs={}, response_metadata={}), HumanMessage(content='武汉热吗', additional_kwargs={}, response_metadata={}), AIMessage(content='武汉市', additional_kwargs={}, response_metadata={}), HumanMessage(content='内蒙古多少度', additional_kwargs={}, response_metadata={})]
内蒙古自治区4、Example selectors(示例选择器)
前面FewShotPromptTemplate的特点是,无论输入什么问题,都会包含全部示例。在实际开发中,我们可以根据当前输入,使用示例选择器,从大量候选示例中选取最相关的示例子集。
使用的好处:避免盲目传递所有示例,减少 token 消耗的同时,还可以提升输出效果。
示例选择策略:语义相似选择、长度选择、最大边际相关示例选择等
语义相似选择 :通过余弦相似度等度量方式评估语义相关性,选择与输入问题最相似的 k 个示例。
长度选择 :根据输入文本的长度,从候选示例中筛选出长度最匹配的示例。增强模型对文本结构的理解。比语义相似度计算更轻量,适合对响应速度要求高的场景。
最大边际相关示例选择 :优先选择与输入问题语义相似的示例;同时,通过惩罚机制避免返回同质化的内容。
- 余弦相似度是通过计算两个向量的夹⻆余弦值来衡量它们的相似性。它的值范围在-1到1之间:当两个向量⽅向相同时值为1;夹⻆为90°时值为0;⽅向完全相反时为-1。
- 数学表达式:余弦相似度 = (A·B) / (||A|| * ||B||)。其中A·B是点积,||A||和||B||是向量的模(⻓度)
# 安装向量数据库
pip install chromadb示例:
embed_model = os.getenv("dmxapi_embedding_model")
llm_model = os.getenv("dmxapi_llm_model")
chat_model = ChatOpenAI(model=llm_model)
# 1. 准备示例数据
examples = [
{"input": "北京天气怎么样", "output": "北京市", "category": "weather"},
{"input": "上海交通拥堵吗", "output": "上海市", "category": "traffic"},
{"input": "广州有什么美食", "output": "广州市", "category": "food"},
{"input": "深圳科技公司多吗", "output": "深圳市", "category": "tech"},
{"input": "杭州西湖美不美", "output": "杭州市", "category": "tourism"},
{"input": "成都火锅好吃吗", "output": "成都市", "category": "food"},
{"input": "重庆地形复杂吗", "output": "重庆市", "category": "geography"},
{"input": "西安历史遗迹多吗", "output": "西安市", "category": "tourism"}
]
# 2. 创建示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples=examples,
embeddings=OpenAIEmbeddings(model=embed_model),
vectorstore_cls=Chroma,
k=2 # 选择最相似的2个示例
)
# 3. 优化后的提示词模板
dynamic_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=PromptTemplate.from_template(
"输入: {input}\n{output}\n" # 添加分隔符
),
prefix="请根据以下示例,从用户输入中提取地名:\n",
suffix="输入: {input}\n",
input_variables=["input"]
)
# 测试不同输入
test_inputs = [
"武汉热干面好吃吗", # 应该选择美食相关示例
"南京下雨了吗", # 应该选择天气相关示例
"苏州园林漂亮吗" # 应该选择旅游相关示例
]
for input_text in test_inputs:
prompt_text = dynamic_prompt.format(input=input_text)
response = chat_model.invoke(prompt_text)
print(f"{input_text} → {response.content.strip()}")输出:
武汉热干面好吃吗 → 武汉市
南京下雨了吗 → 南京市
苏州园林漂亮吗 → 苏州市5、从文档中加载Prompt
一方面,将想要设定prompt所支持的格式保存为JSON或者YAML格式文件。另一方面,通过读取指定路径的格式化文件,获取相应的prompt。
目的与使用场景:
为了便于共享、存储和加强对prompt的版本控制。
当我们的prompt模板数据较大时,我们可以使用外部导入的方式进行管理和维护。
Json 格式示例:
{
"_type": "prompt",
"input_variables": ["name", "what"],
"template": "请{name}讲一个{what}的故事。"
}Yaml 格式示例:
_type: "prompt"
input_variables:
- "name"
- "what"
template: "请给{name}讲一个关于{what}的故事"使用 load_prompt 调用示例:
prompt = load_prompt("prompt.yaml", encoding="utf-8")
prompt_value = prompt.format(name="Alice", what="搞笑")
print(prompt_value)
# 输出:请给Alice讲一个关于搞笑的故事