06 多轮对话记忆
06 多轮对话记忆一、为什么需要记忆大模型本身是无状态的每次调用都是独立的。多轮对话需要我们手动管理历史消息。场景问题解决方案客服机器人用户说它多少钱模型不知道它指什么传入历史对话上下文任务助手用户说把刚才那个改一下记住之前的任务内容知识问答用户追问能详细说说吗保留之前的检索结果二、Memory 类型总览Memory 类型说明适用场景ConversationBufferMemory保存所有历史消息短对话、调试ConversationBufferWindowMemory只保留最近 K 轮控制上下文长度ConversationSummaryMemory用 LLM 总结历史长对话、节省 tokenConversationTokenBufferMemory按 token 数量截断精确控制成本三、ConversationBufferMemory 基础用法 ConversationBufferMemory 基础演示 运行方式python 06_基础记忆.py fromlangchain.memoryimportConversationBufferMemoryfromlangchain.chainsimportConversationChainfromlangchain_openaiimportChatOpenAI# 1. 创建记忆对象memoryConversationBufferMemory()# 2. 手动添加历史消息memory.save_context({input:你好我叫小明},{output:你好小明有什么可以帮你的吗})memory.save_context({input:我想学习LangChain},{output:很好的选择LangChain是大模型应用开发框架。})# 3. 查看记忆内容print(记忆变量,memory.load_memory_variables({}))# 输出{history: Human: 你好我叫小明\nAI: 你好小明...\nHuman: 我想学习LangChain\nAI: 很好的选择...}# 4. 创建带记忆的对话链llmChatOpenAI(modelqwen-plus,temperature0)conversationConversationChain(llmllm,memorymemory,verboseTrue# 打印详细执行过程)# 5. 多轮对话response1conversation.predict(input我叫什么名字)print(f回答1:{response1})# 模型会记住用户叫小明response2conversation.predict(input我刚才说想学什么)print(f回答2:{response2})# 模型会记住用户想学LangChain四、ConversationBufferWindowMemory只保留最近 K 轮对话避免上下文过长 ConversationBufferWindowMemory 演示 运行方式python 06_窗口记忆.py fromlangchain.memoryimportConversationBufferWindowMemory# 只保留最近 3 轮对话memoryConversationBufferWindowMemory(k3)# 添加 5 轮对话foriinrange(5):memory.save_context({input:f问题{i1}},{output:f回答{i1}})# 查看记忆 - 只有最近 3 轮print(memory.load_memory_variables({}))# 输出只有问题3-5问题1-2被丢弃五、ConversationSummaryMemory用 LLM 自动总结历史节省 token ConversationSummaryMemory 演示 运行方式python 06_总结记忆.py fromlangchain.memoryimportConversationSummaryMemoryfromlangchain_openaiimportChatOpenAI llmChatOpenAI(modelqwen-plus,temperature0)# 创建总结记忆memoryConversationSummaryMemory(llmllm)# 添加长对话memory.save_context({input:我是一个Python开发者正在学习大模型开发},{output:了解Python是大模型开发的主流语言。})memory.save_context({input:我已经学完了LangChain现在在学LangGraph},{output:很好的进度LangGraph适合构建复杂的Agent工作流。})memory.save_context({input:我想做一个RAG系统作为秋招项目},{output:RAG是很好的项目方向企业级落地需求大。})# 查看总结 - 而不是原始对话print(memory.load_memory_variables({}))# 输出总结形式如用户是Python开发者正在学习大模型开发已完成LangChain正在学LangGraph计划做RAG项目...六、ConversationTokenBufferMemory按 token 数量控制记忆大小 ConversationTokenBufferMemory 演示 运行方式python 06_token记忆.py fromlangchain.memoryimportConversationTokenBufferMemoryfromlangchain_openaiimportChatOpenAI llmChatOpenAI(modelqwen-plus)# 限制记忆最多 500 tokensmemoryConversationTokenBufferMemory(llmllm,max_token_limit500)# 添加对话memory.save_context({input:请详细解释RAG的原理},{output:RAG检索增强生成是一种结合检索和生成的技术...长回答})# 当超过 500 tokens 时自动截断早期消息print(f当前 token 数:{memory.llm.get_num_tokens(memory.buffer)})七、在 LCEL 中使用 Memory LCEL Memory 演示 运行方式python 06_LCEL记忆.py fromlangchain_openaiimportChatOpenAIfromlangchain.memoryimportConversationBufferMemoryfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_core.runnablesimportRunnablePassthrough# 1. 创建记忆memoryConversationBufferMemory(return_messagesTrue)# 2. 创建提示词模板 - 使用 MessagesPlaceholder 占位promptChatPromptTemplate.from_messages([(system,你是一个有帮助的AI助手。),MessagesPlaceholder(variable_namehistory),# 历史消息占位(human,{input})])# 3. 创建链llmChatOpenAI(modelqwen-plus,temperature0)defget_history(input_dict):returnmemory.load_memory_variables(input_dict)[history]chain(RunnablePassthrough.assign(historyget_history)|prompt|llm)# 4. 多轮对话defchat(user_input):responsechain.invoke({input:user_input})# 保存到记忆memory.save_context({input:user_input},{output:response.content})returnresponse.content# 测试print(chat(你好我叫小明))print(chat(我叫什么))# 模型会记住小明八、完整对话系统示例 完整多轮对话系统 运行方式python 06_完整对话系统.py fromlangchain_openaiimportChatOpenAIfromlangchain.memoryimportConversationBufferWindowMemoryfromlangchain.chainsimportConversationChainfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderclassChatBot:def__init__(self,modelqwen-plus,k10):self.llmChatOpenAI(modelmodel,temperature0.7)self.memoryConversationBufferWindowMemory(kk,return_messagesTrue)# 自定义提示词self.promptChatPromptTemplate.from_messages([(system,你是一个友善的AI助手。 请根据对话历史进行有上下文的回复。 如果用户提到之前的内容请基于历史回答。),MessagesPlaceholder(variable_namehistory),(human,{input})])# 创建对话链self.chainConversationChain(llmself.llm,memoryself.memory,promptself.prompt,verboseFalse)defchat(self,user_input:str)-str:发送消息并获取回复responseself.chain.predict(inputuser_input)returnresponsedefget_history(self)-list:获取对话历史returnself.memory.chat_memory.messagesdefclear_history(self):清空历史self.memory.clear()# 使用示例if__name____main__:botChatBot(k5)# 保留最近5轮print( 多轮对话系统 )print(输入 quit 退出clear 清空历史\n)whileTrue:user_inputinput(你: )ifuser_input.lower()quit:breakifuser_input.lower()clear:bot.clear_history()print(历史已清空\n)continueresponsebot.chat(user_input)print(fAI:{response}\n)九、Memory 选择指南场景推荐 Memory理由短对话调试ConversationBufferMemory查看完整历史客服机器人ConversationBufferWindowMemory控制上下文长度长文档对话ConversationSummaryMemory节省 token成本敏感ConversationTokenBufferMemory精确控制成本生产环境ConversationSummaryBufferMemory平衡长度和信息十、常见问题Q1: Memory 和数据库持久化有什么区别Memory是内存中的对话管理适合单次会话。数据库持久化如 MongoDB用于跨会话保存适合生产环境。Q2: 如何在 LangGraph 中使用 MemoryLangGraph 使用检查点机制Checkpointer替代传统 Memory支持状态持久化和恢复。详见 [[11-LangGraph/06-持久化Persistence|LangGraph 持久化]]。Q3: 多轮对话的 token 成本如何控制使用ConversationBufferWindowMemory限制轮数使用ConversationSummaryMemory压缩历史使用ConversationTokenBufferMemory按 token 截断相关笔记[[01-LangChain概述]] · [[03-提示词模板与Chains]] · [[05-Agents智能体]]