(LangChain实战13):LangChain 自定义实现对话记忆功能,超详细入门版

在使用 LangChain 开发对话机器人时,记忆功能是核心需求之一, 让机器人能记住之前的对话内容,实现上下文连贯的交互。本文不使用 LangChain 封装好的记忆组件,而是通过自定义列表存储历史消息 + 消息占位符的方式,从零实现基础的对话记忆功能,代码简单易懂,适合入门学习。

核心实现思路

实现自定义对话记忆的核心逻辑只有 3 步,非常清晰:

  1. 定义一个列表,专门用于存储每一轮的用户消息(HumanMessage)和 AI 回复消息(AIMessage);
  2. 在构建对话提示模板时,使用MessagesPlaceholder消息占位符,预留历史对话的位置;
  3. 每一轮对话完成后,将当前的用户消息和 AI 回复消息追加到历史列表中,下一轮调用模型时将历史列表传入占位符,实现上下文关联。

环境准备

首先需要安装本次开发所需的依赖库,执行以下命令即可:

pip install langchain-core langchain-openai python-dotenv
  • langchain-core:LangChain 的核心库,提供提示模板、消息类型等基础组件;
  • langchain-openai:对接 OpenAI / 兼容 OpenAI 接口的大模型(如深度求索 DeepSeek);
  • python-dotenv:加载.env 文件中的环境变量,保护 API_KEY 等敏感信息。

同时需要在项目根目录创建.env文件,配置大模型的基础地址和 API_KEY(以 DeepSeek 为例,其他兼容 OpenAI 接口的模型配置方式一致):

# .env文件内容
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_API_KEY=你的DeepSeek_API_KEY

代码分步拆解讲解

下面我们逐段讲解代码的实现逻辑,每一步都标注核心作用,确保能看懂每一行代码的意义。

第一步:导入所需模块和类

import os
from dotenv import load_dotenv
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
  • os + load_dotenv:加载系统环境变量和.env 文件中的自定义环境变量;
  • AIMessage/HumanMessage:LangChain 的核心消息类,分别用于表示 AI 的回复和用户的提问,是实现对话记忆的基础数据类型
  • ChatPromptTemplate/MessagesPlaceholder:构建对话式提示模板,MessagesPlaceholder是实现历史消息插入的核心占位符
  • ChatOpenAI:对接 OpenAI 兼容接口的大模型客户端,用于调用大模型生成回复。

第二步:加载环境变量并初始化大模型

# 加载.env文件中的环境变量
load_dotenv()

# 构建大模型实例
llm = ChatOpenAI(
    model="deepseek-chat",  # 要调用的模型名称(DeepSeek对话模型)
    base_url=os.getenv('OPENAI_BASE_URL'),  # 从环境变量读取模型基础地址
    api_key=os.getenv('OPENAI_API_KEY'),    # 从环境变量读取API_KEY
)
  • load_dotenv():执行后即可通过os.getenv()获取.env 文件中的配置,避免硬编码敏感信息;
  • ChatOpenAI初始化:这里以 DeepSeek 模型为例,其他如智谱、百川等兼容 OpenAI 接口的模型,只需修改modelbase_url即可,核心参数不变。

第三步:定义历史消息列表,作为记忆载体

# 定义空列表,用于存储所有历史对话消息,实现记忆的核心载体
history = []

这是自定义记忆的核心容器,后续每一轮的HumanMessageAIMessage都会追加到这个列表中,列表的内容就是完整的对话历史。

第四步:自定义函数实现对话 + 记忆核心逻辑

这部分是整个代码的核心,我们拆成模板构建、链构建、模型调用、历史存储4 个小部分讲解:

# 自定义实现记忆功能的函数,接收用户提问,返回AI带上下文的回复
def user_defined(msg: str) -> str:
    # 1. 构建对话提示模板,包含系统提示、历史消息占位符、用户当前问题
    chat_prompt_template = ChatPromptTemplate.from_messages([
        ("system", "你是一个AI助手,你的名字叫{name}"),       # 系统角色定义
        MessagesPlaceholder(variable_name="history"),     # 历史消息占位符,关键!
        ("human", "{question}"),                          # 用户当前问题
    ])

    # 2. 构建LangChain的链,实现「提示模板→大模型」的流水线调用
    chain = chat_prompt_template | llm

    # 3. 打印历史记录(方便调试查看),调用模型生成回复
    for e in history:
        print("历史记录:", e)
    response = chain.invoke({
        "name": "小智",        # 给AI助手命名
        "history": history,   # 将历史消息列表传入占位符
        "question": msg       # 传入用户当前的提问
    })

    # 4. 将本轮消息追加到历史列表,实现记忆持久化
    history.append(HumanMessage(content=msg))            # 追加用户消息
    history.append(AIMessage(content=response.content))  # 追加AI回复消息

    # 返回AI的回复内容
    return response.content

