📄 文件代码内容
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_community.chat_models.tongyi import ChatTongyi
chat_prompt_template = ChatPromptTemplate.from_messages( #from_messages可以用来创建模版对象
[
("system", "你是一个边塞诗人,可以作诗。"),
MessagesPlaceholder("history"), # 消息的占位符,提供history作为key 基于invoke动态注入历史回话记录
("human", "请再来一首唐诗"),
]
)
history_data = [
("human", "你来写一个唐诗"),
("ai", "床前明月光,疑是地上霜,举头望明月,低头思故乡"),
("human", "好诗再来一个"),
("ai", "锄禾日当午,汗滴禾下锄,谁知盘中餐,粒粒皆辛苦"),
]
# StringPromptValue to_string()
prompt_text = chat_prompt_template.invoke({"history": history_data}).to_string()
model = ChatTongyi(model="qwen3-max")
res = model.invoke(prompt_text)
print(res.content, type(res))
🔄 代码流程梳理
-
导入依赖
- 从
langchain_core.prompts导入ChatPromptTemplate和MessagesPlaceholder。 - 从
langchain_community.chat_models.tongyi导入ChatTongyi(通义千问模型封装)。
- 从
-
创建聊天提示模板
- 使用
ChatPromptTemplate.from_messages()构建模板,包含三个部分:- 系统消息(固定角色设定:边塞诗人)。
MessagesPlaceholder("history")------运行时将插入一整段历史对话记录。- 人类消息(当前用户问题:"请再来一首唐诗")。
- 使用
-
准备历史对话数据
history_data是一个列表,包含两轮对话的交替消息(human/ai),模拟多轮对话上下文。
-
模板填充(生成最终提示)
- 调用
chat_prompt_template.invoke({"history": history_data}),将历史消息注入占位符,得到PromptValue对象。 - 调用
.to_string()将该对象转为纯字符串形式(便于传给模型或调试)。
- 调用
-
初始化模型并调用
- 创建
ChatTongyi实例,指定模型为"qwen3-max"。 - 将生成的提示字符串传入
model.invoke(),获得模型响应(AIMessage对象)。
- 创建
-
输出结果
- 打印响应内容(
res.content)和响应对象的类型(AIMessage)。
- 打印响应内容(
💡 高频面试知识点与回答思路
1. ChatPromptTemplate 与 PromptTemplate 的区别
PromptTemplate生成纯文本字符串,适用于非聊天模型(如 text-davinci-003)。ChatPromptTemplate生成消息列表(包含角色),专为聊天模型设计,支持 system、human、ai 角色区分,更符合 ChatGPT 等模型的要求。
2. MessagesPlaceholder 的作用及使用场景
- 它用于在模板中预留一个"插槽",运行时可以插入一整段消息序列(如历史对话、工具返回结果)。
- 与普通字符串占位符不同,它保留消息的角色结构,避免手动拼接丢失角色信息。
- 典型场景:多轮对话历史、工具调用链、记忆注入。
3. invoke 与 format_messages / to_string 的区别
invoke执行模板填充,返回PromptValue(一个封装对象,可能包含多种格式)。format_messages直接返回消息列表(List[BaseMessage]),适合直接传给聊天模型。to_string将PromptValue转为纯字符串,方便调试或与不支持消息列表的接口对接。
4. 如何实现真正的"多轮对话记忆"?
- 该示例只是静态注入预设历史,未实现增量记忆。
- 真正的记忆需要在每次对话后将新消息追加到历史列表,并在下一轮调用时传入更新后的完整列表。
- 可以结合
RunnableWithMessageHistory或自定义状态管理(如 LangGraph 中的 State)实现。
5. 如果历史消息过长,如何应对 Token 限制?
- 截断 :只保留最近 N 轮对话(
ConversationBufferWindowMemory)。 - 摘要 :使用
ConversationSummaryMemory对旧消息进行压缩。 - 向量检索记忆 :将历史消息存入向量库,按需检索相关片段(
VectorStoreRetrieverMemory)。 - LangChain 提供的
trim_messages工具可对消息列表按 token 数修剪。
6. ChatTongyi 与 ChatOpenAI 的异同
- 两者均继承自
BaseChatModel,接口一致(invoke、generate等)。 - 区别在于底层调用的 API 提供商不同(阿里云 vs OpenAI),需配置不同的 API Key 和 Base URL。
- 在 LangChain 中可通过统一的
ChatModel接口无缝切换。
📌 面试回答话术(示例)
"该文件演示了如何使用
ChatPromptTemplate构建聊天提示,利用MessagesPlaceholder注入多轮对话历史,并调用通义千问模型生成诗歌。MessagesPlaceholder是管理对话记忆的关键,它能保持消息角色结构。在实际项目中,我会结合RunnableWithMessageHistory和向量记忆来处理长上下文,确保多轮对话的连贯性,同时避免超长历史带来的 Token 浪费。"