一、指南概述
LangChain记忆系统是解决大语言模型(LLM)“无状态天性”与“对话连续性需求”矛盾的核心组件,本质是“上下文管理中间件”。其核心价值在于实现对话状态的持久化存储与动态调用,让AI应用从“单次问答工具”升级为“智能交互助手”,广泛适用于聊天机器人、智能客服、个人助手等场景。
本指南将从核心概念、实战案例、高级拓展到生产落地,系统讲解LangChain记忆系统的使用方法,所有案例均提供完整可运行代码,兼顾入门开发者与进阶需求。
二、核心概念与基础架构
2.1 核心抽象基类
LangChain记忆系统基于两大抽象基类构建,所有具体记忆实现均遵循统一接口规范:
- BaseMemory:通用记忆逻辑层基类,定义
load_memory_variables(加载记忆)、save_context(保存上下文)、clear(清空记忆)三大核心方法。 - BaseChatMessageHistory:对话历史存储基类,专注于对话消息的增删查,核心方法包括
add_message(添加消息)、get_messages(获取消息)、clear(清空消息)。
2.2 核心分类维度
按存储范围划分
- 会话级记忆:存储单次会话内的历史交互,会话结束后记忆清空(如
ConversationBufferMemory)。 - 实体级记忆:存储跨会话的实体信息(如用户偏好、属性),支持长期复用(如
ConversationEntityMemory)。
按上下文格式划分
- 原始文本类:直接存储完整对话历史,上下文完整性高(如
ConversationBufferMemory)。 - 结构化类:将历史信息转换为摘要、实体属性等结构化数据,降低Token消耗(如
ConversationSummaryMemory)。
2.3 核心工作流程
- 存储:将用户输入、AI响应等信息持久化到指定介质(内存、数据库等)。
- 提取:新请求到来时,从存储中提取相关历史信息。
- 注入:将历史信息与当前输入拼接为完整Prompt,传递给LLM。
- 更新:LLM返回结果后,将新的交互信息追加到记忆中,完成更新闭环。
三、核心记忆类型实战
3.1 会话级记忆实战
3.1.1 ConversationBufferMemory(完整会话记忆)
- 核心逻辑:逐句存储完整对话历史,无裁剪或压缩。
- 适用场景:短对话、调试场景,需完整保留上下文。
实战代码:
# 安装依赖 # pip install langchain-openai langchain-core from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain # 初始化LLM llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key="your-api-key") # 初始化记忆组件 memory = ConversationBufferMemory( memory_key="chat_history", # 记忆在Prompt中的键名 return_messages=True # 返回Message对象(而非字符串) ) # 构建对话链 conversation_chain = ConversationChain( llm=llm, memory=memory, verbose=True # 打印执行过程 ) # 多轮对话测试 conversation_chain.invoke({"input": "我叫张三,计划去北京旅游3天"}) conversation_chain.invoke({"input": "我刚才提到的名字是什么?"}) conversation_chain.invoke({"input": "结合我的旅行天数,推荐一下必去景点"})- 优缺点:逻辑简单、上下文完整;长对话易超Token限制,Token消耗高。
3.1.2 ConversationBufferWindowMemory(窗口会话记忆)
- 核心逻辑:仅保留最近N轮对话,通过
k参数控制窗口大小。 - 适用场景:通用多轮对话,需控制上下文长度。
实战代码:
from langchain.memory import ConversationBufferWindowMemory # 初始化窗口记忆(保留最近2轮对话) memory = ConversationBufferWindowMemory( k=2, # 窗口大小:仅保留最近2轮 memory_key="chat_history", return_messages=True ) # 构建并测试对话链(其余代码同3.1.1) conversation_chain = ConversationChain(llm=llm, memory=memory, verbose=True) conversation_chain.invoke({"input": "我叫张三,计划去北京旅游3天"}) conversation_chain.invoke({"input": "北京10月份天气怎么样?"}) conversation_chain.invoke({"input": "我刚才提到的旅行天数是多少?"}) # 能正常回答(在窗口内) conversation_chain.invoke({"input": "我叫什么名字?"}) # 无法回答(超出窗口范围)- 优缺点:自动截断历史,Token消耗可控;可能丢失早期关键信息。
3.1.3 ConversationTokenBufferMemory(Token窗口记忆)
- 核心逻辑:按Token数量控制上下文,超出阈值时裁剪早期内容。
- 适用场景:需精准控制Token消耗的场景,避免模型调用失败。
实战代码:
from langchain.memory import ConversationTokenBufferMemory # 初始化Token窗口记忆 memory = ConversationTokenBufferMemory( llm=llm, # 依赖LLM计算Token数 max_token_limit=300, # 最大Token限制 memory_key="chat_history", return_messages=True ) # 构建并测试对话链(其余代码同3.1.1) conversation_chain.invoke({"input": "我叫张三,计划去北京旅游3天,想看看故宫、长城、颐和园等景点,还想尝尝北京烤鸭和炸酱面"}) conversation_chain.invoke({"input": "推荐一下长城附近的住宿"})- 优缺点:精准控制Token消耗;需额外依赖Token计算工具(如
tiktoken)。
3.1.4 ConversationSummaryMemory(会话摘要记忆)
- 核心逻辑:通过LLM将历史对话压缩为摘要,仅存储摘要信息。
- 适用场景:超长对话,需大幅降低Token消耗。
实战代码:
from langchain.memory import ConversationSummaryMemory # 初始化摘要记忆 memory = ConversationSummaryMemory( llm=llm, # 用于生成摘要的LLM memory_key="chat_history", return_messages=True ) # 构建并测试对话链 conversation_chain = ConversationChain(llm=llm, memory=memory, verbose=True) conversation_chain.invoke({"input": "我叫张三,计划去北京旅游3天,第一天想逛故宫和天安门广场"}) conversation_chain.invoke({"input": "第二天想去八达岭长城,听说那里的景色最壮观"}) conversation_chain.invoke({"input": "第三天打算去颐和园和南锣鼓巷,体验老北京风情"}) conversation_chain.invoke({"input": "总结一下我的旅行计划"}) # 基于摘要精准总结- 优缺点:Token消耗低,支持超长对话;需额外调用LLM生成摘要,可能丢失细节。
3.1.5 ConversationSummaryBufferMemory(混合摘要记忆)
- 核心逻辑:结合原始文本与摘要,未超Token阈值时保留原文,超出后摘要早期内容。
- 适用场景:大多数生产环境,平衡上下文完整性与Token消耗。
实战代码:
from langchain.memory import ConversationSummaryBufferMemory # 初始化混合摘要记忆 memory = ConversationSummaryBufferMemory( llm=llm, max_token_limit=500, # 原文最大Token限制 memory_key="chat_history", return_messages=True ) # 构建并测试对话链(其余代码同3.1.1) conversation_chain.invoke({"input": "我叫张三,计划去北京旅游3天"}) conversation_chain.invoke({"input": "第一天想逛故宫和天安门广场,故宫需要提前预约吗?"}) conversation_chain.invoke({"input": "第二天想去八达岭长城,交通怎么安排比较方便?"}) conversation_chain.invoke({"input": "第三天打算去颐和园和南锣鼓巷,推荐一下当地美食"}) conversation_chain.invoke({"input": "我刚才问了哪些关于交通和预约的问题?"}) # 精准回应- 优缺点:兼顾上下文完整性与Token效率;生产环境首选平衡方案。
3.2 实体级记忆实战
3.2.1 ConversationEntityMemory(实体提取记忆)
- 核心逻辑:自动从对话中提取“实体-属性”对,支持跨会话复用。
- 适用场景:需记忆用户属性、偏好等实体信息的场景。
实战代码:
from langchain.memory import ConversationEntityMemory from langchain_core.prompts import ChatPromptTemplate # 初始化实体记忆 memory = ConversationEntityMemory( llm=llm, memory_key="entities", # 实体信息在Prompt中的键名 return_messages=True ) # 定义包含实体占位符的Prompt prompt = ChatPromptTemplate.from_messages([ ("system", "你是贴心助手,需利用已知实体信息回应用户,实体信息:{entities}"), ("human", "{input}") ]) # 构建对话链 conversation_chain = ConversationChain( llm=llm, memory=memory, prompt=prompt, verbose=True ) # 测试实体记忆功能 conversation_chain.invoke({"input": "我叫张三,喜欢甜食,过敏芒果"}) conversation_chain.invoke({"input": "推荐一款适合我的下午茶"}) # 结合偏好和过敏信息推荐 conversation_chain.invoke({"input": "我刚才说我对什么过敏?"}) # 准确提取实体信息- 核心特性:依赖LLM的实体提取能力,自动构建实体库。
3.2.2 VectorStoreRetrieverMemory(向量检索记忆)
- 核心逻辑:将历史信息转换为向量存储,通过相似性检索提取相关上下文。
- 适用场景:海量历史信息、长周期多会话场景(如私人助手)。
实战代码:
from langchain.memory import VectorStoreRetrieverMemory from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings # 初始化向量存储(Chroma) embeddings = OpenAIEmbeddings(api_key="your-api-key") vector_store = Chroma(embedding_function=embeddings) retriever = vector_store.as_retriever(search_kwargs={"k": 3}) # 检索Top3相关结果 # 初始化向量检索记忆 memory = VectorStoreRetrieverMemory( retriever=retriever, memory_key="chat_history", return_messages=True ) # 构建对话链(其余代码同3.1.1) conversation_chain = ConversationChain(llm=llm, memory=memory, verbose=True) conversation_chain.invoke({"input": "我叫张三,计划10月去北京旅游3天"}) conversation_chain.invoke({"input": "北京10月的平均气温是多少?"}) conversation_chain.invoke({"input": "我的旅行时间是什么时候?"}) # 通过向量检索获取信息- 核心优势:支持海量数据高效检索,避免全量拼接上下文。
四、持久化存储方案实战
4.1 开发环境:内存存储(默认)
- 核心方案:使用
InMemoryChatMessageHistory,内存临时存储。 - 适用场景:本地开发、测试,无需持久化。
实战代码:
from langchain.memory import ConversationBufferMemory from langchain.memory.chat_message_histories import InMemoryChatMessageHistory # 绑定内存存储 chat_history = InMemoryChatMessageHistory() memory = ConversationBufferMemory( chat_memory=chat_history, return_messages=True ) # 测试存储功能 memory.save_context({"input": "我叫张三"}, {"output": "您好!张三"}) print(memory.load_memory_variables({})) # 读取记忆
4.2 生产环境:外部存储集成
4.2.1 Redis存储(高并发场景)
- 适用场景:分布式系统、高吞吐场景。
实战代码:
# 安装依赖:pip install redis langchain-community from langchain.memory.chat_message_histories import RedisChatMessageHistory from langchain.memory import ConversationBufferMemory # 初始化Redis存储(需提前启动Redis服务) chat_history = RedisChatMessageHistory( session_id="user-001", # 会话ID,用于多用户隔离 redis_url="redis://localhost:6379/0" ) # 绑定Redis存储到记忆组件 memory = ConversationBufferMemory( chat_memory=chat_history, return_messages=True ) # 测试持久化功能 memory.save_context({"input": "我叫张三"}, {"output": "您好!张三"}) new_memory = ConversationBufferMemory(chat_memory=RedisChatMessageHistory("user-001", "redis://localhost:6379/0")) print(new_memory.load_memory_variables({})) # 重启后仍可读取
4.2.2 PostgreSQL存储(长期存储场景)
- 适用场景:生产环境、需要长期稳定存储的场景。
实战代码:
# 安装依赖:pip install psycopg2-binary langchain-community from langchain.memory.chat_message_histories import SQLChatMessageHistory from langchain.memory import ConversationBufferMemory # 初始化PostgreSQL存储(需提前创建数据库) chat_history = SQLChatMessageHistory( session_id="user-001", connection_string="postgresql://user:password@localhost:5432/langchain_db" ) # 绑定数据库存储 memory = ConversationBufferMemory(chat_memory=chat_history, return_messages=True) memory.save_context({"input": "我计划去北京旅游"}, {"output": "已为你记录旅行计划"})
4.2.3 SQLite存储(轻量生产场景)
- 适用场景:轻量部署、低并发生产环境。
实战代码:
from langchain.memory.chat_message_histories import SQLChatMessageHistory # 初始化SQLite存储(文件存储,无需额外服务) chat_history = SQLChatMessageHistory( session_id="user-001", connection_string="sqlite:///langchain_memory.db" ) # 后续使用同PostgreSQL方案
五、高级实战:Agent与记忆系统集成
5.1 带记忆的工具调用Agent
- 核心目标:让Agent在调用工具时保留对话状态,支持多轮工具交互。
实战代码:
from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_functions_agent from langchain.memory import ConversationBufferWindowMemory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools import Tool import os # 设置API Key os.environ["OPENAI_API_KEY"] = "your-api-key" # 定义工具:获取当前时间 def get_current_time(): from datetime import datetime return f"当前时间是 {datetime.now().strftime('%Y年%m月%d日 %H:%M')}" tools = [ Tool( name="GetTime", func=get_current_time, description="获取当前精确时间,当用户询问时间相关问题时调用" ) ] # 初始化LLM llm = ChatOpenAI(model="gpt-4-turbo", temperature=0) # 构建Prompt(包含记忆占位符) prompt = ChatPromptTemplate.from_messages([ ("system", "你是有记忆的智能助手,可调用工具回答问题,需结合历史对话提供连贯回应"), MessagesPlaceholder(variable_name="chat_history"), # 记忆注入点 ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad") # 工具调用日志 ]) # 初始化记忆(保留最近2轮) memory = ConversationBufferWindowMemory( k=2, memory_key="chat_history", return_messages=True ) # 创建Agent并绑定记忆 agent = create_openai_functions_agent(llm, tools, prompt) agent_executor = AgentExecutor( agent=agent, tools=tools, memory=memory, verbose=True ) # 多轮测试 agent_executor.invoke({"input": "现在几点了?"}) agent_executor.invoke({"input": "我刚才问的是什么问题?"}) # 记忆工具调用上下文
5.2 自定义记忆组件
- 核心方法:继承
BaseMemory类,实现load_memory_variables和save_context方法。 实战代码(实体提取记忆示例):
from langchain.memory import BaseMemory from langchain_core.pydantic_v1 import BaseModel from typing import Dict, List import spacy # 加载NLP模型(需提前安装:pip install spacy && python -m spacy download en_core_web_lg) nlp = spacy.load("en_core_web_lg") class CustomEntityMemory(BaseMemory, BaseModel): # 存储实体信息的字典 entities: Dict[str, str] = {} # 记忆键名 memory_key: str = "entities" @property def memory_variables(self) -> List[str]: return [self.memory_key] def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, str]: # 加载实体信息,格式化为字符串 entity_str = "\n".join([f"{k}: {v}" for k, v in self.entities.items()]) return {self.memory_key: entity_str} def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None: # 从输入中提取实体(人名、组织、偏好等) user_input = inputs["input"] doc = nlp(user_input) for ent in doc.ents: self.entities[ent.label_] = ent.text # 提取用户偏好类信息(简单规则示例) if "喜欢" in user_input: preference = user_input.split("喜欢")[-1].strip() self.entities["偏好"] = preference # 使用自定义记忆 memory = CustomEntityMemory() conversation_chain = ConversationChain( llm=llm, memory=memory, prompt=ChatPromptTemplate.from_messages([ ("system", "利用实体信息回应:{entities}"), ("human", "{input}") ]), verbose=True ) conversation_chain.invoke({"input": "我叫张三,喜欢登山"}) print(memory.load_memory_variables({})) # 输出提取的实体信息
六、性能优化与最佳实践
6.1 记忆优先级管理
- 时间窗口清理:使用
ConversationBufferWindowMemory的k参数,保留近期对话。 - 内容去重清理:通过语义相似度计算(如Embedding相似度>0.9)删除冗余信息。
- 时效性清理:对时间敏感信息(如临时任务)设置过期时间,自动清理。
6.2 Token消耗优化
- 短对话用
ConversationBufferMemory,长对话切换为SummaryBufferMemory。 - 为
ConversationTokenBufferMemory设置合理的max_token_limit,避免超阈值。 - 向量检索记忆结合上下文压缩,进一步降低Token消耗。
6.3 生产环境关键配置
- 多用户隔离:通过
session_id区分不同用户的记忆,避免交叉污染。 - 定期清理:设置对话过期策略(如7天无交互自动清理),防止存储膨胀。
- 敏感信息加密:对用户手机号、地址等敏感信息加密存储,符合隐私规范。
- 高可用部署:Redis存储配置主从复制,数据库存储开启备份机制。
6.4 常见问题排查
| 问题现象 | 排查方向 | 解决方案 |
|---|---|---|
| 长对话报错“Token超限” | Token消耗失控 | 切换为SummaryBufferMemory或TokenBufferMemory |
| 记忆信息丢失 | 会话隔离失效 | 确认session_id唯一,检查存储介质是否持久化 |
| 实体信息提取不准确 | LLM实体提取能力不足 | 自定义实体提取规则,或更换更强的LLM模型 |
| 向量检索结果无关 | 嵌入模型不匹配 | 更换与业务场景适配的Embedding模型,调整k值 |
七、总结
LangChain记忆系统通过标准化接口和丰富的实现类,为LLM应用提供了灵活的状态管理能力。核心选择逻辑为:短对话用ConversationBufferMemory,通用场景用SummaryBufferMemory,实体记忆用ConversationEntityMemory,海量数据用VectorStoreRetrieverMemory。
生产落地时需重点关注持久化存储、多用户隔离和Token消耗优化,结合具体业务场景选择合适的记忆类型与存储方案。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。