LangChain 多轮对话完全指南目录什么是多轮对话对话历史管理MessagesPlaceholder 占位符对话记忆机制多轮对话实战进阶用法什么是多轮对话单轮对话 vs 多轮对话单轮对话每次独立问答不记住之前的内容# 单轮每次都是全新的开始 response model.invoke(北京天气如何) response model.invoke(那上海呢) # AI不知道那上海指的是什么多轮对话记住对话历史上下文关联# 多轮记住之前的对话 messages [ HumanMessage(content北京天气如何), AIMessage(content北京今天晴天25度), HumanMessage(content那上海呢) #AI知道那上海指的是上海的天气] response model.invoke(messages)为什么需要多轮对话场景单轮问题多轮优势追问那上海呢自动理解指代上文澄清不对是冬天记住之前的错误修正任务延续继续写代码记得之前写了什么个性化我的名字是小明记住用户信息对话历史管理最简单的多轮对话from langchain.chat_models import init_chat_model from langchain.messages import SystemMessage, HumanMessage, AIMessage import os from dotenv import load_dotenv ​ load_dotenv(encodingutf-8) ​ model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) ​ # 构建对话历史 messages [ SystemMessage(content你是一个旅游助手), HumanMessage(content推荐几个国内旅游城市), AIMessage(content我推荐成都、杭州、厦门、丽江), HumanMessage(content成都有什么好吃的), ] ​ response model.invoke(messages) print(response.content)对话历史累积# 初始化对话历史 history [] ​ # 第1轮对话 messages history [ HumanMessage(content推荐几个国内旅游城市) ] response model.invoke(messages) print(fAI: {response.content}) ​ # 更新历史 history.append(HumanMessage(content推荐几个国内旅游城市)) history.append(AIMessage(contentresponse.content)) ​ # 第2轮对话带上历史 messages history [HumanMessage(content成都有什么好吃的)] response model.invoke(messages) print(fAI: {response.content}) ​ # 更新历史 history.append(HumanMessage(content成都有什么好吃的)) history.append(AIMessage(contentresponse.content)) ​ # 第3轮对话 messages history [HumanMessage(content那杭州呢)] response model.invoke(messages) print(fAI: {response.content})MessagesPlaceholder 占位符为什么需要占位符在构建 Prompt 模板时对话历史的长度是动态的不可能写死第1轮0条历史第10轮10条历史这时候需要MessagesPlaceholder占位符在运行时动态插入历史消息。显式使用 MessagesPlaceholderfrom langchain_core.messages import SystemMessage, HumanMessage, AIMessage from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder ​ # 构建模板占位符用于插入对话历史 prompt ChatPromptTemplate.from_messages([ (system, 你是一个资深的Python开发工程师请认真回答我提出的Python相关的问题), MessagesPlaceholder(memory), # 动态插入对话历史 (human, {question}) ]) ​ # 调用时传入历史消息 prompt_value prompt.invoke({ memory: [ HumanMessage(content我的名字叫亮仔是一名程序员), AIMessage(content好的亮仔你好很高兴认识你), ], question: Python的装饰器是什么 })隐式使用占位符# 隐式写法(placeholder, {memory}) 等价于 MessagesPlaceholder(memory) prompt ChatPromptTemplate.from_messages([ (placeholder, {memory}), (system, 你是一个资深的Python开发工程师), (human, {question}) ]) ​ prompt_value prompt.invoke({ memory: [ HumanMessage(content我的名字叫亮仔), AIMessage(content好的亮仔你好), ], question: 装饰器是什么 })两种写法对比# 显式更清晰推荐 MessagesPlaceholder(memory) ​ # 隐式更简洁 (placeholder, {memory})对话记忆机制什么是记忆机制记忆机制是AI 应用记住之前对话内容的能力。常见实现方式类型说明适用场景ConversationBufferMemory完整保存所有历史对话短、上下文重要ConversationTokenBufferMemory按Token数限制对话长、需要控制成本ConversationSummaryMemory自动总结历史超长对话VectorStoreRetrieverMemory向量检索记忆超长对话、语义检索ConversationBufferMemory最简单的记忆方式保存完整对话历史from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain ​ # 创建记忆对象 memory ConversationBufferMemory() ​ # 添加对话历史 memory.save_context({input: 我叫小明}, {output: 你好小明}) memory.save_context({input: 我最喜欢的颜色是蓝色}, {output: 蓝色是很棒的选择}) ​ # 加载历史 history memory.load_memory_variables({}) print(history) # {history: Human: 我叫小明\nAI: 你好小明\nHuman: 我最喜欢的颜色是蓝色\nAI: 蓝色是很棒的选择}结合 LangChain 链使用from langchain.chat_models import init_chat_model from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain from langchain.prompts import PromptTemplate import os from dotenv import load_dotenv load_dotenv(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 创建记忆链 memory ConversationBufferMemory() # 自定义Prompt template 你是一个友好的AI助手。 历史对话 {history} 用户新消息{input} 你的回复 prompt PromptTemplate( templatetemplate, input_variables[history, input] ) # 创建对话链 chain ConversationChain( llmmodel, memorymemory, promptprompt, verboseTrue ) # 对话 response chain.invoke({input: 我叫小明}) print(response) response chain.invoke({input: 我叫什么名字}) print(response) # 会记住叫小明多轮对话实战基础版本手动管理历史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(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 构建带记忆的模板 prompt ChatPromptTemplate.from_messages([ (system, 你是一个旅游助手为用户提供旅行建议), MessagesPlaceholder(history), (human, {question}) ]) def chat(question, history): 对话函数 messages prompt.format_messages(historyhistory, questionquestion) response model.invoke(messages) # 更新历史 history.append(HumanMessage(contentquestion)) history.append(AIMessage(contentresponse.content)) return response.content, history # 开始对话 history [] print( 第1轮 ) answer1, history chat(推荐几个国内旅游城市, history) print(fAI: {answer1}) print(\n 第2轮 ) answer2, history chat(北京有什么好吃的, history) print(fAI: {answer2}) print(\n 第3轮 ) answer3, history chat(那上海呢, history) # 那上海呢需要结合上文理解 print(fAI: {answer3})进阶版本支持上下文理解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(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 改进的系统提示词让AI更好地理解上下文 prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的旅游顾问。 请根据对话历史理解用户的上下文。 如果用户用那...呢、还有呢等指代词要结合之前的对话来理解。 例如 - 问北京之后上海呢 要理解这是在问上海的旅游推荐), MessagesPlaceholder(history), (human, {question}) ]) def chat(question, history): messages prompt.format_messages(historyhistory, questionquestion) response model.invoke(messages) history.append(HumanMessage(contentquestion)) history.append(AIMessage(contentresponse.content)) return response.content, history # 对话测试 history [] answer1, history chat(北京有什么景点, history) print(fAI: {answer1}) answer2, history chat(那上海呢, history) print(fAI: {answer2}) # 应该理解是在问上海的景点生产版本带用户信息记忆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(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 构建带用户信息的模板 prompt ChatPromptTemplate.from_messages([ (system, 你是一个私人旅行助手。用户信息{user_info}), MessagesPlaceholder(history), (human, {question}) ]) class TravelChat: def __init__(self): self.history [] self.user_info { name: 小明, preferences: 喜欢美食和自然风光, budget: 中等预算, travel_style: 自由行 } def chat(self, question): messages prompt.format_messages( user_infoself.user_info, historyself.history, questionquestion ) response model.invoke(messages) self.history.append(HumanMessage(contentquestion)) self.history.append(AIMessage(contentresponse.content)) return response.content def reset(self): 重置对话历史 self.history [] # 使用 chat TravelChat() print( 对话1 ) print(chat.chat(我叫小明喜欢吃辣帮我推荐一个旅游城市)) print(\n 对话2 ) print(chat.chat(那里有什么好吃的辣味美食))进阶用法Token数限制控制成本对话历史太长会导致 Token 消耗过大需要限制from langchain.memory import ConversationTokenBufferMemory from langchain.chat_models import init_chat_model import os from dotenv import load_dotenv load_dotenv(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 限制最大Token数为2000 memory ConversationTokenBufferMemory( llmmodel, max_token_limit2000 ) # 添加大量对话 for i in range(20): memory.save_context({input: f这是第{i}轮对话}, {output: f这是第{i}轮回复}) # 自动截断旧的历史 history memory.load_memory_variables({}) print(f历史长度: {len(history[history])}) # 会自动保留最新的对话删除旧的自动总结历史超长对话from langchain.memory import ConversationSummaryMemory from langchain.chat_models import init_chat_model import os from dotenv import load_dotenv load_dotenv(encodingutf-8) model init_chat_model( modelqwen-plus, model_provideropenai, api_keyos.getenv(aliQwen-api), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) # 自动总结历史 memory ConversationSummaryMemory(llmmodel) # 添加对话 memory.save_context({input: 我叫小明是一名程序员}, {output: 你好小明}) memory.save_context({input: 我工作5年了}, {output: 经验丰富啊}) memory.save_context({input: 我会Python、Java、Go}, {output: 技术栈很广}) # 获取总结后的历史 history memory.load_memory_variables({}) print(history[history]) # 会自动总结为一段话而不是保留所有对话向量记忆语义检索from langchain.memory import VectorStoreRetrieverMemory from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings from langchain.chat_models import init_chat_model import os from dotenv import load_dotenv load_dotenv(encodingutf-8) # 创建向量存储 vectorstore Chroma(embedding_functionOpenAIEmbeddings()) memory VectorStoreRetrieverMemory( vectorstorevectorstore, search_kwargs{k: 3} # 返回最相关的3条记忆 ) # 保存记忆带描述 memory.save_context( {input: 用户喜欢日料}, {output: 已记录用户的日料偏好} ) memory.save_context( {input: 用户下周要去东京}, {output: 已记录用户的东京行程} ) # 检索相关记忆 memory.load_memory_variables({prompt: 用户有什么美食偏好}) # 会语义检索返回喜欢日料相关记忆常见问题1. 对话历史越来越长怎么办# 方法1限制Token数 from langchain.memory import ConversationTokenBufferMemory memory ConversationTokenBufferMemory(llmmodel, max_token_limit2000) # 方法2自动总结 from langchain.memory import ConversationSummaryMemory memory ConversationSummaryMemory(llmmodel) # 方法3只保留最近N轮 def limit_history(history, max_turns5): return history[-max_turns * 2:] # 每轮2条消息问答2. 如何让AI记住用户信息# 方法1放在系统提示词里 prompt ChatPromptTemplate.from_messages([ (system, 用户叫{name}喜欢{preference}), MessagesPlaceholder(history), (human, {question}) ]) # 方法2每次传入用户信息 messages prompt.format_messages( user_infouser_info, historyhistory, questionquestion )3. 如何让AI理解指代词# 改进系统提示词 system_prompt 你是一个专业的AI助手。 请注意理解对话中的指代词 - 那...呢 通常指代之前提到的事物 - 他/她/它 指代之前提到的人或物 - 然后呢 通常继续之前的话题 结合上下文理解用户真实意图。4. 如何持久化对话历史import json # 保存到文件 def save_history(history, filenamehistory.json): with open(filename, w, encodingutf-8) as f: json.dump([msg.to_json() for msg in history], f, ensure_asciiFalse) # 从文件加载 def load_history(filenamehistory.json): with open(filename, r, encodingutf-8) as f: data json.load(f) return [HumanMessage(**m) if m[type]human else AIMessage(**m) for m in data]总结多轮对话核心概念概念作用代码对话历史记住之前的问答history.append(HumanMessage(...))MessagesPlaceholder动态插入历史到模板MessagesPlaceholder(memory)ConversationBufferMemory完整保存历史memory.load_memory_variables({})ConversationTokenBufferMemory限制Token数max_token_limit2000ConversationSummaryMemory自动总结历史memory.load_memory_variables({})选择记忆类型对话长度短 →ConversationBufferMemory最简单 对话长度中等 → ConversationTokenBufferMemory控制成本 对话长度长 → ConversationSummaryMemory自动总结 对话长度超长 →VectorStoreRetrieverMemory向量检索多轮对话模板from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder ​ prompt ChatPromptTemplate.from_messages([ (system, 你是一个AI助手), MessagesPlaceholder(history), # 对话历史 (human, {question}) ]) ​ def chat(question, history): messages prompt.format_messages(historyhistory, questionquestion) response model.invoke(messages) history.append(HumanMessage(contentquestion)) history.append(AIMessage(contentresponse.content)) return response.content, history