LangChain 对话模板(ChatPromptTemplate)实战指南
从单轮问答到多轮对话,掌握 ChatPromptTemplate 的核心用法与工程落地技巧。
一、为什么需要对话模板?
大语言模型(LLM)本质上是无状态的------每次请求都是独立的。要让模型"记住"上下文、维持角色一致性,需要我们在 prompt 中显式拼接历史对话。
LangChain 的 ChatPromptTemplate 就是为这个场景设计的:它区分 system/human/ai 三种消息角色,让多轮对话的结构清晰可控。
二、核心消息类型
| 消息类型 | 类名 | 角色标识 | 用途 |
|---|---|---|---|
| 系统消息 | SystemMessage |
system |
设定全局角色、规则、约束 |
| 用户消息 | HumanMessage |
human / user |
用户的输入问题或指令 |
| AI 回复 | AIMessage |
ai / assistant |
模型的历史回复 |
| 工具消息 | ToolMessage |
tool |
工具/函数执行结果 |
三、基础用法
3.1 直接传入元组列表(最常用)
python
from langchain.prompts import ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名专业的机床维护工程师,擅长解析海德汉CNC报警代码。"),
("human", "报警码 {code} 是什么意思?"),
])
messages = chat_prompt.format_messages(code="E-616")
print(messages)
输出:
python
[
SystemMessage(content="你是一名专业的机床维护工程师..."),
HumanMessage(content="报警码 E-616 是什么意思?")
]
3.2 使用专门的模板对象(更灵活)
python
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
system_template = "你是一名{role},擅长{skill}。"
human_template = "请分析以下报警:{alarm}"
chat_prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(system_template),
HumanMessagePromptTemplate.from_template(human_template),
])
messages = chat_prompt.format_messages(
role="机床维护工程师",
skill="解析海德汉报警",
alarm="E-616 chuck not clamped"
)
四、多轮对话:MessagesPlaceholder
实际工程中,对话历史是动态生成的,长度不固定。MessagesPlaceholder 就是用来插入可变长度历史记录的占位符。
python
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名机床维护专家,根据历史对话和当前问题给出建议。"),
MessagesPlaceholder(variable_name="history"), # 动态插入历史消息
("human", "{input}")
])
# 模拟历史对话
history = [
("human", "E-616 是什么报警?"),
("ai", "工件夹紧信号未到位。"),
("human", "怎么处理?"),
("ai", "1.检查夹具气压 2.确认工件位置 3.复位传感器。"),
]
messages = chat_prompt.format_messages(
history=history,
input="还是不行,夹具气压正常"
)
生成的完整消息序列:
System: 你是一名机床维护专家...
Human: E-616 是什么报警?
AI: 工件夹紧信号未到位。
Human: 怎么处理?
AI: 1.检查夹具气压 2.确认工件位置 3.复位传感器。
Human: 还是不行,夹具气压正常
五、少样本 + 对话模板的结合
在对话中嵌入少样本示例,教模型输出格式:
python
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名机床维护专家。回答时请遵循以下规则:\n"
"1. 先给出根因分析\n"
"2. 再列出处理步骤(编号)\n"
"3. 最后标注严重程度"),
# 少样本示例(教格式)
("human", "报警码 E-616,信息:chuck not clamped"),
("ai", "根因:工件夹紧信号未到位。\n"
"处理:1.检查气压 2.确认工件位置\n"
"严重:严重"),
("human", "报警码 W-617,信息:Robot signal not dropped"),
("ai", "根因:换料时机器人夹具闭合信号未断开。\n"
"处理:1.检查IO信号线 2.确认换料节拍\n"
"严重:警告"),
# 动态历史
MessagesPlaceholder(variable_name="history"),
# 当前问题
("human", "报警码 {code},信息:{message}")
])
六、对话 + RAG 的结合
将检索到的文档作为上下文注入对话:
python
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名机床维护专家。以下是从知识库检索到的相关文档,请结合文档内容回答问题。"),
("human", "相关文档:\n{context}"),
MessagesPlaceholder(variable_name="history"),
("human", "当前问题:{input}")
])
# 使用示例
messages = chat_prompt.format_messages(
context="E-616: 工件夹紧信号异常,常见于气压不足或传感器故障...",
history=[("human", "之前遇到过 E-616"), ("ai", "已记录。")],
input="现在报警变成了 E-618,主轴过载"
)
七、完整工程示例:对话式报警诊断系统
python
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
class AlarmChatSystem:
def __init__(self):
self.prompt = ChatPromptTemplate.from_messages([
("system", "你是一名资深机床维护工程师,拥有20年海德汉系统维修经验。"),
# 少样本:教输出格式
("human", "报警:E-616 chuck not clamped"),
("ai", "【根因】工件夹紧信号未到位\n"
"【处理】1.检查夹具气压(>0.5MPa)\n"
" 2.确认工件放置到位\n"
" 3.复位夹紧传感器\n"
"【严重】严重"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
self.history = []
def chat(self, user_input: str) -> str:
messages = self.prompt.format_messages(
history=self.history,
input=user_input
)
# 调用 LLM(此处省略具体调用代码)
# response = llm.invoke(messages)
# 更新历史
self.history.append(("human", user_input))
# self.history.append(("ai", response.content))
return messages # 实际应返回 response.content
# 使用
system = AlarmChatSystem()
print(system.chat("E-618 主轴过载怎么处理?"))
八、各类模板对比
| 模板类型 | 核心类 | 消息角色 | 适用场景 |
|---|---|---|---|
| 基础模板 | PromptTemplate |
无 | 单轮问答、简单任务 |
| 少样本模板 | FewShotPromptTemplate |
无 | 需要示例引导格式 |
| 对话模板 | ChatPromptTemplate |
system/human/ai | 多轮对话、角色扮演 |
| 历史占位 | MessagesPlaceholder |
动态 | 历史长度不固定 |
九、总结
- ChatPromptTemplate 的本质:用角色区分消息,让 LLM 理解"谁在说话"
- MessagesPlaceholder 是关键:解决动态历史长度的工程问题
- 组合使用威力更大:对话模板 + 少样本(教格式)+ RAG(给知识)= 完整的对话式 AI 应用
- 历史管理要注意:对话过长时要做截断或摘要,避免超出模型上下文窗口
注:本文基于 LangChain 框架,核心思想适用于所有支持消息角色区分的 LLM API。