Skip to content

Model I/O 之 PromptTemplate

Prompt Template:(提示词模板) 就是一个可复用的“提示词样板”,它允许你将提示词中固定的部分和变化的部分分离开。你可以把它理解为一个填空题或者带有占位符的字符串。

有几种不同类型的提示模板:

PromptTemplate:LLM提示模板,用于生成字符串提示。它使用 Python 的字符串来模板提示。

ChatPromptTemplate:聊天提示模板,用于组合各种角色的消息模板,传入聊天模型。

XxxMessagePromptTemplate:消息模板词模板,包括:SystemMessagePromptTemplateHumanMessagePromptTemplateAIMessagePromptTemplateChatMessagePromptTemplate等。

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 使用构造方法

python
from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate(
    template="你是一个{role},你擅长{skill}",
    input_variables=["role"]
)
prompt_value = prompt.format(role="程序员", skill="写代码")
print(prompt_value)

输出:

text
你是一个程序员,你擅长写代码

1.2.2 ⭐使用from_template()

python
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

python
prompt = PromptTemplate.from_template(
    template="你是一个{role},你擅长{skill}",
    partial_variables={"skill": "写代码"}
)

prompt_value = prompt.format(role="程序员")
print(prompt_value)

输出结果:

text
你是一个程序员,你擅长写代码

1.3.2 使用partial()

python
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 组合提示词(了解)

python
prompt = (PromptTemplate.from_template(
    template="你是一个{role},你擅长{skill}")
    + ",你的年龄{age}"
)

prompt_value = prompt.format(role="程序员", skill="写代码", age=18)
print(prompt_value)

1.5 提示词模板赋值

LangChain中,提示词模板有两种常用的方法来填充变量:formatinvoke

1.5.1 format() 方法

返回类型: 字符串(String) 用途: 直接生成格式化后的提示词字符串

示例略:以上测试都是用 format() 进行变量填充的

1.5.2 invoke() 方法

python
prompt = PromptTemplate.from_template(
    template="你是一个{role},你擅长{skill}"
)

prompt_value = prompt.invoke({"role": "程序员", "skill": "写代码"})
print(prompt_value)
print(type(prompt_value))

输出结果:

text
text='你是一个程序员,你擅长写代码'
<class 'langchain_core.prompt_values.StringPromptValue'>

1.5.3 两种方式区别

特性format()invoke()
返回类型字符串(String)PromptValue 对象
参数格式关键字参数字典参数
使用场景需要直接字符串结果时需要传递给模型时

1.6 LLM 调用

python
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)

输出示例:

text
你好!作为程序员,我很乐意帮你解决编程问题或探讨技术话题。
我可以协助你:
- 编写特定功能的代码片段
- 调试和优化现有代码
...

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 使用构造方法

python
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)

输出:

text
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()

python
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()

python
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请用{style}风格来回答问题"),
    ("human", "{question}")
])

prompt_value = prompt.format_messages(role="厨师", style="幽默", question="如何煮意大利面?")
print(prompt_value)
print(type(prompt_value))

输出:

text
[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={})]
<class 'list'>

format_prompt()

python
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请用{style}风格来回答问题"),
    ("human", "{question}")
])

prompt_value = prompt.format_prompt(role="厨师", style="幽默", question="如何煮意大利面?")
print(prompt_value)
print(type(prompt_value))

输出:

