2. 提示词模板(Prompt Template)
关于提示词模板。这里只挑拣几个简单讲解,更多的去官方文档查询使用方法即可
2.1 概念
提示词模板(Prompt Template)是 LangChain 的核心抽象之一,它被广泛应用于构建大语言模型
(LLM)应用的各个环节。简单来说,只要是需要动态、批量、或有结构地向大语言模型【发送请求】的地方,几乎都会用到提示词模板。
一个简单的例子,假设我们想根据一个城市名询问 LLM 其历史,按照之前的做法,我们可以定义
HumanMessage("请介绍上海的历史") 、HumanMessage("请介绍西安的历史") 消息等等。可以发现每次询问都会描写重复的消息内容: 请介绍xxx的历史。
在 LangChain 中,针对这种情况,可以定义一个模板:
• 固定文本(模板):“请介绍{city}的历史。”
• 输入变量:[“city”]
定义好后,可以使用该模板:
• 当我们需要查询北京时,就将 city 变量赋值为 “北京”。模板引擎会生成: “请介绍北京的历
史。”
• 当我们需要查询上海时,就将 city 变量赋值为 “上海”。模板引擎会生成: “请介绍上海的历
史。”
提示词模板就是一个可复用的提示词蓝图,它允许我们动态地生成提示词,而不是每次都手动编写完整的提示词。
它类似于编程中的字符串格式化功能。你创建一个带有“占位符”的模板,然后在运行时,用具体的值(变量)填充这些占位符,从而生成一个最终发送给 LLM 的完整提示词。
提示词模板解决了以下几个核心问题:
1. 可复用性: 只需定义一个模板,就可以用于无数个类似的查询。
2. 关注点分离: 将提示词的结构和逻辑(工程)与具体的内容和数据分离开。提示工程师可以专注于优化模板,而应用程序则负责提供变量值。
3. 一致性: 确保发送给LLM的提示词结构统一,这有助于获得更稳定、可预测的输出结果。
4. 可维护性: 如果需要修改提示词的风格或结构,只需修改一个模板文件,而不用在代码的无数个地方进行修改。
2.2 用法
2.2.1 字符串模板
LangChain 提供了PromptTemplate类来轻松实现这一功能。PromptTemplate 实现了标准的
Runnable 接口。示例如下:
from langchain_core.prompts import PromptTemplate # 1. 定义模板:使用 {language} 作为占位符,运行时会被实际值替换 # from_template() 是类方法,根据模板字符串创建一个 PromptTemplate 实例 prompt_template = PromptTemplate.from_template("Translate the following into {language}") # 2. 实例化模板:调用 invoke 方法,传入一个字典,键为占位符名称,值为要填充的内容 # 返回的是一个 PromptValue 对象,其 .text 属性或 str() 可得到最终字符串 result = prompt_template.invoke({"language": "Chinese"}) print(result) # 直接打印 PromptValue 对象会显示 text='...' print(result.text) # 获取纯文本:Translate the following into Chinese| 参数 | 描述 |
|---|---|
template | 提示模板字符串,包含用{}包裹的变量名。 |
input_variables | 模板中所有变量名的列表(通常自动从模板提取,也可手动指定)。 |
内置方法
| 方法 | 描述 |
|---|---|
from_template(template: str) | 类方法,根据模板字符串创建PromptTemplate实例。 |
invoke(input: dict) | 接收一个字典(变量名 -> 值),返回填充后的PromptValue对象。 |
更完整的示例(便于理解)
PromptTemplate实现了 LangChain 的Runnable接口,可以与模型通过|管道组合:prompt | model。如果模板中使用了变量但未在
invoke传入,会抛出KeyError。
# 定义包含多个变量的模板 template = """ 请根据以下信息回答问题: 问题:{question} 背景:{context} """ prompt = PromptTemplate.from_template(template) # 填充变量 filled = prompt.invoke({ "question": "LangChain 是什么?", "context": "LangChain 是一个用于构建 LLM 应用的框架。" }) print(filled.text) # 输出: # 请根据以下信息回答问题: # 问题:LangChain 是什么? # 背景:LangChain 是一个用于构建 LLM 应用的框架。2.2.2 聊天消息模板
ChatPromptTemplate模板:专为 LangChain 聊天模型设计。可以方便地构建包含
SystemMessage 、HumanMessage 、AIMessage 的消息模板。
# ==================== 1. 基础用法:创建包含 system 和 user 消息的模板 ==================== from langchain_core.prompts import ChatPromptTemplate # 1.1 设置模板:使用元组列表定义消息序列,每个元组为 (角色, 内容模板) # 支持的角色类型通常为 "system", "user", "ai" prompt_template = ChatPromptTemplate( [ ("system", "Translate the following into {language}."), # 系统消息模板 ("user", "{text}") # 用户消息模板 ] ) # 注释:在 langchain_core 0.2.24 版本后可直接使用 ChatPromptTemplate() 构造函数; # 旧版本需要使用 ChatPromptTemplate.from_messages() 方法。 # 1.2 实例化模板:传入具体变量值,得到 PromptValue 对象 messages_value = prompt_template.invoke( { "language": "Chinese", "text": "what is your name?" } ) # 1.3 将 PromptValue 转换为消息列表(包含 SystemMessage 和 HumanMessage 对象) messages = messages_value.to_messages() print(messages) # 输出: # [SystemMessage(content='Translate the following into Chinese.', ...), # HumanMessage(content='what is your name?', ...)] # ==================== 2. 进阶用法:与模型和输出解析器组合成链 ==================== from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser # 2.1 定义大模型(以 OpenAI GPT-4o-mini 为例) model = ChatOpenAI(model="gpt-4o-mini") # 2.2 定义输出解析器:将模型响应转换为字符串 parser = StrOutputParser() # 2.3 构建链:模板 -> 模型 -> 解析器 # 注意:ChatPromptTemplate 可以直接 invoke 返回消息列表,也可以直接放入链中 chain = prompt_template | model | parser # 2.4 执行链:传入变量,自动完成模板填充 -> 模型调用 -> 解析 result = chain.invoke({"language": "Chinese", "text": "what is your name?"}) print(result) # 输出:你的名字是什么?ChatPromptTemplate的作用
专为聊天模型设计,可以方便地定义多轮对话的消息模板(系统、用户、助手角色)。每个消息模板是一个(role, template_string)元组。两种调用方式
单独使用:
prompt_template.invoke(variables)→PromptValue,再调用.to_messages()得到消息列表,传递给模型。链式调用:
prompt_template | model | parser,直接传入变量,自动完成模板填充、模型调用和输出解析。
输入变量的自动推断
ChatPromptTemplate会自动扫描所有模板字符串中的{variable}作为输入变量,无需手动指定input_variables。常见角色类型
"system": 系统消息,设定模型行为。"user": 用户消息。"ai": 助手消息(通常用于少样本示例或对话历史)。也可使用
HumanMessage,AIMessage等对象直接添加,但元组形式更简洁。
第一个
print(messages)输出的是SystemMessage和HumanMessage对象的列表,包含完整元数据。链式调用最终打印的是模型翻译后的中文结果:
你的名字是什么?。
2.2.3 消息占位符
在上面的 ChatPromptTemplate 中,我们看到了如何格式化两条消息,每条消息都是一个字符串。但如果我们希望将消息插入特定位置怎么办?使用MessagesPlaceholder:负责在特定位置添加消息列表。
# ==================== 方式一:使用 MessagesPlaceholder(推荐) ==================== from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.messages import HumanMessage, AIMessage # 1. 定义模板:包含系统消息和一个占位符(用于插入任意消息列表) prompt_template = ChatPromptTemplate([ ("system", "你是一个聊天助手"), MessagesPlaceholder("msgs") # 参数为占位符变量名,运行时会将对应消息列表嵌入此处 ]) # 2. 准备要插入的消息列表(通常是对话历史或动态生成的连续消息) messages_to_pass = [ HumanMessage(content="中国首都是哪里?"), AIMessage(content="中国首都是北京。"), HumanMessage(content="那法国呢?") ] # 3. 调用 invoke,将消息列表赋值给变量 "msgs",生成最终 PromptValue formatted_prompt = prompt_template.invoke({"msgs": messages_to_pass}) # 4. 打印结果:可以看到系统消息后面依次插入了三条消息 print(formatted_prompt) # 输出效果(简化): # messages=[ # SystemMessage(content='你是一个聊天助手', ...), # HumanMessage(content='中国首都是哪里?', ...), # AIMessage(content='中国首都是北京。', ...), # HumanMessage(content='那法国呢?', ...) # ] # ==================== 方式二:使用 ("placeholder", "{var}") 的缩写形式 ==================== # 不显式使用 MessagesPlaceholder 类,直接用元组 ("placeholder", 变量名) 效果相同 from langchain_core.prompts import ChatPromptTemplate from langchain_core.messages import HumanMessage, AIMessage prompt_template = ChatPromptTemplate([ ("system", "You are a helpful assistant"), ("placeholder", "{msgs}") # 等价于 MessagesPlaceholder("msgs") ]) messages_to_pass = [ HumanMessage(content="中国首都是哪里?"), AIMessage(content="中国首都是北京。"), HumanMessage(content="那法国呢?") ] formatted_prompt = prompt_template.invoke({"msgs": messages_to_pass}) print(formatted_prompt) # 输出结果与方式一完全一致什么是
MessagesPlaceholder
它是一个特殊的占位符,允许你在聊天模板的任意位置嵌入一个完整的消息列表(而不是普通字符串)。通常用于:插入多轮对话历史记录。
动态添加任意数量的上下文消息(如检索到的示例、用户的操作记录等)。
为什么需要消息占位符
普通的字符串占位符(如{text})只能填充文本内容,而MessagesPlaceholder可以直接填充BaseMessage列表(HumanMessage、AIMessage等),保留每条消息的角色和元数据。两种写法的区别与选择
推荐写法:
MessagesPlaceholder("variable_name"),语义清晰,IDE 支持良好。缩写写法:
("placeholder", "{variable_name}"),更简洁,但不易发现可用的参数(如optional、n_messages等扩展参数)。
从 LangChain 0.2+ 开始,
MessagesPlaceholder还支持额外参数:optional=True(允许变量缺失而不报错)、n_messages=5(限制插入的消息数量)等,这些在缩写形式中无法使用。与普通模板的区别
普通模板:
("user", "{text}")→ 填充的是纯文本,生成一条HumanMessage。消息占位符:
MessagesPlaceholder("msgs")→ 将整个消息列表“展开”后嵌入,列表中的每条消息保持原样插入。
实际应用场景
# 场景:需要将检索到的示例对话作为上下文插入到系统消息之后 prompt_template = ChatPromptTemplate([ ("system", "你是一个代码助手"), MessagesPlaceholder("few_shot_examples"), # 插入几个例子 ("user", "{user_input}") ]) examples = [ HumanMessage("如何反转列表?"), AIMessage("使用 list[::-1] 即可。"), HumanMessage("如何合并两个字典?"), AIMessage("使用 {**dict1, **dict2}。") ] final_prompt = prompt_template.invoke({ "few_shot_examples": examples, "user_input": "如何创建字典推导式?" })
扩展:MessagesPlaceholder的更多参数(LangChain 0.3+)
MessagesPlaceholder( variable_name="history", optional=True, # 若 history 未提供,不会报错,直接忽略该占位符 n_messages=5 # 最多只取历史中的最后 5 条消息插入 )2.3 使用 LangChain Hub 的提示词模板
LangChain Hub 是一个用于上传、浏览、拉取和管理提示词(prompts)的地方。随着 LLM 的发展,提示变得越来越重要。LangChain 正在打造一个与像 GitHub 这样的传统平台,GitHub长期以来一直是共享和协作代码的首选平台。于是推出了 LangChain Hub 平台。
LangChain Hub 创建一个分享和发现 Prompt 的平台,使得开发者可以更容易地发现新用例和精炼提示。 这一举措使提示工程师更容易合作,重复使用现有的提示,并对其进行微调以实现特定的结果,从而加速对话代理和其他基于语言的应用程序的开发和部署。早期的时候 LangChain Hub 有Prompt、Chain、Agent,现在只有Prompt。
LangChain Hub 官网地址:中心 - LangSmith。通过登录到 Hub 来探索所有现有提示。
这里以提示词模板:hardkothari/prompt-maker 为示例,演示一下如何使用 LangChain Hub 上的提示。Prompt Maker 模板是一个【提示生成器】 ,它可以自动化优化提示的过程,从而提高语言模型在各种应用中的质量和效果。
要想使用该能力,需要先申请并配置LangSmith 环境变量: LANGSMITH_API_KEY="你的LangSmith API Key" 。接着,需要从 hub 拉取相应的提示,并使用
import os from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langsmith import Client # ==================== 1. 设置 LangSmith API 环境变量 ==================== # 在代码中设置(不推荐生产环境使用,仅演示),或者提前在系统环境变量中配置好 LANGSMITH_API_KEY # os.environ["LANGSMITH_API_KEY"] = "你的 LangSmith API Key" # ==================== 2. 初始化 LangSmith 客户端 ==================== client = Client() # 自动从环境变量 LANGSMITH_API_KEY 中读取 API Key # ==================== 3. 从 LangSmith Hub 拉取提示词模板 ==================== # 从 LangSmith Hub 拉取 hardkothari/prompt-maker 提示词模板 # include_model=False 表示只拉取提示词本身的定义,不附带关联的模型配置。 # 如果设置为 True,则会尝试同时加载模板中指定的模型配置(需要额外设置) prompt = client.pull_prompt("hardkothari/prompt-maker", include_model=False) # 4. 定义 LLM 模型:此处使用 OpenAI 的 GPT-4o-mini 模型 model = ChatOpenAI(model="gpt-4o-mini") # 5. 构建处理链:提示词模板 → 大模型调用(此时模板还未“注入”用户输入) chain = prompt | model # 6. 交互式循环:接收用户输入的"任务"和"当前提示词",生成优化后的提示词并打印 while True: # 6.1 获取用户当前的任务描述 task = input("\n你的任务是什么?(输入 quit 退出聊天)\n") if task == 'quit': break # 6.2 获取用户当前的提示词/原始提示 lazy_prompt = input("\n你当前的提示是什么?(输入 quit 退出聊天)\n") if lazy_prompt == 'quit': break # 6.3 将两个变量以字典形式传入链中调用,生成模型的回复并美化打印 print("\n Response:") # 将 task 和 lazy_prompt 传递给链进行调用,注意字典的键名要与模板期望的变量名完全匹配 chain.invoke({'lazy_prompt': lazy_prompt, 'task': task}).pretty_print()通过使用这个模板,可以大 减少手动调整提示所需的工作量,从而节省时间和资源。Prompt Maker通过分析初始提示的结构和内容,然后应用一组预定规则或算法来优化提示,以提高响应质量、清晰度和相关性。这在提示的质量对模型的输出有很大影响的场景中特别有用,比如客户服务机器人、对话代理或数据分析任务。