LangChain 设计原理分析⁶ | Memory 系统设计:如何构建上下文感知的链

本文深入介绍 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):

python 复制代码
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_historyinput_messages_keyhistory_messages_key 等参数
  • 不改变原有链的功能,只是在调用前后插入"历史注入 + 历史记录"逻辑
python 复制代码
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(response.content)

此机制适合单用户/多线程管理,可替换持久化存储(如 Redis)用于实际部署。


当然可以。下面是对你提供的内容进行专业、全面的扩展说明 ,包括每种 Memory 类型的功能解析、使用场景完整示例代码


四、Memory 类型与历史拼接方法详解

LangChain 的 Memory 系统本质上是对历史消息的持久化与上下文拼接机制,其核心目标是:

  • 维持上下文连贯性(记住历史提问/回答)
  • 节省 Prompt 长度(通过滑窗或摘要机制)
  • 提升用户体验(多轮对话、状态感知)

1. ConversationBufferMemory:最简单的全量对话缓存器

✅ 适用于短对话或窗口足够大的场景

功能说明:
  • 缓存所有历史消息(用户与 AI 的对话)
  • 会被自动拼接注入 Prompt 中
  • 容易超长,但适合简单原型开发
示例代码:
python 复制代码
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 压力
  • 控制成本与上下文权衡
示例代码:
python 复制代码
from langchain.memory import ConversationBufferWindowMemory

memory = ConversationBufferWindowMemory(
    k=3,  # 仅保留最近3轮消息
    return_messages=True
)

搭配使用方式与 ConversationBufferMemory 相同。


3. ConversationSummaryMemory:自动摘要上下文

✅ 适用于历史很长但上下文窗口受限场景

功能说明:
  • 使用 LLM 自动生成对历史对话的总结(如"用户想了解投资建议...")
  • 将该 summary 注入到 Prompt 中作为上下文
  • 每轮对话后 summary 会动态更新,保持语义完整
示例代码:
python 复制代码
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'])

4. ConversationSummaryBufferMemory:摘要 + 滑窗的混合策略

✅ 适用于既想缩短上下文,又希望保留部分原文历史

功能说明:
  • 保留一部分原始对话(如最近2轮)
  • 对更早的对话进行摘要压缩
  • 综合使用 buffer + summarization 的策略
示例代码:
python 复制代码
from langchain.memory import ConversationSummaryBufferMemory

memory = ConversationSummaryBufferMemory(
    llm=ChatOpenAI(),
    max_token_limit=500,
    return_messages=True
)

此方案对长时间交互特别友好,适合实际产品部署。


5. 自定义 Memory:继承 BaseMemory / BaseChatMessageHistory

如果你希望将消息保存到数据库、Redis、MongoDB 等,也可以通过实现自定义 Memory 类来替换默认行为:

python 复制代码
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()

你可以将其结合到 RunnableWithMessageHistory 或自定义链中。


✅ 小结对比

Memory 类型 优点 适用场景
ConversationBufferMemory 实现简单、保留全部对话 原型、短对话
ConversationBufferWindowMemory 控制窗口大小、性能更好 中长对话
ConversationSummaryMemory 自动压缩语义、节省 token 超长上下文、摘要理解
ConversationSummaryBufferMemory 兼顾原文与摘要,灵活性最高 高质量对话系统

总结

  • Memory 系统让 LLM 拥有"记忆"能力,从无状态到上下文感知
  • Buffer 简单直观,适合短期交互;Window 和 Summary 可应对长对话
  • RunnableWithMessageHistory 是目前主流记忆注入入口
  • 可与 LangGraph 持久化结合,构建可扩展、多用户、分支记忆体系

接下来,我们将解析 LangChain Agent 的决策流程、工具调用与动作推理机制,构建智能 Agent 执行体系。

相关推荐
王国强20092 小时前
LangChain 设计原理分析⁷ | Agent 架构设计详解:决策循环与 ReAct
langchain
掘我的金7 小时前
04_LangChain服务部署与链路监控
langchain
都叫我大帅哥9 小时前
🌟 LangChain回调机制全解析:从入门到实战,打造你的AI智能小助手
python·langchain·ai编程
Chasing__Dreams11 小时前
langchain--1--prompt、output格式、LCEL示例
langchain
王国强20091 天前
LangChain 设计原理分析⁵ | PromptTemplate 模板系统与上下文注入机制
langchain
都叫我大帅哥1 天前
当AI遇上话痨:LangGraph的`trim_messages`裁剪艺术完全指南
python·langchain·ai编程
青衫客362 天前
LLM——使用 LangGraph 构建 ReAct 智能体:多轮对话 + 工具调用 + 可视化流程图
langchain·大模型·llm·agent·langgraph