【LangChain核心组件】Memory:让大语言模型拥有持续对话记忆的工程实践

目录

一、Memory架构设计解析

1. 核心组件关系图

2. 代码中的关键实现

二、对话记忆的工程实现

1. 消息结构化存储

2. 动态提示组装机制

三、Memory类型选型指南

四、生产环境优化实践

1. 记忆容量控制

2. 记忆分片策略

3. 记忆检索增强

五、典型问题调试技巧

1. 记忆丢失问题排查

.2. 消息类型不匹配修复

六、扩展应用场景

1. 个性化对话系统

2. 多模态记忆存储

示例代码关键方法对照表

1、库名解析

2、ConversationBufferMemory关键参数

3、LLMChain()关键参数

示例代码


在AI对话系统开发中,让模型记住上下文如同赋予机器"短期记忆",这是构建连贯交互体验的关键。本文通过剖析一个完整的多轮对话实现案例,揭示LangChain的Memory模块如何突破大模型的"金鱼记忆"困境。


一、Memory架构设计解析

1. 核心组件关系图

2. 代码中的关键实现
# 记忆存储初始化(对话历史容器)
chat_memory = ConversationBufferMemory(memory_key="chat_history",  # 存储标识符return_messages=True  # 保持消息对象结构
)# 记忆系统与链的整合
memory_chain = LLMChain(llm=qwen,prompt=prompt,memory=chat_memory  # 记忆注入
)

二、对话记忆的工程实现

1. 消息结构化存储
# 典型记忆存储结构
[HumanMessage(content="你好"),AIMessage(content="您好!有什么可以帮助您?"),HumanMessage(content="讲个笑话"),AIMessage(content="为什么程序员总分不清万圣节和圣诞节?因为Oct31==Dec25!")
]
  • 设计优势:保留原始消息类型,支持角色区分化处理

2. 动态提示组装机制
# 运行时实际发生的提示拼接
final_prompt = [SystemMessage(content="你是一个专业的聊天AI"),HumanMessage(content="你好"),AIMessage(content="您好!有什么可以帮助您?"),HumanMessage(content="讲个笑话")
]
  • 技术价值:使模型始终在完整对话上下文中生成响应


三、Memory类型选型指南

Memory类型存储原理适用场景代码示例
ConversationBufferMemory完整保存所有对话记录短对话调试return_messages=True
ConversationBufferWindowMemory仅保留最近K轮对话移动端轻量化应用k=3
ConversationSummaryMemory存储摘要而非原始对话长文档分析summary_prompt=...
CombinedMemory混合多种存储策略复杂对话系统memories=[buffer, summary]

四、生产环境优化实践

1. 记忆容量控制
from langchain.memory import ConversationBufferWindowMemory# 保留最近3轮对话
optimized_memory = ConversationBufferWindowMemory(k=3,memory_key="chat_history",return_messages=True
)
  • 避免问题:GPT-3.5的4k token限制下,防止长对话溢出

2. 记忆分片策略
class ChunkedMemory:def save_context(self, inputs, outputs):# 将长对话分段存储chunk_size = 500  # 按token计算self.chunks = split_text(inputs['question'], chunk_size)
  • 应用场景:法律咨询、医疗问诊等长文本领域

3. 记忆检索增强
from langchain.retrievers import TimeWeightedVectorStoreRetriever# 基于时间权重的记忆检索
retriever = TimeWeightedVectorStoreRetriever(vectorstore=FAISS(),memory_stream=chat_memory.load_memory_variables({})['chat_history']
)
  • 技术价值:优先召回相关性高且较近期的对话


五、典型问题调试技巧

1. 记忆丢失问题排查
# 打印记忆状态
print(chat_memory.load_memory_variables({}))
# 期望输出:
# {'chat_history': [HumanMessage(...), AIMessage(...)]}
.2. 消息类型不匹配修复
# 错误现象:TypeError: sequence item 0: expected str instance, HumanMessage found
# 解决方案:确保Memory配置return_messages=True

 3. 长对话性能优化

# 监控内存使用
pip install memory_profiler
mprof run python chat_app.py

六、扩展应用场景

1. 个性化对话系统
# 用户画像记忆
profile_memory = ConversationBufferMemory(memory_key="user_profile",input_key=["age", "occupation"]
)# 组合记忆体系
combined_memory = CombinedMemory(memories=[chat_memory, profile_memory])
2. 多模态记忆存储
from langchain_core.messages import ImageMessage# 支持图片记忆
chat_memory.save_context({"question": "分析这张图片"},{"output": ImageMessage(content=image_bytes)}
)

 3. 记忆持久化方案

# SQLite存储实现
from langchain.memory import SQLiteMemorypersistent_memory = SQLiteMemory(database_path="chat.db",session_id="user123"
)

 结语