关键知识点讲解

  1. MessagesPlaceholder(variable_name="history"):必须指定唯一的变量名,后续调用invoke时,通过该变量名将历史消息列表传入,实现历史消息的动态插入;
  2. 链的构建chat_prompt_template | llm:LangChain 的管道符语法,等价于将提示模板的输出作为大模型的输入,简化了调用逻辑;
  3. HumanMessage/AIMessage:必须用这两个类封装消息,因为MessagesPlaceholder只接收LangChain 的消息类实例作为输入,直接传字符串会报错;
  4. 历史追加逻辑:每一轮对话完成后,先存用户消息,再存 AI 回复,保证历史列表的消息顺序和实际对话一致。

第五步:主函数实现交互式对话

if __name__ == '__main__':
    # 无限循环实现持续对话
    while True:
        input_message = input("请输入问题: ")
        # 定义退出条件,输入指定字符则退出程序
        if input_message.lower() in ['退出', 'exit', 'quit', 'q']:
            print("再见!")
            break
        # 调用自定义函数,获取AI带上下文的回复
        output_message = user_defined(input_message)
        # 打印AI回复
        print(output_message)
  • 无限循环while True:实现持续的对话交互,直到用户输入退出指令;
  • 退出条件判断:兼容中文和英文退出指令,提升使用体验;
  • 调用user_defined函数:将用户输入传入,获取并打印 AI 的回复。

完整代码

将以上所有部分整合,就是完整的自定义记忆功能代码,可直接复制使用(记得修改.env 文件中的 API_KEY):

import os

from dotenv import load_dotenv
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

# 加载env环境变量
load_dotenv()

# 构建模型
llm = ChatOpenAI(
    model="deepseek-chat",
    base_url=os.getenv('OPENAI_BASE_URL'),
    api_key=os.getenv('OPENAI_API_KEY'),
)

# 历史消息列表,作为记忆载体
history = []


# 自定义实现记忆功能
def user_defined(msg: str) -> str:
    # 定义消息模版,包含系统提示、历史占位符、用户问题
    chat_prompt_template = ChatPromptTemplate.from_messages([
        ("system", "你是一个AI助手,你的名字叫{name}"),
        MessagesPlaceholder(variable_name="history"),
        ("human", "{question}"),
    ])

    # 构建管道链,实现提示模板到模型的调用
    chain = chat_prompt_template | llm
    # 打印历史记录,方便调试查看上下文
    for e in history:
        print("历史记录:", e)
    # 调用模型,传入参数(助手名、历史消息、当前问题)
    response = chain.invoke({"name": "小智", "history": history, "question": msg})
    # 将本轮的用户消息和AI回复存入历史列表,实现记忆
    history.append(HumanMessage(content=msg))
    history.append(AIMessage(content=response.content))
    # 返回AI回复内容
    return response.content


if __name__ == '__main__':
    # 交互式对话循环
    while True:
        input_message = input("请输入问题: ")
        # 退出条件判断
        if input_message.lower() in ['退出', 'exit', 'quit', 'q']:
            print("再见!")
            break
        # 调用自定义函数获取回复并打印
        output_message = user_defined(input_message)
        print(output_message)

运行结果展示

直接运行上述代码,按照提示输入问题,即可看到带上下文记忆的对话效果,以下是实际运行的完整输出:

E:\pythonWorkSpace\pythonProject1\.venv1\Scripts\python.exe "E:\pythonWorkSpace\LangChain\(12)LangChain中的Memory记忆.py" 
请输入问题: 我是Bruk,你好
你好,Bruk!很高兴认识你!我是小智,有什么可以帮你的吗? 😊
请输入问题: 你知道我是谁吗?
历史记录: content='我是Bruk,你好' additional_kwargs={} response_metadata={}
历史记录: content='你好,Bruk!很高兴认识你!我是小智,有什么可以帮你的吗? 😊' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]
根据我们的对话记录,我知道你叫Bruk,这是我们第一次交流时你告诉我的名字。除此之外,我还不了解其他关于你的信息。如果你愿意分享更多,我会很乐意倾听并更好地帮助你! 😊
请输入问题: 

结果分析

  1. 第一次输入我是Bruk,你好,历史列表为空,模型直接回复初次问候;
  2. 第二次输入你知道我是谁吗?,程序先打印了历史列表中的两条消息(用户消息 + AI 回复),模型通过传入的历史列表,准确识别出用户的名字是 Bruk,实现了上下文记忆。
    在这里插入图片描述

核心要点总结

本文通过自定义代码实现 LangChain 的对话记忆功能,核心要点只需记住 3 点:

  1. 列表作为历史消息的载体,存储HumanMessageAIMessage实例;
  2. MessagesPlaceholder在提示模板中预留历史消息的位置,并指定唯一变量名;
  3. 每轮对话后追加消息到历史列表,下一轮调用模型时将列表传入占位符,实现上下文关联。

这种方式是 LangChain 记忆功能的底层实现逻辑,理解后再学习 LangChain 封装好的ConversationBufferMemory等记忆组件,会更加轻松。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