【第二周】 RAG与Agent实战16:ChatPromptTemplate的使用 —— 打造有记忆的AI

在前节中,学习了 PromptTemplate(通用模板)和
FewShotPromptTemplate(示例模板)。它们非常适合处理单次任务,比如翻译、摘要或问答。

但是,当我们构建一个聊天机器人 时,情况就变了。用户会说:"再写一首",这时候模型必须知道"上一首是什么"才能接得上话。这就需要我们引入历史会话信息(History)

普通的 PromptTemplate

只能处理简单的字符串变量,无法优雅地处理动态增长的对话列表。这时,就需要主角登场了:ChatPromptTemplate

🧠 三大模板对比

在 LangChain 中,我们有三种主要的提示词模板,各司其职:

模板类型 核心作用 适用场景
PromptTemplate 注入简单变量 (String) 单次任务:翻译、提取信息
FewShotPromptTemplate 注入示例数据 (Examples) 复杂推理、格式模仿
ChatPromptTemplate 注入历史消息 (Messages) 多轮对话、角色扮演、Agent

💡 关键区别

  • PromptTemplate.from_template() 接收单个字符串。
  • ChatPromptTemplate.from_messages() 接收消息列表,可以包含 System、Human、AI 等多种角色。

💻 实战案例:作诗机器人的多轮对话

我们将构建一个诗人 AI。用户先让它写一首唐诗,它写了;然后用户说"再来一首",它需要基于之前的语境继续创作。

代码实现

python 复制代码
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_community.chat_models.tongyi import ChatTongyi

# ---------------------------------------------------------
# 第一步:定义聊天模板
# 使用 from_messages 接收一个列表
# ---------------------------------------------------------
chat_prompt_template = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一个专业的诗人,可以作诗。"),
        # 关键点:使用 MessagesPlaceholder 预留历史对话的位置
        MessagesPlaceholder(variable_name="history"),
        ("human", "请再来一首"),
    ]
)

# ---------------------------------------------------------
# 第二步:准备历史对话数据
# 这是一个动态列表,随着对话进行会越来越长
# 格式通常为:(role, content) 元组列表
# ---------------------------------------------------------
history_data = [
    ("human", "写一首唐诗"),
    ("ai", "锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦。"),
    ("human", "好诗再来一个"),
    ("ai", "床前明月光,疑是地上霜。举头望明月,低头思故乡。"),
]

# ---------------------------------------------------------
# 第三步:生成提示词 (必须使用 invoke!)
# 将 history_data 注入到 "history" 占位符中
# ---------------------------------------------------------
# .to_string() 是为了打印查看方便,实际传给 ChatModel 时可以省略
prompt_value = chat_prompt_template.invoke(input={"history": history_data})
prompt_text = prompt_value.to_string()

print("📝 组装后的完整提示词预览:\n")
print(prompt_text)
print("\n" + "="*50 + "\n")

# ---------------------------------------------------------
# 第四步:调用聊天模型
# ---------------------------------------------------------
model = ChatTongyi(model="qwen-max")

# 注意:ChatModel 最好直接接收 prompt_value 对象,或者 messages 列表
# 这里为了演示,我们传入了转换后的字符串(虽然不推荐,但也能工作)
# 最佳实践是:res = model.invoke(prompt_value) 
res = model.invoke(input=prompt_text)

print("🤖 AI 的新作品:\n")
print(res.content)

️ 运行结果逻辑分析

当代码运行时,ChatPromptTemplate 会将 history_data 中的每一条消息插入到 MessagesPlaceholder 的位置。最终发送给模型的提示词结构如下:

text 复制代码
System: 你是一个专业的诗人,可以作诗。
Human: 写一首唐诗
AI: 锄禾日当午...
Human: 好诗再来一个
AI: 床前明月光...
Human: 请再来一首  <-- 这是当前最新的问题

模型看到完整的上下文后,就能明白"再来一首"是指"再写一首像前面那样的唐诗",从而给出连贯的回答。


🔍 核心知识点解析

1. MessagesPlaceholder 的作用

这是 ChatPromptTemplate 最强大的功能之一。

  • 问题:历史对话是动态的。第一轮对话时 history 为空,第十轮对话时 history 有 20 条消息。我们无法在写代码时把 history 写死在字符串里。
  • 解决MessagesPlaceholder(variable_name="history") 就像一个插槽 。它在模板中占据一个位置,但在运行时才会被填入真实的 history_data 列表。

2. 为什么必须用 invoke 而不能用 format

这是很多初学者容易踩的坑!

  • .format() 的局限 :它只能做简单的字符串替换({key} -> value)。如果你传入一个列表给 {history},它会试图把整个列表转换成字符串(比如 "['...', '...']"),这会破坏消息的结构,模型根本看不懂。
  • .invoke() 的强大 :它是 LangChain 的标准接口。它知道 MessagesPlaceholder 需要的是一个消息列表对象 ,而不是字符串。它会智能地将列表中的每个元组 (role, content) 转换为模型能理解的 BaseMessage 对象。

⚠️ 结论 :只要你的模板里用了 MessagesPlaceholder必须 使用 .invoke().format() 会报错或产生错误结果。

3. 返回值类型:PromptValue

和之前一样,chat_prompt_template.invoke() 返回的是一个 ChatPromptValue 对象。

  • 它可以调用 .to_string() 变成纯文本(适合调试或 LLM)。
  • 它可以调用 .to_messages() 变成消息列表(最适合 ChatModel)。

在上面的代码中,虽然我们用了 .to_string() 转成字符串传给模型,但在生产环境中,建议直接传对象:

python 复制代码
# ✅ 最佳实践
prompt_value = chat_prompt_template.invoke({"history": history_data})
res = model.invoke(prompt_value) 

🚀 总结

本节课我们掌握了构建多轮对话系统的关键技术:

  1. ChatPromptTemplate:专为聊天场景设计的模板类,支持多角色消息列表。
  2. MessagesPlaceholder:用于动态注入历史对话记录的"插槽",解决了上下文长度变化的问题。
  3. Invoke vs Format :深刻理解了在处理结构化数据(如消息列表)时,必须使用 invoke 方法。

有了 ChatPromptTemplate,我们的 AI 就不再是"金鱼记忆"(只有7秒),而是拥有了长期记忆,能够进行流畅的多轮交互。

相关推荐
测试_AI_一辰2 小时前
AI系统测试:LLM 在系统中负责什么,怎么测试?
人工智能·功能测试·ai·ai编程
软件资深者2 小时前
Coze自动化工作流+Agent智能体实战教程(0基础入门,附多场景实操)
运维·人工智能·ai·自动化·工作流·扣子·课程
2501_948114242 小时前
OpenClaw + 星链4SAPI:打造AI自动化“智能体舰队”,从数据采集到模型调度的终极实战
大数据·人工智能
沪漂阿龙2 小时前
大模型如何分清“我爱你”和“你爱我”?——深度拆解位置编码的奥秘
人工智能
Tadas-Gao2 小时前
权力的游戏:当AI龙虾获得Root权限
人工智能·架构·系统架构·大模型·llm·openclaw
九河云2 小时前
教育行业上云实践:从在线课堂到智慧校园的架构升级
大数据·运维·人工智能·安全·架构·数字化转型
xier_ran2 小时前
【第二周】RAG与Agent实战13:通用提示词模板 (PromptTemplate)
langchain·prompt·rag·王浩宇
工边页字3 小时前
AI产品面试官超喜欢问:什么是 Embedding,它是怎么工作的 ?
前端·人工智能·后端