LangChain Prompts模块学习
背景
在AI交互中,清晰的提示词设计与输出控制是提升任务成功率的关键,例如:
-
当提示词为:"请列举3种最适合猫咪编程的语言"
AI输出:
yamlAI: 为猫咪设计的"编程语言"需要极简、直观且符合猫咪的习性(比如喜欢拍打键盘或随机踩踏)。以下是三种最适合猫咪的趣味编程语言推荐: --- ### 1. **Catlang** - **特点**:专为猫咪设计的极简语言,键盘上的任意按键组合都可能生成有效代码(比如 `Meow++` 表示循环,`Purr()` 表示输出)。 - **猫咪友好度**:键盘
-
当提示词为:"请列举3种最适合猫咪编程的语言,并用逗号分隔。"
AI 输出:
makefileAI: Scratch, Python, JavaScript
由此可以看出,一个"好"的提示词对模型输出结果影响较大,那么如何写好提示词?
本文将介绍LangChain框架提供了哪些Prompts方法
概念介绍
模型输入(Prompts)有助于将用户输入和参数转换为语言模型的指令。这可以用来指导模型的响应,帮助其理解上下文并生成相关且连贯的语言输出。提示模板输出一个 PromptValue。此 PromptValue 可以传递给 LLM 或 ChatModel,也可以转换为字符串或消息列表。此 PromptValue 存在的目的是为了方便在字符串和消息之间切换。LangChain框架主要提供了一下3个PromptTemplate
- PromptTemplate 基础模板引擎,支持动态参数替换(如{price}、{flower_name}),实现指令与数据的解耦。通过占位符机制避免硬编码问题,提升代码复用性。
- ChatPromptTemplate 适配多轮对话场景,支持角色化消息模板(如SystemMessage、HumanMessage、AIMessage),构建结构化聊天上下文
- FewShotPromptTemplate 通过预置示例引导模型生成特定风格的输出(如广告文案模板),提升任务适配性
验证模型:Deepseek-chat
python
from langchain.chat_models import ChatOpenAI
import os
llm = ChatOpenAI(
model="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
temperature=0.7,
max_tokens=100
)
基础模板类:PromptTemplates
提示模板由一个字符串模板组成。它接受来自用户的一组参数,这些参数可用于生成语言模型的提示。可以使用 f 字符串(默认)、jinja2 或 mustache 语法来格式化模板。
ini
class PromptTemplate(StringPromptTemplate):
template: str # 必填 定义提示模板的字符串内容,包含占位符(如 {variable})用于动态替换
template_format: PromptTemplateFormat = "f-string" # 指定模板渲染格式,可选值:"f-string"、"mustache"、"jinja2"
validate_template: bool = False # 是否验证模板合法性(如变量是否匹配、语法是否正确),默认关闭以避免性能损耗
python
class BasePromptTemplate(
RunnableSerializable[dict, PromptValue], Generic[FormatOutputType], ABC
):
"""Base class for all prompt templates, returning a prompt."""
功能:定义模板中必须由用户提供的变量名称列表(如 {topic})。这些变量在调用 format() 时需显式传入
示例:input_variables=["adjective", "content"] 对应模板中的 {adjective} 和 content 占位符
input_variables: list[str]
功能:声明模板中的可选变量,通常用于占位符或动态推断场景。这些变量无需用户显式传入,由系统自动处理
optional_variables: list[str] = Field(default=[])
功能:指定输入变量的类型约束(如 int、str)。若未声明,默认所有变量为字符串类型,增强类型安全性
input_types: typing.Dict[str, Any] = Field(default_factory=dict, exclude=True) # noqa: UP006
功能:定义如何解析模型的输出(如转为 JSON 或结构化数据)
output_parser: Optional[BaseOutputParser] = None
功能:预填充模板中的部分变量(如固定指令、上下文信息),减少重复参数传递。例如,预填 date="2025-05-22" 后,调用时只需传入其他变量
partial_variables: Mapping[str, Any] = Field(default_factory=dict)
功能:用于追踪模板的元数据(如版本、作者)和标签(如分类标记),支持调试与监控
metadata: Optional[typing.Dict[str, Any]] = None # noqa: UP006
tags: Optional[list[str]] = None
模板渲染格式
f-string
python
from langchain_core.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template("Does {x} like {y} and why? ")
prompt = prompt_template.format(x="foo", y="bar")
print(prompt) # Output: Does foo like bar and why?
python
from langchain_core.prompts import PromptTemplate
template = "Does {x} like {y} and why? "
prompt_template = PromptTemplate(
template=template,
template_format="f-string",
validate_template=True,
input_variables=["x", "y"],
optional_variables=[],
input_types={
"x": str,
"y": str,
},
partial_variables={
"brand": "Generic"
},
metadata={
"version": "1.0",
"author": "AI Engineer"
},
tags=["marketing", "product"]
)
# 填充变量并生成提示
prompt = prompt_template.format(x="foo", y="bar")
print("生成的提示:", prompt) # Output: Does foo like bar and why?
# 疑问 prompt_template.format(x="foo", y=99) pormpt输出?
sql
生成的提示: Does foo like 99 and why?
jinja2
python
from langchain_core.prompts import PromptTemplate
from typing import Dict, Any
from pydantic import Field
from langchain_core.output_parsers import BaseOutputParser
from langchain.chat_models import ChatOpenAI
import os
from langchain_core.messages import AIMessage
# 定义一个模板字符串,使用 Jinja2 格式
template = """
{% if product_category == 'electronics' %}
请为{{ product_name }}(电子产品)设计宣传语,强调其技术创新。
{% else %}
请为{{ product_name }}(普通商品)设计宣传语,突出性价比。
{% endif %}
"""
# 创建 PromptTemplate 实例,配置所有参数
prompt_template = PromptTemplate(
template=template,
template_format="jinja2",
validate_template=True,
input_variables=["product_category", "product_name"],
optional_variables=["brand"],
input_types={
"product_category": str,
"product_name": str,
"brand": str
},
partial_variables={
"brand": "Generic"
},
metadata={
"version": "1.0",
"author": "AI Engineer"
},
tags=["marketing", "product"]
)
# 填充变量并生成提示
prompt = prompt_template.format(
product_category="electronics",
product_name="智能耳机",
brand="TechBrand"
)
print("生成的提示:", prompt) # Output: 请为智能耳机(电子产品)设计宣传语,强调其技术创新。
# 填充变量并生成提示
prompt = prompt_template.format(
product_category="merchandise",
product_name="智能耳机",
brand="TechBrand"
)
print("生成的提示:", prompt) # Output: 请为智能耳机(普通商品)设计宣传语,突出性价比。
生成的提示:
请为智能耳机(电子产品)设计宣传语,强调其技术创新。
生成的提示:
请为智能耳机(普通商品)设计宣传语,突出性价比。
mustache
python
from langchain_core.prompts import PromptTemplate
# 定义 mustache 风格模板
template = """
{{#is_electronics}}
请为{{product_name}}(电子产品)设计宣传语,强调其技术创新。
{{/is_electronics}}
{{^is_electronics}}
请为{{product_name}}(普通商品)设计宣传语,突出性价比。
{{/is_electronics}}
"""
prompt_template = PromptTemplate(
template=template,
template_format="mustache",
validate_template=False, # mustache 模板不能自动校验,validate_template 必须设为 False。
input_variables=["product_name", "is_electronics"],
optional_variables=[],
input_types={
"product_name": str,
"is_electronics": bool
},
metadata={
"version": "1.0",
"author": "AI Engineer"
},
tags=["marketing", "product"]
)
# 填充变量并生成提示(电子产品)
prompt1 = prompt_template.format(product_name="智能手表", is_electronics=True)
print("电子产品提示:", prompt1) # Output: 请为智能手表(电子产品)设计宣传语,强调其技术创新。
# 填充变量并生成提示(普通商品)
prompt2 = prompt_template.format(product_name="保温杯", is_electronics=False)
print("普通商品提示:", prompt2) # Output: 请为保温杯(普通商品)设计宣传语,突出性价比。
电子产品提示:
请为智能手表(电子产品)设计宣传语,强调其技术创新。
普通商品提示:
请为保温杯(普通商品)设计宣传语,突出性价比。
对话模板:ChatPromptTemplate
SystemMessagePromptTemplate 和 HumanMessagePromptTemplate 是 ChatPromptTemplate 的组成部分,用于定义不同角色的消息内容
-
ChatPromptTemplate 用于多轮对话场景,支持组合 system、human、ai 等多种消息模板,生成适合聊天模型的输入。
-
HumanMessagePromptTemplate 用于定义"用户输入"消息模板,支持变量占位符,灵活插入用户输入内容。
-
SystemMessagePromptTemplate 用于定义"系统消息"模板,通常用于设定 AI 的角色、行为准则等。
ChatPromptTemplate
类的实例,使用format_messages
方法生成适用于聊天模型的提示。
python
class ChatPromptTemplate(BaseChatPromptTemplate):
"""Prompt template for chat models."""
messages: Annotated[list[MessageLike], SkipValidation()]
"""List of messages consisting of either message prompt templates or messages."""
validate_template: bool = False
"""Whether or not to try validating the template."""
python
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate([
("system", "You are a helpful AI bot. Your name is {name}."),
("human", "Hello, how are you doing?"),
("ai", "I'm doing well, thanks!"),
("human", "{user_input}"),
],validate_template = True
)
prompt_value = template.invoke(
{
"name": "Bob",
"user_input": "What is your name?"
}
)
for message in prompt_value.messages:
print(message.content)
# Output:
# SystemMessage: You are a helpful AI bot. Your name is Bob.
# HumanMessage : Hello, how are you doing?
# AIMessage : I'm doing well, thanks!
# HumanMessage : What is your name?
vbnet
You are a helpful AI bot. Your name is Bob.
Hello, how are you doing?
I'm doing well, thanks!
What is your name?
python
from langchain_core.prompts import (
ChatPromptTemplate,
HumanMessagePromptTemplate,
SystemMessagePromptTemplate,
)
# 定义一个多轮对话模板
prompt = ChatPromptTemplate([
SystemMessagePromptTemplate.from_template("你是一个乐于助人的AI助手。"),
HumanMessagePromptTemplate.from_template("请用{language}写一个冒泡排序。"),
])
# 填充变量并生成消息列表
prompt_value = prompt.invoke({"language": "Python"})
for message in prompt_value.messages:
print(message.type, ":", message.content)
yaml
system : 你是一个乐于助人的AI助手。
human : 请用Python写一个冒泡排序。
Messages Placeholder
MessagesPlaceholder 是 LangChain 框架中用于动态管理对话上下文的结构化占位符,主要解决多轮对话中历史消息注入、格式对齐与动态内容替换等问题。
python
class MessagesPlaceholder(BaseMessagePromptTemplate):
variable_name: str
"""Name of variable to use as messages."""
optional: bool = False
"""If True format_messages can be called with no arguments and will return an empty
list. If False then a named argument with name `variable_name` must be passed
in, even if the value is an empty list."""
n_messages: Optional[PositiveInt] = None
"""Maximum number of messages to include. If None, then will include all.
Defaults to None."""
以下是两种不同的写法:
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.prompts import MessagesPlaceholder
template = ChatPromptTemplate([
("system", "You are a helpful AI bot."),
MessagesPlaceholder(variable_name="conversation", optional=True)
])
prompt_value = template.invoke(
{
"conversation": [
("human", "Hi!"),
("ai", "How can I assist you today?"),
("human", "Can you make me an ice cream sundae?"),
("ai", "No.")
]
}
)
for message in prompt_value.messages:
print(message.content)
css
You are a helpful AI bot.
Hi!
How can I assist you today?
Can you make me an ice cream sundae?
No.
python
template = ChatPromptTemplate([
("system", "You are a helpful AI bot."),
("placeholder", "{conversation}")
])
prompt_value = template.invoke(
{
"conversation": [
("human", "Hi!"),
("ai", "How can I assist you today?"),
("human", "Can you make me an ice cream sundae?"),
("ai", "No.")
]
}
)
for message in prompt_value.messages:
print(message.content)
css
You are a helpful AI bot.
Hi!
How can I assist you today?
Can you make me an ice cream sundae?
No.
Single-variable template
python
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate([
("system", "You are a helpful AI bot. Your name is Carl."),
("human", "{user_input}"),
])
prompt_value = template.invoke("Hello, there!")
for message in prompt_value.messages:
print(message.content)
csharp
You are a helpful AI bot. Your name is Carl.
Hello, there!
示例增强模板:FewShotPromptTemplate
FewShotPromptTemplate是向模型提供你希望它执行的操作的示例, 比如:在提示词中可以添加,按照以下格式生成
python
class FewShotPromptTemplate(_FewShotPromptTemplateMixin, StringPromptTemplate):
"""Prompt template that contains few shot examples."""
validate_template: bool = False
"""Whether or not to try validating the template."""
example_prompt: PromptTemplate
"""PromptTemplate used to format an individual example."""
suffix: str
"""A prompt template string to put after the examples."""
example_separator: str = "\n\n"
"""String separator used to join the prefix, the examples, and suffix."""
prefix: str = ""
"""A prompt template string to put before the examples."""
template_format: Literal["f-string", "jinja2"] = "f-string"
"""The format of the prompt template. Options are: 'f-string', 'jinja2'."""
python
import os
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain.chat_models import ChatOpenAI
examples = [
{
"question": "家庭成员的年龄和职业推理",
"answer": """
1. 母亲是教师,年龄为 40 岁。
2. 父亲比母亲大 5 岁,所以父亲 45 岁。
3. 儿子是程序员,年龄是母亲的一半,即 20 岁。
4. 女儿是医生,年龄比父亲小 10 岁,即 35 岁。
最终结论:
- 父亲:45 岁,职业:未知
- 母亲:40 岁,职业:教师
- 儿子:20 岁,职业:程序员
- 女儿:35 岁,职业:医生
"""
},
{
"question": "公司员工的职位与年龄推理",
"answer": """
1. 员工 A 是项目经理,年龄 35 岁。
2. 员工 B 是设计师,年龄比项目经理小 5 岁,即 30 岁。
3. 员工 C 是工程师,年龄是设计师的两倍,即 60 岁。
4. 员工 D 是实习生,年龄比设计师小 10 岁,即 20 岁。
最终结论:
- A:35 岁,职业:项目经理
- B:30 岁,职业:设计师
- C:60 岁,职业:工程师
- D:20 岁,职业:实习生
"""
},
{
"question": "学生兴趣小组的年龄与兴趣推理",
"answer": """
1. 学生甲是 15 岁,兴趣是编程。
2. 学生乙比甲大 2 岁,兴趣是绘画。
3. 学生丙比乙小 1 岁,兴趣是音乐。
4. 学生丁比丙大 3 岁,兴趣是运动。
最终结论:
- 甲:15 岁,兴趣:编程
- 乙:17 岁,兴趣:绘画
- 丙:16 岁,兴趣:音乐
- 丁:19 岁,兴趣:运动
"""
}
]
# 创建示例提示模板
example_prompt = PromptTemplate(
input_variables=["question", "answer"],
template="问题: {question}\n推理过程:{answer}"
)
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="任务说明:回答以下问题\n",
suffix="问题:{user_input}\n答案:",
input_variables=["user_input"]
)
usr_input = """1. 员工 A 是项目经理,年龄 20 岁。
2. 员工 B 是设计师,年龄比项目经理小 4 岁。
3. 员工 C 是工程师,年龄是设计师的两倍。
4. 员工 D 是实习生,年龄比设计师小 10 岁。"""
# 生成格式化后的字符串
formatted_prompt = few_shot_prompt.format(user_input=usr_input)
# 初始化模型
llm = ChatOpenAI(
model="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
temperature=0.7,
max_tokens=400
)
# 调用提示模板生成答案
response = llm.invoke(formatted_prompt)
print(response.content)
markdown
/tmp/ipykernel_13815/1004832111.py:71: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.0.10 and will be removed in 1.0. An updated version of the class exists in the :class:`~langchain-openai package and should be used instead. To use it run `pip install -U :class:`~langchain-openai` and import as `from :class:`~langchain_openai import ChatOpenAI``.
llm = ChatOpenAI(
### 初始信息整理:
1. **员工A**
- 职位:项目经理
- 年龄:20岁
2. **员工B**
- 职位:设计师
- 年龄比项目经理小4岁
3. **员工C**
- 职位:工程师
- 年龄是设计师的两倍
4. **员工D**
- 职位:实习生
- 年龄比设计师小10岁
### 分步推理:
#### 第一步:计算员工B的年龄
- 员工B的年龄 = 项目经理的年龄 - 4
- 项目经理(A)的年龄 = 20岁
- 因此,员工B的年龄 = 20 - 4 = **16岁**
#### 第二步:计算员工C的年龄
- 员工C的年龄 = 设计师的年龄 × 2
- 设计师(B)的年龄 = 16岁
- 因此,员工C的年龄 = 16 × 2 = **32岁**
#### 第三步:计算员工D的年龄
- 员工D的年龄 = 设计师的年龄 - 10
- 设计师(B)的年龄 = 16岁
- 因此,员工D的年龄 = 16 - 10 = **6岁**
#### 验证年龄合理性:
- 员工D的年龄为6岁,现实中不太可能成为实习生(通常实习生需成年)。可能是题目设定特殊,暂按逻辑计算。
### 最终结论:
- **A**:20岁,职业:项目经理
- **B**:16岁,职业:设计师
- **C**:32岁,职业:工程师
- **D**:6岁,职业:实习生
### 完整答案:
```
- A:20 岁,职业:项目经理
- B:16 岁,职业:设计师
流水线模板:PipelinePromptTemplate
PipelinePromptTemplate 用于将多个提示模板(PromptTemplate)或链式组件(如 LLM、工具等)组合成一个"流水线",实现多阶段、分步处理复杂任务。它常用于需要多步推理、信息汇总、上下文动态注入等场景。
新版 LangChain 已不推荐单独的 PipelinePromptTemplate 类,推荐直接用"RunnablePassthrough链式写法"来实现流水线功能。
python
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough, RunnableSequence
from langchain.chat_models import ChatOpenAI
# 定义子模板
city_template = PromptTemplate.from_template("推荐一个适合{season}旅游的城市:")
attraction_template = PromptTemplate.from_template("列举{city}的3个热门景点:")
food_template = PromptTemplate.from_template("推荐{city}的{attraction}周边美食:")
llm = ChatOpenAI(
model="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
temperature=0.7,
max_tokens=100
)
# 构建多阶段链
travel_chain = (
RunnablePassthrough.assign(
city=lambda x: llm.invoke(city_template.format(season=x["season"])).content
)
| RunnablePassthrough.assign(
attraction=lambda x: llm.invoke(attraction_template.format(city=x["city"])).content
)
| RunnablePassthrough.assign(
food=lambda x: llm.invoke(food_template.format(
city=x["city"], attraction=x["attraction"]
)).content
)
| (lambda x: f"**{x['season']}旅行攻略**\n城市:{x['city']}\n景点:{x['attraction']}\n美食:{x['food']}")
)
# 调用链生成攻略
result = travel_chain.invoke({"season": "春季"})
print(result)
markdown
**春季旅行攻略**
城市:春季是万物复苏、气候宜人的季节,适合去一些风景优美、气候温和的城市旅行。以下推荐几个适合春季旅游的国内外城市,各有特色,供你参考:
---
### **国内推荐:**
1. **杭州(浙江)**
- **推荐理由**:西湖的春天桃红柳绿,苏堤、白堤樱花和桃花盛开,龙井茶园新绿盎然。
- **亮点**:漫步西湖、品龙井茶
景点:以下是杭州春季旅游的3个热门景点推荐,结合自然风光与茶文化体验:
---
### **1. 西湖(苏堤 & 白堤)**
- **春日特色**:
- 苏堤"六桥烟柳"春色如画,两岸樱花、桃花交错盛开,形成粉色长廊。
- 白堤"一株柳树一株桃"的经典景观,3月底至4月初最佳,桃红柳绿
美食:以下是杭州春季旅游的3个热门景点推荐,结合自然风光、茶文化体验及周边美食,助你规划一场春日味觉与视觉的双重盛宴:
---
### **1. 西湖(苏堤 & 白堤)**
- **春日特色**:
- 苏堤"六桥烟柳":两岸樱花、桃花交错盛开,形成粉色长廊,最佳观赏期为3月下旬至4月中旬。
- 白堤经典景观:
本文由博客一文多发平台 OpenWrite 发布!