text
[SystemMessage(content='你是一个厨师,请用幽默风格来回答问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='如何煮意大利面?', additional_kwargs={}, response_metadata={})]
<class 'langchain_core.prompt_values.ChatPromptValue'>

类型转换补充

format_prompt()invoke() 可以通过方法进行消息类型转换

to_string() 转换提示词类型为字符串,示例如下

python
prompt_value = prompt.format_prompt(role="厨师", style="幽默", question="如何煮意大利面?").to_string()
print(prompt_value)
print(type(prompt_value))

# 输出
System: 你是一个厨师,请用幽默风格来回答问题
Human: 如何煮意大利面?
<class 'str'>

to_messages() 转换提示词类型为列表,示例如下:

python
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(),参数类型都是列表类型 。列表中的元素可以是多种类型,前面我们主要测试了元组类型。

源码:

python
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

源码:

python
@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类型

python
chat_template = ChatPromptTemplate.from_messages([
	"Hello, {name}!" # 等价于 ("human", "Hello, {name}!")
])

2.3.2 dict类型

python
prompt = ChatPromptTemplate.from_messages([
    {"role": "system", "content": "你是一个{role}."},
    {"role": "human", "content": ["复杂内容", {"type": "text"}]},
])
print(prompt.format_messages(role="教师"))

2.3.3 Message类型

python
chat_prompt_template = ChatPromptTemplate.from_messages([
    SystemMessage(content="我是一个贴心的智能助手"),
    HumanMessage(content="我的问题是:人工智能英文怎么说?")
])

2.3.4 BaseChatPromptTemplate类型

使用 BaseChatPromptTemplate,可以理解为 ChatPromptTemplate 里嵌套了 ChatPromptTemplate

python
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。最常用的是 SystemMessagePromptTemplateHumanMessagePromptTemplateAIMessagePromptTemplate ,分别创建系统消息、人工消息和AI消息,它们是ChatMessagePromptTemplate的特定角色子类。

python
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的中间步骤处理此功能非常有用。

python
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    MessagesPlaceholder("msgs")
])

prompt_value = prompt.format_messages(msgs=[HumanMessage("hi")])
print(prompt_value)

输出:

text
[SystemMessage(content='You are a helpful assistant', additional_kwargs={}, response_metadata={}), HumanMessage(content='hi', additional_kwargs={}, response_metadata={})]

3、提示词样本

在构建 prompt 时,可以通过构建一个少量示例列表去进一步格式化 prompt,这是一种简单但强大的指导生成的方式,在某些情况下可以 显著提高模型性能 。

3.1 FewShotPromptTemplate

python
# 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
text='Input: 北京天气怎么样\nOutput: 北京市\n\nInput: 南京下雨吗\nOutput: 南京市\n\nInput: 武汉热吗\nOutput: 武汉市\n\nInput: 内蒙古多少度\nOutput:'
内蒙古自治区

3.2 FewShotChatMessagePromptTemplate

除了FewShotPromptTemplate之外,FewShotChatMessagePromptTemplate是专门为聊天对话场景 设计的少样本(few-shot)提示模板,它继承自 FewShotPromptTemplate ,但针对聊天消息的格式进行了优化。

特点:

  • 自动将示例格式化为聊天消息( HumanMessage / AIMessage 等)
  • 输出结构化聊天消息( List[BaseMessage] )
  • 保留对话轮次结构
python
# 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)

输出:

text
[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||是向量的模(⻓度)
python
# 安装向量数据库
pip install chromadb

示例:

python
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()}")

输出:

text
武汉热干面好吃吗 → 武汉市
南京下雨了吗 → 南京市
苏州园林漂亮吗 → 苏州市

5、从文档中加载Prompt

一方面,将想要设定prompt所支持的格式保存为JSON或者YAML格式文件。另一方面,通过读取指定路径的格式化文件,获取相应的prompt。

目的与使用场景:

  • 为了便于共享、存储和加强对prompt的版本控制。

  • 当我们的prompt模板数据较大时,我们可以使用外部导入的方式进行管理和维护。

Json 格式示例:

json
{
  "_type": "prompt",
  "input_variables": ["name", "what"],
  "template": "请{name}讲一个{what}的故事。"
}

Yaml 格式示例:

yaml
_type: "prompt"
input_variables:
  - "name"
  - "what"
template: "请给{name}讲一个关于{what}的故事"

使用 load_prompt 调用示例:

python
prompt = load_prompt("prompt.yaml", encoding="utf-8")
prompt_value = prompt.format(name="Alice", what="搞笑")
print(prompt_value)

# 输出:请给Alice讲一个关于搞笑的故事