通过合理运用Memory组件,开发者可以构建出具备以下能力的智能对话系统:
✅ 30轮以上连贯对话
✅ 个性化上下文感知
✅ 长期用户画像记忆
✅ 跨会话状态保持

工作流程图

 

示例代码关键方法对照表

1、库名解析
方法/类名所属模块核心功能
ChatPromptTemplatelangchain.prompts多角色提示模板构建
SystemMessagePromptTemplatelangchain.prompts系统角色提示定义
MessagesPlaceholderlangchain.prompts动态消息占位符
HumanMessagePromptTemplatelangchain.prompts用户消息格式化
ConversationBufferMemorylangchain.memory对话历史缓冲存储
LLMChainlangchain.chains语言模型执行流水线

2、ConversationBufferMemory关键参数
参数名类型作用说明默认值
memory_keystr记忆字典的键名"history"
return_messagesbool是否返回Message对象False
input_keystr输入项的键名None

return_messages=True

  • 必要性

    • MessagesPlaceholder需要Message对象列表(而不仅是字符串)

    • 保持消息类型信息(系统/人类/AI消息)

  • 对比实验

    设置输入格式是否可用
    return_messages=TrueMessage对象列表
    return_messages=False纯文本字符串

3、LLMChain()关键参数
  • 核心参数

    参数类型作用说明
    llmBaseLanguageModel语言模型实例
    promptBasePromptTemplate提示模板
    memoryBaseMemory记忆系统
    verbosebool是否打印执行日志

示例代码

代码说明:

该代码实现了一个基于LangChain的带记忆功能的智能对话系统,主要演示以下核心能力:

1. **对话记忆管理**  
 通过`ConversationBufferMemory`实现对话历史的持久化存储,突破大模型单次请求的上下文限制,支持连续多轮对话。

2. **提示工程架构**  
   采用分层提示模板设计:
   - 系统消息固化AI角色设定
   - `MessagesPlaceholder`动态注入历史对话
   - 用户消息模板接收即时输入

3. **服务集成方案**  
   对接阿里云灵积平台(DashScope)的千问大模型,演示:
   - 第三方模型API调用
   - 参数调优(temperature=0增强确定性)

4. **执行流水线封装**  
   使用`LLMChain`将提示工程、记忆系统、模型调用封装为可复用组件,体现LangChain模块化设计思想。完整技术栈涵盖环境变量管理、类型化消息处理、交互式调试等工程实践。

from langchain.chat_models import ChatOpenAI
from langchain.prompts import (ChatPromptTemplate,MessagesPlaceholder,SystemMessagePromptTemplate,HumanMessagePromptTemplate,
)
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory
import os
from dotenv import load_dotenv#一、加载配置环境
load_dotenv()# 二、初始化ChatOpenAI模型
llm = ChatOpenAI(model="qwen-max",api_key=os.getenv("DASHSCOPE_API_KEY"),openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",temperature=0
)# 三、创建对话提示模板
prompt = ChatPromptTemplate(messages=[SystemMessagePromptTemplate.from_template("You are a nice chatbot having a conversation with a human."),# 这里的`variable_name`必须与记忆中的对应MessagesPlaceholder(variable_name="chat_history"),HumanMessagePromptTemplate.from_template("{question}")]
)#四、定义历史消息存储
# 注意我们设置`return_messages=True`以适配MessagesPlaceholder
# 注意`"chat_history"`与MessagesPlaceholder名称对应
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)#五、创建LLMChain实例,用于处理对话
conversation = LLMChain(llm=llm,prompt=prompt,verbose=True,memory=memory
)#六、定义模拟历史对话消息
# 注意我们只传入`question`变量 - `chat_history`由记忆填充
conversation({"question": "你好"})
conversation({"question":"你能给我讲一个苹果和医生的笑话吗?"})
conversation({"question":"说得好,再讲一个"})
conversation({"question":"讲一个葫芦娃的笑话"})#七、问题输入执行
while True:question = input("请输入问题:")if question.lower() == "exit":response = conversation({"question": "再见"})  # 主动触发结束语print(response['text'])breakresponse = conversation({"question": question})print(response['text'])  # 确保输出模型响应

运行结果

> Entering new LLMChain chain...
Prompt after formatting:
System: You are a nice chatbot having a conversation with a human.


Human: 你好
AI: 你好!有什么可以帮助你的吗?


Human: 你能给我讲一个苹果和医生的笑话吗?
AI: 当然可以,这里有一个经典的笑话:

为什么医生建议每天吃一个苹果?

因为医生需要钱买房子!(实际上原话是 "An apple a day keeps the doctor away",意思是“一天一个苹果,医生远离我”,但这个版本更幽默一些。)

