别再手写Prompt了!LangChain模板实战指南,3个案例带你从入门到业务落地
1. 本章目标
学完本章后,你应该能够:
- 理解 Prompt 在大模型应用中的作用
- 使用普通字符串编写 Prompt
- 使用
PromptTemplate管理单段提示词 - 使用
ChatPromptTemplate管理聊天消息 - 给 Prompt 注入变量
- 编写适合业务场景的提示词
- 完成商品文案、学习计划、客服回复三个案例
2. 什么是 Prompt
Prompt 就是给模型的指令。
例如:
请用一句话介绍 LangChain。这是一条很简单的 Prompt。
在实际项目中,Prompt 往往会更复杂:
你是一名电商运营专家。 请根据商品名称、商品卖点、目标用户,生成一段适合详情页展示的商品文案。 要求: 1. 语气自然 2. 不超过 150 字 3. 突出用户利益Prompt 的质量会直接影响模型输出质量。
3. 为什么需要 Prompt 模板
如果每次都手写完整 Prompt,会有几个问题:
- 代码里字符串太长
- 多个地方重复写类似提示词
- 变量拼接容易出错
- 后期不方便维护和修改
例如:
prompt = f"请为商品 {product_name} 写一段文案,卖点是 {selling_points}"这种写法可以用,但当提示词变长后就不好维护。
LangChain 提供了 Prompt 模板,可以把固定内容和变量分开。
4. PromptTemplate 基本使用
PromptTemplate适合普通文本提示词。
示例:
from langchain_core.prompts import PromptTemplate prompt_template = PromptTemplate.from_template( "请为商品 {product_name} 写一句广告语,突出卖点:{selling_points}" ) prompt = prompt_template.invoke( { "product_name": "无线鼠标", "selling_points": "静音、续航长、轻便", } ) print(prompt.text)模板中的变量:
{product_name} {selling_points}会被实际数据替换。
5. ChatPromptTemplate 基本使用
如果要使用 system / human 消息结构,推荐使用ChatPromptTemplate。
示例:
from langchain_core.prompts import ChatPromptTemplate prompt_template = ChatPromptTemplate.from_messages( [ ("system", "你是一名电商运营专家,回答要简洁、有吸引力。"), ("human", "请为商品 {product_name} 写一段文案,卖点是:{selling_points}"), ] )调用:
prompt = prompt_template.invoke( { "product_name": "无线鼠标", "selling_points": "静音、续航长、轻便", } )ChatPromptTemplate会生成消息列表,适合聊天模型。
本课程后面会经常使用它。
随堂代码:
from langchain_core.prompts import PromptTemplate prompt_template=PromptTemplate.from_template("请为商品 {product_name} 写一句广告语,突出卖点:{selling_points}") prompt=prompt_template.invoke( { "product_name":"logi鼠标", "selling_points":"特别安静,灵敏,速度快,无延迟" } ) print(prompt.text)from langchain_core.prompts import ChatPromptTemplate chat_template=ChatPromptTemplate.from_messages( [ ("system","你是一名电商运营专家,回答要简洁、有吸引力。"), ("human","请为商品 {product_name} 写一段文案,卖点是:{selling_points}") ] ) prompt=chat_template.invoke( { "product_name":"logi鼠标", "selling_points":"特别安静,灵敏,速度快,无延迟" } ) print(prompt) # 在真正使用时,需要将整个对象都传递给大模型,而不是一个字符串 print(prompt.messages[1].content)核心本质差异
PromptTemplate
纯文本提示词模板,只生成一段完整字符串。
无角色概念,只能把系统指令、用户提问揉在一段文字里,靠文字描述区分角色,模型容易混淆。
ChatPromptTemplate 【建议使用】
对话消息模板,生成结构化消息列表[SystemMessage, HumanMessage, AIMessage]。
适用:现代对话大模型(GPT-3.5/4、Claude、通义千问、文心一言等),所有 Agent、ReAct、聊天智能体都用它。
ChatPromptTemplate:原生支持三种角色消息:
- SystemMessage:系统提示词(智能体规则、ReAct 流程、约束)
- HumanMessage:用户输入
- AIMessage:模型历史回复(用于多轮记忆)
6. Prompt 编写建议
第一阶段先掌握几个最实用的原则。
6.1 明确角色
例如:
你是一名电商运营专家。角色可以帮助模型确定回答风格。
6.2 明确任务
例如:
请根据商品名称和卖点生成一段详情页文案。任务越明确,模型越容易输出想要的结果。
6.3 明确约束
例如:
要求: 1. 不超过 150 字 2. 不要使用夸张宣传 3. 适合年轻上班族约束可以减少输出跑偏。
6.4 给出输入字段
例如:
商品名称:{product_name} 商品卖点:{selling_points} 目标用户:{target_user}让模型清楚知道每个变量的含义。
7. 案例一:商品文案生成器
本案例根据商品信息生成一段电商文案。
创建01_product_copywriter.py:
import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate load_dotenv() model=init_chat_model( model="deepseek-v4-flash", model_provider="openai", base_url=os.getenv("DEEPSEEK_BASE_URL"), api_key=os.getenv("DEEPSEEK_API_KEY"), temperature=0.5 ) prompt_str=""" 请根据下面信息生成一段商品详情页文案。 商品名称:{product_name} 商品卖点:{selling_points} 目标用户:{target_user} 要求: 1. 不超过 150 字 2. 突出用户能获得的好处 3. 不要使用虚假夸张表达 """ chat_promt_template=ChatPromptTemplate.from_messages([ ("system","你是一名电商运营专家,擅长写自然、有吸引力但不过度夸张的商品文案"), ("human",prompt_str) ]) prompt=chat_promt_template.invoke({ "product_name":"无线静音鼠标", "selling_points":"静音按键、蓝牙连接、续航 30 天、轻便便携", "target_user":"经常在办公室和图书馆使用电脑的人", }) response=model.invoke(prompt) print(response.content)运行:
python 01_product_copywriter.py这个案例体现了 Prompt 的基本结构:
- 角色
- 输入
- 要求
- 输出任务
8. 减少重复代码:封装模型初始化
前面几个案例都重复写了模型初始化代码。
将其放入到一个 utils 工具包下
可以创建model_factory.py:
import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model def get_deepSeek_model(temperature:float=0.7): load_dotenv() model = init_chat_model( model="deepseek-v4-flash", model_provider="openai", base_url=os.getenv("DEEPSEEK_BASE_URL"), api_key=os.getenv("DEEPSEEK_API_KEY"), temperature=temperature ) return model然后案例中可以改成:
from model_factory import get_deepseek_model model = get_deepseek_model(temperature=0.5)这不是复杂封装,只是减少重复代码。
9. 案例二:学习计划生成器
本案例根据学习目标生成学习计划。
创建02_study_plan.py:
from langchain_core.prompts import ChatPromptTemplate from utils.model_factory import get_deepSeek_model model=get_deepSeek_model(0.5) prompt_str=""" 请为我制定一个学习计划。 学习主题:{topic} 学习时长:{days} 天 每天可学习时间:{hours_per_day} 小时 当前基础:{level} 要求: 1. 按天列出学习内容 2. 每天给出练习任务 3. 内容要适合当前基础 """ chat_promt_template=ChatPromptTemplate.from_messages([ ("system","你是一名编程课程规划老师,擅长为初学者制定可执行的学习计划。"), ("human",prompt_str) ]) prompt=chat_promt_template.invoke({ "topic":"langchain", "days":"3", "hours_per_day":"1", "level":"会python基础" }) response=model.invoke(prompt) print(response.content)运行:
python 02_study_plan.py这个案例可以看到:
- Prompt 可以接收多个变量
- 变量可以是字符串,也可以是数字
- 模型输出可以被规则引导
10. 案例三:客服回复生成器
本案例根据用户问题和订单状态,生成客服回复。
创建03_customer_reply.py:
from langchain_core.prompts import ChatPromptTemplate from utils.model_factory import get_deepSeek_model model = get_deepSeek_model(0.7) prompt_str = """ 请根据用户问题和订单状态,生成一段客服回复。 用户问题:{user_question} 订单状态:{order_status} 物流信息:{shipping_info} 要求: 1. 先安抚用户 2. 再说明当前情况 3. 最后给出下一步建议 4. 不超过 120 字 """ chat_promt_template = ChatPromptTemplate.from_messages([ ("system", "你是一名电商客服,回复要礼貌、明确,不推卸责任。"), ("human", prompt_str) ]) prompt = chat_promt_template.invoke({ "user_question": "我的快递三天没更新了,是不是丢了?", "order_status": "已发货", "shipping_info": "物流显示包裹已到达上海转运中心,暂未更新下一站信息" }) response = model.invoke(prompt) print(response.content)运行:
python 03_customer_reply.py这个案例接近真实业务:
- 用户问题来自前端
- 订单状态来自数据库
- 物流信息来自第三方接口
- Prompt 负责组织这些信息并生成回复
11.MessagesPlaceholder
作用:
MessagesPlaceholder用来在ChatPromptTemplate中插入一组消息列表。
它通常用于:
- 插入聊天历史
- 插入 Agent 中间步骤
- 插入已经构造好的多条 message
普通变量{question}只能填充一段文本,而MessagesPlaceholder("history")可以一次插入多条(历史)消息。
基本导入
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder基本语法
MessagesPlaceholder(variable_name)常用写法:
MessagesPlaceholder("history")完整参数:
MessagesPlaceholder( variable_name="history", optional=True, n_messages=6, )参数说明
参数 | 类型 | 说明 |
variable_name | str | 占位符对应的输入变量名 |
optional | bool | 是否允许不传该变量 |
n_messages | int \| None | 最多保留最近多少条消息 |
在 ChatPromptTemplate 中使用
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant. "), MessagesPlaceholder("history"), ("human", "{question}"), ])这里面有一个照应关系:当MessagesPlaceholder("history")时,默认optional=False
也就是说 prompt.invoke 时,必须传入history 这个标签,当然这个标签的名字两个地方保持一致即可
那如果optional=True, 那么prompt.invoke 时,可以不传递 history
另外这个history,必须是一个列表才行
调用时传入:
prompt_value = prompt.invoke({ "history": [ ("human", "My name is Alice."), ("ai", "Nice to meet you, Alice."), ], "question": "What is my name?", })最终消息顺序相当于:
[ SystemMessage(content="You are a helpful assistant."), HumanMessage(content="My name is Alice."), AIMessage(content="Nice to meet you, Alice."), HumanMessage(content="What is my name?"), ]输入格式
MessagesPlaceholder对应的变量必须是消息列表。
可以使用 tuple 格式:
history = [ ("human", "你好"), ("ai", "你好,有什么可以帮你?"), ]也可以使用 LangChain 消息对象:
from langchain_core.messages import HumanMessage, AIMessage history = [ HumanMessage(content="你好"), AIMessage(content="你好,有什么可以帮你?"), ]错误写法:
prompt.invoke({ "history": "你好", "question": "刚才我说了什么?", })history不能是普通字符串,必须是 list。
optional=True
默认情况下,如果没有传入history,会报错。
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), MessagesPlaceholder("history"), ("human", "{question}"), ]) prompt.invoke({ "question": "Hello!", })如果聊天历史可能为空,建议设置:
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), MessagesPlaceholder("history", optional=True), ("human", "{question}"), ])这样就可以不传history:
prompt_value = prompt.invoke({ "question": "Hello!", })n_messages
n_messages用来限制插入最近多少条消息。
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a concise assistant."), MessagesPlaceholder("history", optional=True, n_messages=4), ("human", "{question}"), ])示例输入:
prompt_value = prompt.invoke({ "history": [ ("human", "My name is Alice."), ("ai", "Nice to meet you, Alice."), ("human", "I like Python."), ("ai", "Great choice."), ("human", "I also use LangChain."), ("ai", "LangChain is useful for LLM apps."), ], "question": "What do you know about me?", })这里history只会插入最近 4 条消息:
[ HumanMessage(content="I like Python."), AIMessage(content="Great choice."), HumanMessage(content="I also use LangChain."), AIMessage(content="LangChain is useful for LLM apps."), ]然后再追加当前问题:
HumanMessage(content="What do you know about me?")placeholder 简写
MessagesPlaceholder也可以使用 tuple 简写:
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), ("placeholder", "{history}"), ("human", "{question}"), ])通常等价于:
prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), MessagesPlaceholder("history", optional=True), ("human", "{question}"), ])如果需要设置n_messages,建议使用显式写法:
MessagesPlaceholder("history", optional=True, n_messages=4)from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from utils.model_factory import get_deepSeek_model model=get_deepSeek_model(temperature=0.7) chat_prompt=ChatPromptTemplate.from_messages( [ ("system","你是一个很棒的问答助手"), MessagesPlaceholder(variable_name="history",optional=True,n_messages=4), ("human","{question}") ] ) prompt=chat_prompt.invoke({ "history":[ ("human", "My name is Alice."), ("ai", "Nice to meet you, Alice."), ("human", "I like Python."), ("ai", "Great choice."), ("human", "I also use LangChain."), ("ai", "LangChain is useful for LLM apps."), ], "question":"我叫什么名字?" }) resp=model.invoke(prompt) print(resp.content)12. 本章重点
本章最重要的是掌握:
- Prompt 是给模型的任务说明
- Prompt 应该包含角色、任务、输入、约束
PromptTemplate适合普通文本提示词ChatPromptTemplate适合聊天模型- Prompt 模板可以通过变量复用
- 业务场景中要把输入信息清晰地交给模型
13. 常见问题
12.1 Prompt 越长越好吗
不是。
Prompt 应该清晰,但不应该堆太多无关要求。
要求越多,模型越可能顾此失彼。
12.2 为什么模型没有完全按要求输出
大模型不是传统程序,不能保证百分百服从每一条指令。
如果输出格式很重要,后续要结合结构化输出和程序校验。
这部分会在第 4 章讲。
12.3 PromptTemplate 和 ChatPromptTemplate 怎么选
简单建议:
- 普通文本任务:可以用
PromptTemplate - 聊天模型任务:优先用
ChatPromptTemplate
本课程后面会更多使用ChatPromptTemplate。