【LangChain】P11 LangChain 提示词模板深度解析(二):ChatPromptTemplate 从入门到精通
ChatPromptTemplate 的核心价值在于结构化组织多角色对话。优先使用根据场景选择合适的输出格式利用 MessagesPlaceholder 和 partial 处理复杂场景2025.10.04 吉林·松原。
在使用 LangChain 构建 AI 应用时,提示词模板是连接用户输入和大语言模型的关键桥梁。今天我们来深入了解 ChatPromptTemplate —— 一个专为对话场景设计的强大工具。
ChatPromptTemplate 是什么
ChatPromptTemplate 是 LangChain 中专为多角色对话场景设计的提示词模板类。它通过结构化的方式组织 System、Human、AI 等不同角色的消息,让复杂对话的构建变得清晰可控。
与 PromptTemplate 的本质区别:
- PromptTemplate:单一文本模板,适合简单的单次问答
- ChatPromptTemplate:消息列表模板,为多轮对话和角色管理而生
核心设计:元组参数格式
ChatPromptTemplate 使用元组来定义每条消息:
(role, content)
- role:字符串类型,如
"system"
、"human"
、"ai"
- content:字符串类型,支持
{变量名}
占位符
这种设计带来三个优势:
- 代码可读性强,角色一目了然
- 类型安全,减少运行时错误
- 易于扩展和维护
两种实例化方式对比
方式一:构造方法
from langchain_core.prompts import ChatPromptTemplate
chat_prompt = ChatPromptTemplate(
messages=[
("system", "你是一个AI助手,你的名字叫{name}"),
("human", "我的问题是{question}")
],
input_variables=["name", "question"]
)
特点: 显式声明 input_variables
,适合需要严格参数校验的场景。
方式二:from_messages() 【推荐】
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个AI助手,你的名字叫{name}"),
("human", "我的问题是{question}")
])
特点: 自动识别变量,代码更简洁。95% 的场景推荐使用。
四种调用方法的本质差异
理解这四种方法的关键是 输入方式 和 输出类型。
核心对比表
方法 | 输入 | 输出 | 核心用途 |
---|---|---|---|
invoke() | 字典 | ChatPromptValue | 链式调用标准接口 |
format() | 关键字参数 | str | 调试查看 |
format_messages() | 关键字参数 | list[BaseMessage] | 消息对象操作 |
format_prompt() | 关键字参数 | ChatPromptValue | 非链式场景的标准输出 |
1. invoke() - 链式调用标准
result = chat_prompt.invoke({"name": "小智", "question": "1+2*3=?"})
# 输出: ChatPromptValue(messages=[SystemMessage(...), HumanMessage(...)])
关键点: 传入字典,返回 ChatPromptValue 对象,这是 LangChain 链式调用的标准输入格式。
2. format() - 快速调试
result = chat_prompt.format(name="小智", question="1+2*3=?")
# 输出: "System: 你是一个AI助手,你的名字叫小智\nHuman: 我的问题是1+2*3=?"
关键点: 返回字符串,直接看到最终发送给模型的文本,调试利器。
3. format_messages() - 消息级操作
messages = chat_prompt.format_messages(name="小智", question="1+2*3=?")
# 输出: [SystemMessage(content='...'), HumanMessage(content='...')]
# 典型应用:插入历史消息
messages.insert(1, AIMessage(content="我记得你上次问过类似问题"))
关键点: 返回消息对象列表,可直接操作每条消息,适合需要动态调整对话结构的场景。
4. format_prompt() - 非字典输入的标准输出
result = chat_prompt.format_prompt(name="小智", question="1+2*3=?")
# 输出: ChatPromptValue(messages=[...])
关键点: 功能等同 invoke()
,但使用关键字参数而非字典。
实战选择指南
场景一:构建标准 LCEL 链
from langchain_openai import ChatOpenAI
chain = chat_prompt | ChatOpenAI(model="gpt-4")
result = chain.invoke({"name": "小智", "question": "1+2*3=?"})
选择: invoke()
- 字典格式是链式调用的标准
场景二:调试模板输出
print(chat_prompt.format(name="小智", question="测试"))
选择: format()
- 直观查看文本
场景三:动态插入历史对话
messages = chat_prompt.format_messages(name="小智", question="今天天气")
messages.insert(1, HumanMessage(content="昨天:你好"))
messages.insert(2, AIMessage(content="昨天:你好,我是小智"))
选择: format_messages()
- 可操作消息列表
场景四:简单脚本(非链式)
prompt_value = chat_prompt.format_prompt(name="小智", question="测试")
response = llm.generate_prompt([prompt_value])
选择: format_prompt()
- 关键字参数更直观
进阶技巧(选)
技巧 1:MessagesPlaceholder 处理历史对话
from langchain_core.prompts import MessagesPlaceholder
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是助手{name}"),
MessagesPlaceholder(variable_name="history"),
("human", "{question}")
])
# 使用时传入历史消息
chat_prompt.invoke({
"name": "小智",
"history": [
HumanMessage(content="1+1=?"),
AIMessage(content="1+1=2")
],
"question": "那2+2呢?"
})
技巧 2:partial() 预填充变量
# 固定 system 角色名称
partial_prompt = chat_prompt.partial(name="小智")
# 之后只需传入 question
result = partial_prompt.invoke({"question": "你好"})
常见错误与避坑
错误 1:混淆输入格式
# ❌ 错误:invoke() 不接受关键字参数
chat_prompt.invoke(name="小智", question="测试")
# ✅ 正确
chat_prompt.invoke({"name": "小智", "question": "测试"})
错误 2:变量名不匹配
# 模板中是 {question},但传入了 {query}
chat_prompt.invoke({"name": "小智", "query": "测试"}) # ❌ KeyError
总结
ChatPromptTemplate 的核心价值在于结构化组织多角色对话。掌握它的关键是:
- 实例化: 优先使用
from_messages()
- 调用方法: 根据场景选择合适的输出格式
- 进阶应用: 利用 MessagesPlaceholder 和 partial 处理复杂场景
2025.10.04 吉林·松原
更多推荐
所有评论(0)