希望这能让你会心一笑!


Human: 说得好,再讲一个
AI: 好的,再来一个苹果和医生的笑话:

为什么苹果不喜欢去看医生?

因为每次医生都会说:“你看起来有点核(核心)问题!”

希望这个也能让你笑一笑!


Human: 讲一个葫芦娃的笑话
AI: 当然可以,这里有一个关于葫芦娃的笑话:

为什么葫芦娃们总是穿肚兜?

希望这个笑话能让你开心一笑!
Human: 回答我刚刚的问题

> Finished chain.


好的,再来一个关于葫芦娃的笑话

为什么葫芦娃们每次都能找到爷爷?

因为不管他们被妖怪抓到哪里,只要喊一声“爷爷,救我!”爷爷就能立刻感应到他们的位置。这大概是因为葫芦娃和爷爷之间有特殊的“GPS”吧!

希望这个笑话能让你笑一笑!
请输入问题:

说明:主要看最后一个问题“回答我刚刚的问题”,可以发现大模型能够根据历史对话再去讲述关于葫芦娃的笑话。这也就说明成功实现了Memory记忆功能。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/77077.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

适应 AI 时代的软件开发流程:用 AI + TDD 构建可维护项目

🧠 适应 AI 时代的软件开发流程:用 AI + TDD 构建可维护项目 本文面向有系统开发经验的工程师,分享如何结合 Git 管理、AI 协作、YAML 驱动与 TDD 开发方式,高效构建一个可维护、可协作、可交付的嵌入式或通用工程项目。适合 BLE 模块、协议栈组件、物联网控制系统等项目落…

使用 chromedriver 实现网络爬虫【手抄】

1、引用 selenium 包 <dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.29.0</version> </dependency> <dependency><groupId>org.seleniumhq.seleniu…

Python项目--基于Python的自然语言处理文本摘要系统

1. 项目概述 自然语言处理(NLP)是人工智能领域中一个重要的研究方向&#xff0c;而文本摘要作为NLP的一个重要应用&#xff0c;在信息爆炸的时代具有重要意义。本项目旨在开发一个基于Python的文本摘要系统&#xff0c;能够自动从长文本中提取关键信息&#xff0c;生成简洁而全…

【Vue #3】指令补充样式绑定

一、指令修饰符 Vue 的指令修饰符&#xff08;Directive Modifiers&#xff09;是 Vue 模板语法中的重要特性&#xff0c;它们以半角句号 . 开头&#xff0c;用于对指令的绑定行为进行特殊处理 修饰符作用如下&#xff1a; 简化事件处理&#xff08;如阻止默认行为、停止冒泡…

Reinforcement Learning强化学习--李宏毅机器学习笔记

个人学习笔记&#xff0c;如有错误欢迎指正&#xff0c;也欢迎交流&#xff0c;其他笔记见个人空间 强化学习 vs 监督学习 监督学习&#xff08;Supervised Learning&#xff09;&#xff1a;你有输入和明确的输出标签&#xff0c;例如图像分类。 强化学习&#xff08;Rein…

Windows VsCode Terminal窗口使用Linux命令

背景描述&#xff1a; 平时开发环境以Linux系统为主&#xff0c;有时又需要使用Windows系统下开发环境&#xff0c;为了能像Linux系统那样用Windows VsCode&#xff0c;Terminal命令行是必不可少内容。 注&#xff1a;Windows11 VsCode 1.99.2 下面介绍&#xff0c;如何在V…

软件测试之测试数据生成(Excel版)

