LangChain快速筑基(带代码)P3-连续对话Memory

怎么让大模型"记住"之前的对话内容呢?怎么在多轮对话呢中保持上下文连贯呢?

LangChain提供了Memory组件。

Memory:记忆

大模型本身通常是无状态的,Memory通过存储与加载历史信息解决了这个问题。

  • 存储 Memory记录对话的每一轮交互(用户的输入和模型的输出)。
  • 加载 在下一次调用 LLM 之前,将相关的历史对话信息加载出来,并以某种形式(通常是作为提示的一部分)提供给 LLM。 比如使用ChatPromptTemplate提示类时,使用MessagesPlaceholder允许在对话模板中动态插入消息列表(如对话历史、用户输入或其他角色消息)。

通过存储、加载对话,LLM 在生成新的回复时,就能"看到"之前的对话历史,从而理解当前的语境,给出更相关、更连贯的回答。

基础 Memory 类型:ConversationBufferMemory

ConversationBufferMemory最简单也最常用的 Memory 类型之一。它会把所有历史对话原封不动地存储起来,并在下次调用时全部传递给 LLM。

ConversationBufferMemory文档:python.langchain.com/api_referen...

下面,让我们创造一个带记忆的对话。

python 复制代码
import os

# 基础对话所需
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import SystemMessage, HumanMessage

# 提示模板 - ConversationChain 有自己的默认模板,但我们也可以自定义
from langchain_core.prompts import (
    ChatPromptTemplate,
    MessagesPlaceholder,  # 非常重要,用于在提示中为历史消息占位
    HumanMessagePromptTemplate
)
# Memory 组件
from langchain.memory import ConversationBufferMemory

# 链 - 我们会使用 ConversationChain
from langchain.chains import ConversationChain

# 环境key
os.environ["DEEPSEEK_API_KEY"] = 'sk-xx'


def get_deepseek_key():
    key = os.getenv('DEEPSEEK_API_KEY')
    if key is None:
        raise ValueError(
            "DEEPSEEK_API_KEY not found in environment variables.")
    return key

# --- LLM 初始化 ---


def create_deepseek_llm():
    api_key = get_deepseek_key()
    if not api_key:
        raise ValueError("没有ds key")
    return ChatDeepSeek(
        model="deepseek-chat",
        temperature=0.1,  # 温度,更具备确定性
        max_tokens=1024,
        timeout=None,
        max_retries=2,
        api_key=api_key
    )

# --- 带记忆的对话测试 ---


def test_conversation_with_buffer_memory():
    print("使用ConversationBufferMemory测试带记忆的对话")
    llm = create_deepseek_llm()

    """
    1.初始化 Memory
    `memory_key="history"` 是 ConversationBufferMemory 默认存储历史记录的变量名。
    `return_messages=True` 表示 memory 将以消息对象列表的形式返回历史记录,这对于 ChatModels 更好。
    """
    memory = ConversationBufferMemory(
        memory_key="history", return_messages=True)

    """
    2. 为ConversationChain自定义一个提示模板
    ConversationChain 有一个默认的提示模板,但我们可以自定义以加入系统消息等。
    使用MessagesPlaceholder,它告诉模板在哪里插入历史消息
    `input` 是 ConversationChain 期望的用户输入变量名。
    """
    prompt_template = ChatPromptTemplate.from_messages(
        [
            SystemMessage("你是一个乐于助人的LangChain专家,擅长简洁明了地解释概念。"),
            MessagesPlaceholder(variable_name="history"),  # Memory中的历史消息会插入这里
            HumanMessagePromptTemplate.from_template("{input}")  # 用户输入会插入这里
        ]
    )

    """
    3. 初始化 ConversationChain
    verbose=True 表示 ConversationChain 会打印出每个消息的处理结果。
    可以让我们看到链的执行过程,包括发送给 LLM 的完整提示
    """
    conversation_chain = ConversationChain(
        llm=llm,
        memory=memory,
        prompt=prompt_template,# 使用自定义的提示模板
        verbose=True
    )
    
    # --- 开始多轮对话 ---
    print("\n 第一轮对话")
    response1 = conversation_chain.invoke({"input": "你好,我是啾啾。请问LangChain中的Memory组件是做什么用的?"})
    # response1 是一个字典,通常包含 'input', 'history', 'response' (LLM的回答)
    print(f"AI 回答: {response1['response']}")

    print("\n--- 查看当前 Memory 内容 ---")
    # load_memory_variables({}) 会加载所有存储的变量,这里主要是 history
    print(memory.load_memory_variables({}))


    print("\n第二轮对话:")
    response2 = conversation_chain.invoke({"input": "很好,那我刚才告诉你我的名字了吗?如果说了,是什么?"})
    print(f"AI 回答: {response2['response']}")

    print("\n--- 再次查看当前 Memory 内容 (应该包含第一轮和第二轮) ---")
    print(memory.load_memory_variables({}))

    print("\n第三轮对话 (测试 AI 是否还记得我叫啾啾):")
    response3 = conversation_chain.invoke({"input": "你觉得我提出的关于Memory组件的问题怎么样?"}) 
    print(f"AI 回答: {response3['response']}")
    
    print("\n--- 测试结束 ConversationBufferMemory ---")
    
