本文深入介绍 LangChain 的 Memory 系统机制,包括 ConversationMemory 类型、历史对话拼接与自动总结功能,助你搭建支持上下文记忆与多轮对话的智能链条。
一、为什么需要 Memory 系统?
LLM 默认无状态,每次调用仅看当前输入,不记忆前文
对话系统要记住上下文,答案才能“接得住”
Memory 系统负责 记录、拼接、管理历史对话,并把相关内容注入 prompt,以维持对话连续性与上下文理解能力
二、Memory 类型概览
| 类型 | 功能 | 适用场景 |
|---|---|---|
| ConversationBufferMemory | 存储完整对话历史 | 短会话或上下文窗口足够 |
| ConversationBufferWindowMemory | 仅保留最后 k 条消息 | 对话较长时防止上下文膨胀 |
| ConversationSummaryMemory | 使用 LLM 自动生成 summary,拼接到 prompt | 对话长、希望压缩上下文时 |
| ConversationSummaryBufferMemory | 综合 buffer + summarization | 多策略混合平衡记忆与上下文长度管理 |
这些 Memory 类型虽已逐步迁移至 LangGraph,但源码支持仍可使用,适合当前链式记忆机制。
三、如何使用 RunnableWithMessageHistory
LangChain 提供 RunnableWithMessageHistory 封装任何 Runnable,实现会话记忆管理:
langchain_core.runnables.history.RunnableWithMessageHistory
实现逻辑简要(How it works):
class RunnableWithMessageHistory(Runnable):
def __init__(
self,
runnable: Runnable, # 被包裹的链或模型
get_session_history: Callable, # 根据 session_id 获取 MessageHistory 对象
input_messages_key: str = ...,
history_messages_key: str = ...
):
...
def invoke(self, input: dict, config: RunnableConfig) -> Any:
# 1. 从 config 中获取 session_id
session_id = config.configurable.get("session_id")
# 2. 调用 get_session_history(session_id) 获取消息记录对象
history = self.get_session_history(session_id)
# 3. 从 history 读取历史消息 → 注入 input 中指定的 key
input[self.history_messages_key] = history.messages
# 4. 执行原始 runnable
output = self.runnable.invoke(input, config)
# 5. 将当前对话的输入/输出消息记录到 history 中
history.add_messages([HumanMessage(...), AIMessage(...)])
return output
作用(What it does):
包装一个模型调用链,如 ChatPromptTemplate | ChatModel
生命周期中自动注入历史消息至 prompt,并保存交互信息
需要传入:get_session_history、input_messages_key、history_messages_key 等参数
不改变原有链的功能,只是在调用前后插入“历史注入 + 历史记录”逻辑
import os
from typing import Dict
from langchain_core.runnables import RunnableWithMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# 模拟一个内存中的历史记录存储(实际部署可替换为 Redis 等)
session_store: Dict[str, ChatMessageHistory] = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in session_store:
session_store[session_id] = ChatMessageHistory()
return session_store[session_id]
# 创建 Prompt 模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个非常专业且友好的助手。"),
("user", "{question}"),
])
# 创建原始模型链
llm = ChatOpenAI(
temperature=0.7,
model="glm-4.5",
openai_api_key=os.getenv("ZAI_API_KEY"),
openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)
chain = prompt | llm
# 包装为带记忆功能的链
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="question", # 输入参数名
history_messages_key="history", # prompt 接收历史的参数名
)
# 执行调用,自动注入历史并记录
response = chain_with_history.invoke(
{"question": "帮我总结一下《实践论》的核心论点,纯文本输出。"},
config={"configurable": {"session_id": "user123"}}
)
print(session_store)
print("-------------------------------")
print(response.content)
{'user123': InMemoryChatMessageHistory(messages=[HumanMessage(content='帮我总结一下《实践论》的核心论点,纯文本输出。', additional_kwargs={}, response_metadata={}), AIMessage(content='《实践论》的核心论点是:**实践是认识的基础、动力、目的和检验真理的唯一标准**。全文围绕认识与实践的辩证关系展开,主要包含以下要点:\n\n1. **实践对认识的决定作用** \n - 认识来源于实践:人类的生产活动是最基本的实践活动,是认识发展的根本来源;阶级斗争、政治生活、科学实验等其他社会实践也深刻影响认识。\n - 实践推动认识发展:从感性认识上升到理性认识,离不开实践提供的反复观察和材料积累。\n - 实践是认识的目的:认识的根本任务在于指导实践、改造世界。\n - 实践是检验真理的唯一标准:只有通过实践才能验证认识的正确性。\n\n2. **认识发展的辩证过程** \n - 认识经历两个阶段:**感性认识**(对事物表面和片面的直观)和**理性认识**(对事物本质和规律的抽象概括),二者在实践基础上统一。\n - 理性认识依赖于感性认识,感性认识有待深化为理性认识。\n - 认识运动是循环往复、不断深化的过程:从实践到认识,再回到实践,如此“实践—认识—再实践—再认识”,每一次循环都推动认识向更高层次发展。\n\n3. **反对教条主义和经验主义** \n - 批判脱离实践的教条主义(空谈理论)和经验主义(固守片面经验),强调理论必须联系实际,在实践中持续修正和发展认识。\n\n4. **改造主观世界与客观世界** \n - 认识世界的最终目的是改造世界,包括改造客观世界(社会与自然)和主观世界(提高认识能力),二者统一于社会实践。\n\n**总结**:《实践论》系统阐述了马克思主义认识论的基本原理,突出强调实践的核心地位,主张通过“知行统一”的动态过程不断接近真理,为实现理论与实践的结合提供了哲学基础。', additional_kwargs={}, response_metadata={'token_usage': {'completion_tokens': 383, 'prompt_tokens': 25, 'total_tokens': 408, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 25}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'finish_reason': 'stop', 'logprobs': None}, id='run--4ade92e9-44f0-427d-a744-61989849df7e-0')])}
-------------------------------
《实践论》的核心论点是:**实践是认识的基础、动力、目的和检验真理的唯一标准**。全文围绕认识与实践的辩证关系展开,主要包含以下要点:
1. **实践对认识的决定作用**
- 认识来源于实践:人类的生产活动是最基本的实践活动,是认识发展的根本来源;阶级斗争、政治生活、科学实验等其他社会实践也深刻影响认识。
- 实践推动认识发展:从感性认识上升到理性认识,离不开实践提供的反复观察和材料积累。
- 实践是认识的目的:认识的根本任务在于指导实践、改造世界。
- 实践是检验真理的唯一标准:只有通过实践才能验证认识的正确性。
2. **认识发展的辩证过程**
- 认识经历两个阶段:**感性认识**(对事物表面和片面的直观)和**理性认识**(对事物本质和规律的抽象概括),二者在实践基础上统一。
- 理性认识依赖于感性认识,感性认识有待深化为理性认识。
- 认识运动是循环往复、不断深化的过程:从实践到认识,再回到实践,如此“实践—认识—再实践—再认识”,每一次循环都推动认识向更高层次发展。
3. **反对教条主义和经验主义**
- 批判脱离实践的教条主义(空谈理论)和经验主义(固守片面经验),强调理论必须联系实际,在实践中持续修正和发展认识。
4. **改造主观世界与客观世界**
- 认识世界的最终目的是改造世界,包括改造客观世界(社会与自然)和主观世界(提高认识能力),二者统一于社会实践。
**总结**:《实践论》系统阐述了马克思主义认识论的基本原理,突出强调实践的核心地位,主张通过“知行统一”的动态过程实现认识的发展与真理的验证,为科学方法论和革命实践提供了哲学基础。
此机制适合单用户/多线程管理,可替换持久化存储(如 Redis)用于实际部署。
四、Memory 类型与历史拼接方法详解
LangChain 的 Memory 系统本质上是对历史消息的持久化与上下文拼接机制,其核心目标是:
维持上下文连贯性(记住历史提问/回答)
节省 Prompt 长度(通过滑窗或摘要机制)
提升用户体验(多轮对话、状态感知)
1. ConversationBufferMemory:最简单的全量对话缓存器
✅ 适用于短对话或窗口足够大的场景
功能说明:
缓存所有历史消息(用户与 AI 的对话)
会被自动拼接注入 Prompt 中
容易超长,但适合简单原型开发
import os
from langchain.chains.conversation.base import ConversationChain
from langchain.memory import ConversationBufferMemory
from langchain_openai import ChatOpenAI
memory = ConversationBufferMemory(return_messages=True)
llm = ChatOpenAI(
temperature=0.7,
model="glm-4.5",
openai_api_key=os.getenv("ZAI_API_KEY"),
openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)
chain = ConversationChain(
llm=llm,
memory=memory,
verbose=False
)
print(chain.invoke(
{"input": "请用一句话回答(不要超过30个汉字):苏联的存在时间区间是什么?"})["response"])
print(chain.invoke({"input": "我刚才问的问题是什么?"})["response"])
2. ConversationBufferWindowMemory:滑动窗口对话历史
✅ 适用于需要历史但受限于 Prompt 长度的中长对话
功能说明:
只保留最后 k 轮对话(默认每轮包含用户+AI 各一条)
防止历史无限增长,减小 Token 压力
控制成本与上下文权衡
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(
k=3, # 仅保留最近3轮消息
return_messages=True
)
搭配使用方式与 ConversationBufferMemory 相同。
3. ConversationSummaryMemory:自动摘要上下文
✅ 适用于历史很长但上下文窗口受限场景
功能说明:
使用 LLM 自动生成对历史对话的总结(如“用户想了解投资建议...”)
将该 summary 注入到 Prompt 中作为上下文
每轮对话后 summary 会动态更新,保持语义完整
import os
from langchain.chains.conversation.base import ConversationChain
from langchain.memory import ConversationSummaryMemory
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
temperature=0.7,
model="glm-4.5",
openai_api_key=os.getenv("ZAI_API_KEY"),
openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)
memory = ConversationSummaryMemory(
llm=llm, # 用于生成摘要的 LLM
return_messages=True,
max_token_limit=300 # 控制 summary 长度
)
chain = ConversationChain(
llm=llm,
memory=memory,
verbose=False
)
response = chain.invoke(dict(input="我最近很焦虑,可能是因为工作压力大。"))
print(response['response'])
print("\n" + "*" * 100 + "\n")
response = chain.invoke(dict(input="你有什么放松建议吗?"))
print(response['response'])
听到你这么说,我很理解你的感受。工作压力确实是现代人常见的焦虑来源之一。你愿意具体聊聊最近工作中遇到了什么特别有压力的事情吗?比如是任务量突然增加、人际关系紧张,还是对未来的不确定性感到担忧?有时候把具体问题梳理出来,本身就能缓解一部分情绪。
另外,如果你需要的话,我可以和你分享一些缓解工作焦虑的小方法,比如:
1. **短期应对**:尝试用“番茄工作法”分割任务,每工作25分钟休息5分钟,避免持续高压;
2. **调整视角**:每天睡前写下3件当天完成的小事(哪怕只是“准时开会”),强化掌控感;
3. **身体调节**:焦虑时容易浅呼吸,可以刻意练习腹式呼吸(吸气4秒→屏息4秒→呼气6秒),帮助神经系统放松。
当然,如果这种状态持续超过两周,并影响到睡眠或日常生活,也建议考虑和专业心理咨询师聊一聊。你最近睡眠和食欲怎么样?
****************************************************************************************************
当然有。既然你提到了工作压力,我们可以从一些简单易行的方法开始。这里有几个层次的建议,你可以根据当下的感受选择尝试:
### 1. **“微休息”技巧(适合工作中即时缓解)**
- **呼吸重置法**:闭上眼睛,用4秒吸气→屏息4秒→用6秒缓慢呼气,重复5次。这能快速平复神经系统。
- **桌面正念**:拿起手边的一个物件(比如水杯),专注感受它的温度、纹理30秒,让大脑从焦虑叙事中抽离。
- **番茄工作法变式**:工作25分钟→强制休息5分钟(**离开座位走动**),每4个循环后休息15分钟。休息时绝对不看工作消息。
### 2. **工作习惯调整**
- **焦虑清单**:把担忧的具体事项写在纸上(例如“明天会议报告可能被质疑”),旁边标注:①最坏结果是什么?②我能控制的部分是什么?③第一步小行动是什么?往往写下来就会发现焦虑被具象化、可控化了。
- **设定“焦虑时段”**:每天给自己10分钟专门用来担忧,其他时间出现焦虑念头时告诉自己:“留到专属时段再处理”。
### 3. **下班后的身心恢复**
- **温差刺激法**:结束工作后用温水洗脸后,再用凉毛巾敷眼周10秒,能快速唤醒副交感神经。
- **15分钟“身份切换仪式”**:比如换掉工作装、点燃香薰、播放特定音乐,暗示大脑“工作模式关闭”。
- **渐进式肌肉放松**:从脚趾开始向上,依次收紧每个肌肉群5秒后彻底放松,感受身体沉入椅子的重量感。
### 4. **长期视角建设**
- **每周做一次“压力源审计”**:记录本周引发强烈焦虑的3件事,观察是否存在模式(例如总是在接到某类任务后崩溃)。
- **创造“成就感档案”**:建立专属文件夹,存放工作成果、同事感谢、学会的新技能记录,焦虑时翻阅。
### 特别提醒:
你之前提到睡眠和食欲可能受影响,如果出现:
- 连续2周以上入睡困难/早醒
- 对曾经喜欢的事物失去兴趣
- 胸闷、手抖等身体症状频繁出现
建议优先考虑**三甲医院临床心理科**或**专业心理咨询师**进行评估。这不是“脆弱”,就像感冒需要吃药一样正常。
**你想先从哪个方法开始尝试?或者需要我针对某个场景提供更具体的方案吗?** 🌿
4. ConversationSummaryBufferMemory:摘要 + 滑窗的混合策略
✅ 适用于既想缩短上下文,又希望保留部分原文历史
功能说明:
保留一部分原始对话(如最近2轮)
对更早的对话进行摘要压缩
综合使用 buffer + summarization 的策略
from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(
llm=ChatOpenAI(),
max_token_limit=500,
return_messages=True
)
5. 自定义 Memory:继承 BaseMemory / BaseChatMessageHistory
如果你希望将消息保存到数据库、Redis、MongoDB 等,也可以通过实现自定义 Memory 类来替换默认行为
from langchain_core.chat_history import BaseChatMessageHistory
class MyCustomMemory(BaseChatMessageHistory):
def __init__(self):
self.messages = []
def add_message(self, message): self.messages.append(message)
def add_messages(self, messages): self.messages.extend(messages)
def clear(self): self.messages.clear()
✅ 小结对比
Memory 类型、优点及适用场景
| Memory | 类型优点 | 适用场景 |
|---|---|---|
| ConversationBufferMemory | 实现简单、保留全部对话原型 | 短对话 |
| ConversationBufferWindowMemory | 控制窗口大小、性能更好 | 中长对话 |
| ConversationSummaryMemory | 自动压缩语义、节省 token | 超长上下文、摘要理解 |
| ConversationSummaryBufferMemory | 兼顾原文与摘要,灵活性最高 | 高质量对话系统 |
总结
Memory 系统让 LLM 拥有“记忆”能力,从无状态到上下文感知
Buffer 简单直观,适合短期交互;Window 和 Summary 可应对长对话
RunnableWithMessageHistory 是目前主流记忆注入入口
可与 LangGraph 持久化结合,构建可扩展、多用户、分支记忆体系