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 执行体系。

相关推荐
FreeCode1 小时前
使用LangSmith评估智能体
python·langchain·agent
FreeCode2 小时前
使用LangSmith追踪智能体运行
python·langchain·agent
汗流浃背了吧,老弟!3 小时前
LangChain提取和输出结构化数据
langchain
王国强20098 小时前
LangGraph 如何通过 Checkpoint 实现持久化
langchain
王国强200910 小时前
剖析 LangGraph 的 Super-step 概念
langchain
前端小东18 小时前
Langchain Template 全面指南
langchain·openai
StringKai1 天前
milvus+langchain实现RAG应用
langchain·milvus
王国强20091 天前
Workflows vs Agents:如何选择你的 LLM 应用架构?
langchain
玲小珑1 天前
LangChain.js 完全开发手册(十九)前端 AI 开发进阶技巧
前端·langchain·ai编程
大模型真好玩1 天前
LangChain1.0实战之多模态RAG系统(一)——多模态RAG系统核心架构及智能问答功能开发
人工智能·langchain·agent