if __name__ == '__main__':
    test_conversation_with_buffer_memory()

ConversationBufferWindowMemory

这种 Memory 只会保留最近的 K 轮对话,防止上下文过长超出 LLM 限制或消耗过多 token。

python 复制代码
from langchain.memory import ConversationBufferMemory,ConversationBufferWindowMemory
python 复制代码
# --- 另一种 Memory 类型:`ConversationBufferWindowMemory` ---
# 这种 Memory 只会保留最近的 K 轮对话,防止上下文过长超出 LLM 限制或消耗过多 token。
def test_conversation_with_window_memory():
    print("\n\n--- 开始测试 ConversationBufferWindowMemory (k=2) ---")
    llm = create_deepseek_llm()

    # 1. 初始化 Window Memory,k=2 表示只保留最近2轮对话
    # (Human输入 + AI输出 算一轮交互,但这里k指的是交互的"对数"或消息数,取决于具体实现,通常是交互对)
    # 为了清晰,我们说 k=2 保留最近2次完整的 "Human: ..." 和 "AI: ..." 交换
    window_memory = ConversationBufferWindowMemory(k=2, memory_key="history", return_messages=True)

    prompt_template = ChatPromptTemplate.from_messages([
        SystemMessage(content="你是一个简明扼要的AI助手。"),
        MessagesPlaceholder(variable_name="history"),
        HumanMessagePromptTemplate.from_template("{input}")
    ])

    conversation_chain_window = ConversationChain(
        llm=llm,
        memory=window_memory,
        prompt=prompt_template,
        verbose=True
    )

    print("\n第1轮:")
    conversation_chain_window.invoke({"input": "我喜欢蓝色。"})
    print(f"Memory: {window_memory.load_memory_variables({})}")

    print("\n第2轮:")
    conversation_chain_window.invoke({"input": "我最喜欢的食物是披萨。"})
    print(f"Memory: {window_memory.load_memory_variables({})}") # 应该包含蓝色和披萨

    print("\n第3轮:")
    conversation_chain_window.invoke({"input": "我住在北京。"})
    # 因为 k=2, "我喜欢蓝色" 这一轮对话应该被挤掉了
    print(f"Memory: {window_memory.load_memory_variables({})}") # 应该只包含披萨和北京

    print("\n第4轮 (测试AI是否还记得第一轮内容):")
    response = conversation_chain_window.invoke({"input": "我最开始说的我喜欢什么颜色?"})
    print(f"AI 回答: {response['response']}") # AI 可能不记得了,或猜一个

    print("\n--- 测试结束 ConversationBufferWindowMemory ---")
    

ConversationSummaryMemory

用 LLM 对历史对话进行总结,存储总结而不是完整对话(节省 token,但可能丢失细节,且需要额外 LLM 调用)。

ConversationSummaryBufferMemory

结合了 Buffer 和 Summary,保留最近几轮的完整对话,对更早的对话进行总结。 还有基于知识图谱的 Memory 等更高级的类型。

Memory总结

相关推荐
JaydenAI2 小时前
[拆解LangChain执行引擎] ManagedValue——一种特殊的只读虚拟通道
python·langchain
OPEN-Source3 小时前
大模型实战:搭建一张“看得懂”的大模型应用可观测看板
人工智能·python·langchain·rag·deepseek
一切尽在,你来5 小时前
1.4 LangChain 1.2.7 核心架构概览
人工智能·langchain·ai编程
一切尽在,你来5 小时前
1.3 环境搭建
人工智能·ai·langchain·ai编程
蛇皮划水怪12 小时前
深入浅出LangChain4J
java·langchain·llm
、BeYourself13 小时前
LangChain4j 流式响应
langchain
、BeYourself13 小时前
LangChain4j之Chat and Language
langchain
qfljg15 小时前
langchain usage
langchain
kjkdd19 小时前
6.1 核心组件(Agent)
python·ai·语言模型·langchain·ai编程
渣渣苏1 天前
Langchain实战快速入门
人工智能·python·langchain