news 2026/5/4 19:08:43

【LangChain 多轮对话】记忆篇

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LangChain 多轮对话】记忆篇

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(encoding='utf-8') ​ model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://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(f"AI: {response.content}") ​ # 更新历史 history.append(HumanMessage(content="推荐几个国内旅游城市")) history.append(AIMessage(content=response.content)) ​ # 第2轮对话(带上历史) messages = history + [HumanMessage(content="成都有什么好吃的?")] response = model.invoke(messages) print(f"AI: {response.content}") ​ # 更新历史 history.append(HumanMessage(content="成都有什么好吃的?")) history.append(AIMessage(content=response.content)) ​ # 第3轮对话 messages = history + [HumanMessage(content="那杭州呢?")] response = model.invoke(messages) print(f"AI: {response.content}")

MessagesPlaceholder 占位符

为什么需要占位符?

构建 Prompt 模板时,话历史的长度是动态的,不可能写死:

  • 第1轮:0条历史

  • 第10轮:10条历史

这时候需要MessagesPlaceholder占位符,在运行时动态插入历史消息。

显式使用 MessagesPlaceholder

from 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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) # 创建记忆链 memory = ConversationBufferMemory() # 自定义Prompt template = """你是一个友好的AI助手。 历史对话: {history} 用户新消息:{input} 你的回复:""" prompt = PromptTemplate( template=template, input_variables=["history", "input"] ) # 创建对话链 chain = ConversationChain( llm=model, memory=memory, prompt=prompt, verbose=True ) # 对话 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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) # 构建带记忆的模板 prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个旅游助手,为用户提供旅行建议"), MessagesPlaceholder("history"), ("human", "{question}") ]) def chat(question, history): """对话函数""" messages = prompt.format_messages(history=history, question=question) response = model.invoke(messages) # 更新历史 history.append(HumanMessage(content=question)) history.append(AIMessage(content=response.content)) return response.content, history # 开始对话 history = [] print("=== 第1轮 ===") answer1, history = chat("推荐几个国内旅游城市", history) print(f"AI: {answer1}") print("\n=== 第2轮 ===") answer2, history = chat("北京有什么好吃的?", history) print(f"AI: {answer2}") print("\n=== 第3轮 ===") answer3, history = chat("那上海呢?", history) # "那上海呢"需要结合上文理解 print(f"AI: {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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) # 改进的系统提示词,让AI更好地理解上下文 prompt = ChatPromptTemplate.from_messages([ ("system", """你是一个专业的旅游顾问。 请根据对话历史,理解用户的上下文。 如果用户用"那...呢"、"还有呢"等指代词,要结合之前的对话来理解。 例如: - 问"北京之后上海呢?" 要理解这是在问上海的旅游推荐"""), MessagesPlaceholder("history"), ("human", "{question}") ]) def chat(question, history): messages = prompt.format_messages(history=history, question=question) response = model.invoke(messages) history.append(HumanMessage(content=question)) history.append(AIMessage(content=response.content)) return response.content, history # 对话测试 history = [] answer1, history = chat("北京有什么景点?", history) print(f"AI: {answer1}") answer2, history = chat("那上海呢?", history) print(f"AI: {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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://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_info=self.user_info, history=self.history, question=question ) response = model.invoke(messages) self.history.append(HumanMessage(content=question)) self.history.append(AIMessage(content=response.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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) # 限制最大Token数为2000 memory = ConversationTokenBufferMemory( llm=model, max_token_limit=2000 ) # 添加大量对话 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(encoding='utf-8') model = init_chat_model( model="qwen-plus", model_provider="openai", api_key=os.getenv("aliQwen-api"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) # 自动总结历史 memory = ConversationSummaryMemory(llm=model) # 添加对话 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(encoding='utf-8') # 创建向量存储 vectorstore = Chroma(embedding_function=OpenAIEmbeddings()) memory = VectorStoreRetrieverMemory( vectorstore=vectorstore, 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(llm=model, max_token_limit=2000) # 方法2:自动总结 from langchain.memory import ConversationSummaryMemory memory = ConversationSummaryMemory(llm=model) # 方法3:只保留最近N轮 def limit_history(history, max_turns=5): 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_info=user_info, history=history, question=question )

3. 如何让AI理解指代词?

# 改进系统提示词 system_prompt = """你是一个专业的AI助手。 请注意理解对话中的指代词: - "那...呢" 通常指代之前提到的事物 - "他/她/它" 指代之前提到的人或物 - "然后呢" 通常继续之前的话题 结合上下文理解用户真实意图。"""

4. 如何持久化对话历史?

import json # 保存到文件 def save_history(history, filename="history.json"): with open(filename, "w", encoding="utf-8") as f: json.dump([msg.to_json() for msg in history], f, ensure_ascii=False) # 从文件加载 def load_history(filename="history.json"): with open(filename, "r", encoding="utf-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_limit=2000
ConversationSummaryMemory自动总结历史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(history=history, question=question) response = model.invoke(messages) history.append(HumanMessage(content=question)) history.append(AIMessage(content=response.content)) return response.content, history
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 19:07:28

2026届毕业生推荐的十大降AI率神器推荐榜单

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 于学术写作跟内容创作里,文本重复率过高属于常见问题,专业的降重网站…

作者头像 李华
网站建设 2026/5/4 19:00:25

4399游戏平台开发技术栈拆解

4399游戏平台开发技术栈拆解 以《怪物世界》为案例一、4399是什么技术底子? 4399本质是一个网页游戏聚合平台,自己不开发引擎,而是为第三方开发者提供发行和流量。平台上的游戏技术栈随时代分成了几个清晰的阶段。二、技术栈演进拆解 阶段1&a…

作者头像 李华
网站建设 2026/5/4 18:56:21

【C++27文件系统权威实测报告】:对比GCC 14/Clang 18/MSVC 19.41,这4个扩展接口在Windows/Linux/macOS行为差异首次公开

更多请点击: https://intelliparadigm.com 第一章:C27文件系统扩展的标准化演进与设计动机 C27 正在将 库从 C17 的基础能力推向工业级健壮性,其核心动因源于现代跨平台应用对元数据精度、并发安全及异步 I/O 的迫切需求。标准化委员会&…

作者头像 李华
网站建设 2026/5/4 18:54:06

实战应用:利用快马平台AI解决C++项目集成第三方C库的编译兼容性问题

最近在开发一个C项目时,遇到了一个典型的技术难题:需要集成一个纯C语言编写的第三方JSON解析库。这个过程中,编译兼容性问题让我头疼了好一阵子。不过通过使用ccswitch和一些CMake技巧,最终完美解决了这个问题。下面就把我的实战经…

作者头像 李华
网站建设 2026/5/4 18:38:27

深度解析:5个高效技巧掌握LX Music桌面版音乐播放器开发

深度解析:5个高效技巧掌握LX Music桌面版音乐播放器开发 【免费下载链接】lx-music-desktop 一个基于 Electron 的音乐软件 项目地址: https://gitcode.com/GitHub_Trending/lx/lx-music-desktop LX Music桌面版是一款基于Electron和Vue 3开发的开源跨平台音…

作者头像 李华