这是Excel生成测试数据的函数使用 1.时间 1.1.时间 例生成2022-05-01之前一年内任意时间点: =TEXT("2022-05-01"-RAND()-RANDBETWEEN(1,365),"yyyy-mm-dd hh:mm:ss")1.2.年月日 yyyy-mm-dd 以当前时间生成10年的日期 =TEXT(NOW()-RAND()-RANDBETWE…

libwebsocket建立服务器需要编写LWS_CALLBACK_ADD_HEADERS事件处理

最近在使用libwebsocket&#xff0c;感觉它搭建Http与websocket服务器比较简单&#xff0c;不像poco库那么庞大&#xff0c;但当我使用它建立websocket服务器后&#xff0c;发现websocket客户端连接一直没有连接成功&#xff0c;不知道什么原因&#xff0c;经过一天的调试&…

从 PyTorch 到 ONNX:深度学习模型导出全解析

在模型训练完毕后&#xff0c;我们通常希望将其部署到推理平台中&#xff0c;比如 TensorRT、ONNX Runtime 或移动端框架。而 ONNX&#xff08;Open Neural Network Exchange&#xff09;正是 PyTorch 与这些平台之间的桥梁。 本文将以一个图像去噪模型 SimpleDenoiser 为例&a…

Hadoop集群部署教程-P6

Hadoop集群部署教程-P6 Hadoop集群部署教程&#xff08;续&#xff09; 第二十一章&#xff1a;监控与告警系统集成 21.1 Prometheus监控体系搭建 Exporter部署&#xff1a; # 部署HDFS Exporter wget https://github.com/prometheus/hdfs_exporter/releases/download/v1.1.…

【Altium】AD-生成PDF文件图纸包含太多的空白怎么解决

1、 文档目标 AD设计文件导出PDF时&#xff0c;图纸模板方向设置问题 2、 问题场景 AD使用Smart PDF导出PDF时&#xff0c;不管你怎么设置页面尺寸&#xff0c;只要从横向转为纵向输出&#xff0c;输出的始终是横向纸张&#xff08;中间保留纵向图纸&#xff0c;两边大量留白…

大厂面试:六大排序

前言 本篇博客集中了冒泡&#xff0c;选择&#xff0c;二分插入&#xff0c;快排&#xff0c;归并&#xff0c;堆排&#xff0c;六大排序算法 如果觉得对你有帮助&#xff0c;可以点点关注&#xff0c;点点赞&#xff0c;谢谢你&#xff01; 1.冒泡排序 //冒泡排序&#xff…

大模型开发:源码分析 Qwen 2.5-VL 视频抽帧模块(附加FFmpeg 性能对比测试)

目录 qwen 视频理解能力 messages 构建 demo qwen 抽帧代码分析 验证两个实际 case 官网介绍图 性能对比&#xff1a;ffmpeg 抽帧、decord 库抽帧 介绍 联系 对比 测试结果 测试明细 ffmpeg 100 qps 测试&#xff08;CPU&#xff09; decord 100 qps 测试&#x…

git的上传流程

好久没使用git 命令上传远程仓库了。。。。。温习了一遍&#xff1b; 几个注意点--单个文件大小不能超过100M~~~ 一步步运行下面的命令&#xff1a; 进入要上传的文件夹内&#xff0c;点击git bash 最终 hbu的小伙伴~有需要nndl实验的可以自形下载哦

驱动学习专栏--字符设备驱动篇--2_字符设备注册与注销

对于字符设备驱动而言&#xff0c;当驱动模块加载成功以后需要注册字符设备&#xff0c;同样&#xff0c;卸载驱动模 块的时候也需要注销掉字符设备。字符设备的注册和注销函数原型如下所示 : static inline int register_chrdev(unsigned int major, const char *name, const…

redis 放置序列化的对象,如果修改对象,需要修改版本号吗?

在 Redis 中存储序列化对象时,如果修改了对象的类结构(例如增删字段、修改字段类型或顺序),是否需要修改版本号取决于序列化协议的兼容性策略和业务场景的容错需求。以下是详细分析: 1. 为什么需要考虑版本号? 序列化兼容性问题: 当对象的类结构发生变化时,旧版本的序列…

WPF ObjectDataProvider

在 WPF(Windows Presentation Foundation)中,ObjectDataProvider 是一个非常有用的类,用于将非 UI 数据对象(如业务逻辑类或服务类)与 XAML 绑定集成。它允许在 XAML 中直接调用方法、访问属性或实例化对象,而无需编写额外的代码。以下是关于 ObjectDataProvider 的详细…

深度学习-损失函数 python opencv源码(史上最全)

目录 定义 种类 如何选择损失函数&#xff1f; 平方&#xff08;均方&#xff09;损失函数&#xff08;Mean Squared Error, MSE&#xff09; 均方根误差 交叉熵 对数损失 笔记回馈 逻辑回归中一些注意事项&#xff1a; 定义 损失函数又叫误差函数、成本函数、代价函数…

poll为什么使用poll_list链表结构而不是数组 - 深入内核源码分析

一&#xff1a;引言 在Linux内核中,poll机制是一个非常重要的I/O多路复用机制。它允许进程监视多个文件描述符,等待其中任何一个进入就绪状态。poll的内部实现使用了poll_list链表结构而不是数组,这个设计选择背后有其深层的技术考量。本文将从内核源码层面深入分析这个设计决…

使用 Azure AKS 保护 Kubernetes 部署的综合指南

企业不断寻求增强其软件开发和部署流程的方法。DevOps 一直是这一转型的基石,弥合了开发与运营之间的差距。然而,随着安全威胁日益复杂,将安全性集成到 DevOps 流水线(通常称为 DevSecOps)已变得势在必行。本指南深入探讨了如何使用 Azure Kubernetes 服务 (AKS) 来利用 D…