LangChain Prompts模块学习
背景
在AI交互中,清晰的提示词设计与输出控制是提升任务成功率的关键,例如:
当提示词为:"请列举3种最适合猫咪编程的语言"
AI输出:
AI: 为猫咪设计的“编程语言”需要极简、直观且符合猫咪的习性(比如喜欢拍打键盘或随机踩踏)。以下是三种最适合猫咪的趣味编程语言推荐:---### 1. **Catlang** - **特点**:专为猫咪设计的极简语言,键盘上的任意按键组合都可能生成有效代码(比如 `Meow++` 表示循环,`Purr()` 表示输出)。 - **猫咪友好度**:键盘
当提示词为:"请列举3种最适合猫咪编程的语言,并用逗号分隔。"
AI 输出:
AI: 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
from langchain.chat_models import ChatOpenAIimport osllm = 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 语法来格式化模板。
class PromptTemplate(StringPromptTemplate): template: str # 必填定义提示模板的字符串内容,包含占位符(如 {variable})用于动态替换 template_format: PromptTemplateFormat = "f-string" # 指定模板渲染格式,可选值:"f-string"、"mustache"、"jinja2" validate_template: bool = False # 是否验证模板合法性(如变量是否匹配、语法是否正确),默认关闭以避免性能损耗
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
from langchain_core.prompts import PromptTemplateprompt_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?
from langchain_core.prompts import PromptTemplatetemplate = "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输出?
生成的提示: Does foo like 99 and why?
jinja2
from langchain_core.prompts import PromptTemplatefrom typing import Dict, Anyfrom pydantic import Fieldfrom langchain_core.output_parsers import BaseOutputParserfrom langchain.chat_models import ChatOpenAIimport osfrom 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
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
方法生成适用于聊天模型的提示。
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."""
from langchain_core.prompts import ChatPromptTemplatetemplate = 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?
You are a helpful AI bot. Your name is Bob.Hello, how are you doing?I'm doing well, thanks!What is your name?
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)
system : 你是一个乐于助人的AI助手。human : 请用Python写一个冒泡排序。
Messages Placeholder
MessagesPlaceholder 是 LangChain 框架中用于动态管理对话上下文的结构化占位符,主要解决多轮对话中历史消息注入、格式对齐与动态内容替换等问题。
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."""
以下是两种不同的写法:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderfrom langchain_core.prompts import MessagesPlaceholdertemplate = 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)
You are a helpful AI bot.Hi!How can I assist you today?Can you make me an ice cream sundae?No.
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)
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
from langchain_core.prompts import ChatPromptTemplatetemplate = 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)
You are a helpful AI bot. Your name is Carl.Hello, there!
示例增强模板:FewShotPromptTemplate
FewShotPromptTemplate是向模型提供你希望它执行的操作的示例, 比如:在提示词中可以添加,按照以下格式生成
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'."""
import osfrom langchain_core.prompts import FewShotPromptTemplate, PromptTemplatefrom langchain.chat_models import ChatOpenAIexamples = [ { "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)
/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链式写法”来实现流水线功能。
from langchain_core.prompts import PromptTemplatefrom langchain_core.runnables import RunnablePassthrough, RunnableSequencefrom 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)
**春季旅行攻略** 城市:春季是万物复苏、气候宜人的季节,适合去一些风景优美、气候温和的城市旅行。以下推荐几个适合春季旅游的国内外城市,各有特色,供你参考: --- ### **国内推荐:** 1. **杭州(浙江)** - **推荐理由**:西湖的春天桃红柳绿,苏堤、白堤樱花和桃花盛开,龙井茶园新绿盎然。 - **亮点**:漫步西湖、品龙井茶 景点:以下是杭州春季旅游的3个热门景点推荐,结合自然风光与茶文化体验: --- ### **1. 西湖(苏堤 & 白堤)** - **春日特色**: - 苏堤"六桥烟柳"春色如画,两岸樱花、桃花交错盛开,形成粉色长廊。 - 白堤"一株柳树一株桃"的经典景观,3月底至4月初最佳,桃红柳绿 美食:以下是杭州春季旅游的3个热门景点推荐,结合自然风光、茶文化体验及周边美食,助你规划一场春日味觉与视觉的双重盛宴: --- ### **1. 西湖(苏堤 & 白堤)** - **春日特色**: - 苏堤"六桥烟柳":两岸樱花、桃花交错盛开,形成粉色长廊,最佳观赏期为3月下旬至4月中旬。 - 白堤经典景观:
本文由博客一文多发平台 OpenWrite 发布!