LangChain Prompt 完整指南
目录
消息类型
在 LangChain 中,Message 是大模型对话的基本单元,就像聊天记录里的每一条消息。
四种核心消息类型
| 类型 | 谁说的 | 作用 | 代码示例 |
|---|---|---|---|
| SystemMessage | 系统/开发者 | 给AI定角色、定规则 | SystemMessage(content="你是一个法律助手") |
| HumanMessage | 用户 | 用户的提问 | HumanMessage(content="酒驾了怎么办") |
| AIMessage | AI | AI的回复 | AIMessage(content="非法律问题无可奉告") |
| ToolMessage | 工具 | 工具执行结果 | ToolMessage(tool_call_id="abc", content="...") |
为什么要区分消息类型?
多轮对话需要记忆:
# 错误做法:每次只问当前问题
HumanMessage(content="北京人口有多少?")
# 正确做法:带上对话历史
messages = [
SystemMessage(content="你是一个旅游助手"),
HumanMessage(content="北京有什么景点?"), # 第1轮
AIMessage(content="推荐故宫、长城、颐和园"), # AI回答
HumanMessage(content="故宫要门票吗?"), # 第2轮(带上了上文)
]
SystemMessage - 系统消息
是什么:定义 AI 的身份、角色和行为规则
SystemMessage(content="你是一个法律助手,只回答法律问题,超出范围的统一回答,非法律问题无可奉告")
就像:给 AI 定了一个"岗位说明书"
HumanMessage - 用户消息
是什么:模拟用户的输入/提问
HumanMessage(content="11") # 用户随便输入的内容
就像:用户发给 AI 的每一条消息
AIMessage - AI消息
是什么:模拟 AI 的回复
AIMessage(content="非法律问题无可奉告")
就像:AI 回复的每一条消息
ToolMessage - 工具消息
是什么 :用于 Agent 调用工具后的结果返回
ToolMessage(
tool_call_id="call_abc123", # 关联的工具调用ID
content='{"population": 21540000, "area": "16410平方公里"}', # 工具执行结果
)
使用场景:当 AI 调用搜索、计算等工具时,工具返回的结果通过 ToolMessage 传回给 AI
完整示例
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
messages = [
SystemMessage(content="你是一个乐于助人的智能小助手"),
HumanMessage(content="你好,请你介绍一下你自己"),
AIMessage(content="我是一名人工智能助手,请问您有什么想问的嘛?"),
# ToolMessage - 用于工具调用场景
ToolMessage(
tool_call_id="call_abc123",
content='{"population": 21540000, "area": "16410平方公里"}',
)
]
Prompt 模板
什么是 PromptTemplate?
PromptTemplate 用于生成格式化的提示词文本,是纯字符串模板。
核心特点:
-
输入:模板 + 变量值
-
输出:格式化后的字符串
-
适用场景:简单问答、文本生成
1. 构造方法创建
from langchain_core.prompts import PromptTemplate
template = PromptTemplate(
template="你是一个专业的{role}工程师,请回答我的问题:{question}",
input_variables=['role', 'question']
)
prompt = template.format(role="python开发", question="冒泡排序怎么写?")
print(prompt)
# 你是一个专业的python开发工程师,请回答我的问题:冒泡排序怎么写?
2. from_template 方法创建
from langchain_core.prompts import PromptTemplate
# 方式1:直接创建
template = PromptTemplate.from_template(
"你是一个专业的{role}工程师,请回答我的问题:{question}"
)
# 方式2:模板拼接(使用 + 号连接)
template1 = PromptTemplate.from_template("请用一句话介绍{topic},要求通俗易懂\n")
template2 = PromptTemplate.from_template("内容不超过{length}个字")
combined_template = template1 + template2
prompt = combined_template.format(topic="LangChain", length=100)
3. format vs invoke 方法
# format() - 返回字符串
prompt_str = template.format(role="python", question="什么是闭包?")
print(prompt_str) # 字符串类型
# invoke() - 返回 PromptValue 对象,可转换为字符串或消息列表
from langchain_core.prompts import PromptTemplate
template = PromptTemplate.from_template(
"你是一个专业的{role}工程师,你的问题是:{question}"
)
prompt_value = template.invoke({"role": "python开发", "question": "冒泡排序怎么写?"})
print(prompt_value) # PromptValue 对象
print(prompt_value.to_string()) # 转为字符串: "你是一个专业的python开发工程师..."
print(prompt_value.to_messages()) # 转为消息列表 [HumanMessage(content='你是一个专业的...')]
4. partial 预绑定变量
有时候希望先固定部分变量,后续再填充剩余变量:
from langchain_core.prompts import PromptTemplate
from datetime import datetime
# 方式1:实例化时使用 partial_variables
template1 = PromptTemplate.from_template(
"现在时间是:{time}, 请回答我的问题:{question}",
partial_variables={"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
)
prompt1 = template1.format(question="今天是几号?")
# 方式2:使用 partial() 方法(推荐,更灵活)
template2 = PromptTemplate.from_template("现在时间是:{time}, 请回答我的问题:{question}")
partial_template = template2.partial(time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
prompt2 = partial_template.format(question="今天是几号?")
# 方式3:构造时使用 partial_variables 预绑定
template3 = PromptTemplate(
template="{foo} {bar}",
input_variables=["foo", "bar"],
partial_variables={"foo": "hello"} # foo 预先绑定为 hello
)
prompt3 = template3.format(bar="world") # 只需传入 bar
# 结果: hello world
5. PromptTemplate 完整方法对比
| 方法 | 作用 | 返回类型 | 示例 |
|---|---|---|---|
format() |
填充变量生成字符串 | str |
template.format(var1="a", var2="b") |
invoke() |
填充变量生成 PromptValue | PromptValue |
template.invoke({"var1": "a", "var2": "b"}) |
partial() |
预绑定部分变量 | PromptTemplate |
template.partial(var1="a") |
to_string() |
PromptValue 转为字符串 | str |
prompt_value.to_string() |
to_messages() |
PromptValue 转为消息列表 | List[BaseMessage] |
prompt_value.to_messages() |
ChatPromptTemplate 对话模板
什么是 ChatPromptTemplate?
ChatPromptTemplate 用于构建多角色对话场景,生成消息列表而非纯文本。
PromptTemplate vs ChatPromptTemplate 对比:
| 特性 | PromptTemplate | ChatPromptTemplate |
|---|---|---|
| 输出类型 | 字符串 str |
消息列表 List[BaseMessage] |
| 用途 | 简单文本生成 | 多角色对话 |
| 支持角色 | 无 | System/Human/AI/Tool |
| 对话历史 | 不支持 | 支持(通过占位符) |
1. 构造方法 - 三种参数格式
from langchain_core.prompts import ChatPromptTemplate
# 格式1:tuple 元组 ("role", content) - 最常用
chat_prompt1 = ChatPromptTemplate.from_messages([
("system", "你是一个{name},你的职责是{role}。"),
("human", "{user_input}")
])
# 格式2:dict 字典 {"role": ..., "content": ...}
chat_prompt2 = ChatPromptTemplate.from_messages([
{"role": "system", "content": "你是AI助手,名字叫{name}。"},
{"role": "user", "content": "请问:{question}"}
])
# 格式3:Message 类(显式指定消息类型)
from langchain_core.messages import SystemMessage, HumanMessage
chat_prompt3 = ChatPromptTemplate.from_messages([
SystemMessage(content="你是AI助手,名字叫{name}。"),
HumanMessage(content="请问:{question}")
])
2. format_messages 方法
ChatPromptTemplate 使用 format_messages() 生成消息列表:
# 构建模板
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个AI开发工程师,你的名字是{name}。"),
("human", "你能帮我做什么?"),
("ai", "我能开发很多{thing}。"),
("human", "{user_input}")
])
# 填充变量,生成消息列表
messages = chat_prompt.format_messages(
name="小谷AI",
thing="AI应用",
user_input="7 + 5等于多少"
)
print(messages)
# 输出:
# [
# SystemMessage(content='你是一个AI开发工程师,你的名字是小谷AI。'),
# HumanMessage(content='你能帮我做什么?'),
# AIMessage(content='我能开发很多AI应用。'),
# HumanMessage(content='7 + 5等于多少')
# ]
3. from_messages vs format_messages
-
ChatPromptTemplate.from_messages()- 从模板定义创建模板对象 -
chat_template.format_messages()- 填充变量,生成实际的消息列表
# from_messages - 创建模板
chat_prompt = ChatPromptTemplate.from_messages([
SystemMessage(content="你是AI助手,你的名字叫{name}。"),
HumanMessage(content="请问:{question}")
])
# format_messages - 填充变量,生成消息
formatted_messages = chat_prompt.format_messages(name="亮仔", question="什么是LangChain")
4. MessagesPlaceholder 占位符
用于动态插入对话历史,实现多轮对话记忆:
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 显式使用 MessagesPlaceholder
prompt1 = ChatPromptTemplate.from_messages([
("system", "你是一个资深的Python开发工程师"),
MessagesPlaceholder("memory"), # 动态插入对话历史
("human", "{question}")
])
# 隐式使用占位符(简写形式,效果相同)
prompt2 = ChatPromptTemplate.from_messages([
("placeholder", "{memory}"), # 等价于 MessagesPlaceholder("memory")
("system", "你是一个资深的Python开发工程师"),
("human", "{question}")
])
# 调用时传入历史消息
prompt_value = prompt1.invoke({
"memory": [
HumanMessage(content="我的名字叫亮仔,是一名程序员"),
AIMessage(content="好的,亮仔你好"),
],
"question": "Python的装饰器是什么?"
})
进阶用法
外部加载 Prompt
可以将 Prompt 模板保存为 JSON 或 YAML 文件,然后加载使用,实现 Prompt 和代码分离。
从 JSON 加载
# prompt.json 文件内容
# {
# "input_variables": ["name", "what"],
# "template": "请{name}讲一个{what}的故事"
# }
from langchain_core.prompts import load_prompt
template = load_prompt("prompt.json", encoding="utf-8")
print(template.format(name="张三", what="搞笑的"))
# 请张三讲一个搞笑的的故事
从 YAML 加载
# prompt.yaml 文件内容
# input_variables:
# - name
# - what
# template: "请{name}讲一个{what}的故事"
from langchain_core.prompts import load_prompt
template = load_prompt("prompt.yaml", encoding="utf-8")
print(template.format(name="年轻人", what="滑稽"))
# 请年轻人讲一个滑稽的故事
多轮对话完整示例
from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
import os
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
# 初始化模型
model = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 构建带记忆的对话模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个旅游助手,为用户提供旅行建议"),
MessagesPlaceholder("history"), # 对话历史占位符
("human", "{question}")
])
# 模拟多轮对话
def chat(prompt, history, question):
messages = prompt.format_messages(history=history, question=question)
response = model.invoke(messages)
# 更新历史
history.append(HumanMessage(content=question))
history.append(AIMessage(content=response.content))
return response.content, history
# 开始对话
history = []
response1, history = chat(prompt, history, "推荐几个国内旅游城市")
print(f"AI: {response1}")
response2, history = chat(prompt, history, "北京有什么好吃的?")
print(f"AI: {response2}")
response3, history = chat(prompt, history, "那上海呢?")
print(f"AI: {response3}")
组合提示词模板
通过将多个子提示(Prompt)按一定逻辑顺序或层级组合起来,形成一个复杂任务的整体 Prompt:
from langchain_core.prompts import PromptTemplate
# 方式1:直接拼接
template = PromptTemplate.from_template("请用一句话介绍{topic},要求通俗易懂\n") + "内容不超过{length}个字"
prompt = template.format(topic="LangChain", length=100)
# 方式2:变量拼接
prompt_a = PromptTemplate.from_template("请用一句话介绍{topic},要求通俗易懂\n")
prompt_b = PromptTemplate.from_template("内容不超过{length}个字")
prompt_all = prompt_a + prompt_b
prompt = prompt_all.format(topic="LangChain", length=200)
模板变量类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 普通变量 | 需要手动传入 | {question}, {name} |
| 部分变量 | 预绑定值,可不传 | partial_variables={"time": now} |
| 占位符 | 动态插入消息列表 | MessagesPlaceholder("memory") |
注意事项
1. load_dotenv() 必须放在最前面
# 正确:放在最前面
import os
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
# 错误:被注释或放在后面
# load_dotenv() # 这行被注释了,导致 API Key 读取不到
2. temperature 范围
阿里云 DashScope 要求 temperature 在 0.0 到 2.0 之间(不包含2.0):
temperature=0.0 # 最稳定
temperature=0.7 # 适中(推荐日常使用)
temperature=1.9 # 很随机(创意场景)
temperature=2.0 # ❌ 错误:超出范围会报错
3. 响应对象没有 content_blocks 属性
# 错误:content_blocks 不存在
print(response.content_blocks)
# 正确:使用 content 获取回复内容
print(response.content)
4. 异步调用必须用 asyncio.run()
# 正确
asyncio.run(async_function())
# 错误:直接调用不会执行
async_function()
5. astream 必须用 async for
# 正确
async for chunk in response:
print(chunk.content)
# 错误:不能用普通 for
for chunk in response: # 不会迭代
print(chunk.content)
6. 区分 PromptTemplate 和 ChatPromptTemplate
# PromptTemplate - 输出字符串
from langchain_core.prompts import PromptTemplate
template = PromptTemplate.from_template("你是{role}专家")
print(template.format(role="Python")) # 字符串
# ChatPromptTemplate - 输出消息列表
from langchain_core.prompts import ChatPromptTemplate
chat = ChatPromptTemplate.from_messages([("human", "你是{role}专家")])
print(chat.format_messages(role="Python")) # 消息列表