LangChain实战:大模型RAG与Agent智能体的长期会话记忆实现
1. 项目概述大模型RAG与Agent智能体实战中的长期会话记忆在构建基于大模型的智能对话系统时长期会话记忆是实现自然交互的核心能力。想象一下当你与人类客服交流时对方能记住你之前提过的需求和个人信息这种连续性体验正是我们需要在AI系统中复现的。本次实战将使用LangChain框架通过BaseChatMessageHistory类和property装饰器实现对话历史的持久化存储。这个方案特别适合需要处理多轮复杂对话的场景比如智能客服、个性化教学助手或医疗咨询系统。传统的大模型对话往往存在健忘症每次提问都像初次见面而我们的技术方案能让AI记住对话上下文甚至跨会话保持记忆。在RAG检索增强生成架构中这种记忆能力可以显著提升回答的相关性和一致性。2. 核心组件解析与技术选型2.1 LangChain中的消息历史管理BaseChatMessageHistory是LangChain提供的抽象基类定义了对话历史存储的标准接口。它支持常见的操作如add_message、clear等让我们可以灵活选择存储后端。在实际项目中我推荐优先考虑这些实现方案RedisBackedChatMessageHistory适合高并发生产环境利用Redis的TTL功能可以自动清理过期对话PostgresChatMessageHistory当需要复杂查询或事务支持时关系型数据库是不二之选DynamoDBChatMessageHistory无服务器架构下的弹性扩展方案from langchain.memory import RedisChatMessageHistory # 初始化Redis存储的对话历史 message_history RedisChatMessageHistory( session_iduser123_session456, urlredis://localhost:6379/0, ttl3600 # 1小时过期 )2.2 property装饰器的妙用在管理对话历史时property装饰器帮助我们以更优雅的方式封装核心属性。比如当我们需要在获取历史消息时自动进行敏感信息过滤class SafeChatHistory: def __init__(self): self._messages [] property def messages(self): return [self._filter_sensitive_info(msg) for msg in self._messages] def _filter_sensitive_info(self, message): # 实现敏感信息过滤逻辑 return message.replace(信用卡, ***)这种设计模式带来三个显著优势保持接口简洁内部实现可随时变更添加访问控制逻辑无需修改客户端代码实现惰性计算和缓存等高级特性3. 完整实现方案与核心代码剖析3.1 持久化存储的集成实现让我们构建一个支持MongoDB存储的定制化历史记录类。选择MongoDB是因为其灵活的文档结构特别适合存储多变的对话数据from pymongo import MongoClient from langchain.schema import BaseChatMessageHistory, HumanMessage, AIMessage class MongoChatMessageHistory(BaseChatMessageHistory): def __init__(self, session_id, mongo_uri, db_namechat_db): client MongoClient(mongo_uri) self.db client[db_name] self.collection self.db[chat_history] self.session_id session_id def add_message(self, message): doc { session_id: self.session_id, type: human if isinstance(message, HumanMessage) else ai, content: message.content, timestamp: datetime.now() } self.collection.insert_one(doc) property def messages(self): cursor self.collection.find( {session_id: self.session_id} ).sort(timestamp, 1) return [self._convert_doc_to_message(doc) for doc in cursor] def _convert_doc_to_message(self, doc): if doc[type] human: return HumanMessage(contentdoc[content]) return AIMessage(contentdoc[content])重要提示在生产环境中务必为session_id和timestamp字段创建复合索引可以大幅提升查询性能db.chat_history.create_index([(session_id, 1), (timestamp, 1)])3.2 与LangChain Agent的集成将定制化的历史记录类集成到LangChain工作流中需要配置ConversationChainfrom langchain.chains import ConversationChain from langchain.llms import OpenAI llm OpenAI(temperature0) memory ConversationChain( llmllm, memoryMongoChatMessageHistory( session_iduser_123, mongo_urimongodb://localhost:27017 ), verboseTrue ) response memory.run(你好我想咨询理财产品) print(fAI回复: {response}) # 后续对话会自动保持上下文 response memory.run(有哪些适合新手的选项)4. 性能优化与生产级部署4.1 分级存储架构设计对于高流量生产系统我推荐采用分级存储策略热存储Redis缓存最近15分钟的活跃对话温存储MongoDB保存7天内的完整历史冷存储定期将过期数据归档到对象存储如S3这种架构在保证响应速度的同时也控制了存储成本。以下是实现示例class TieredChatMessageHistory(BaseChatMessageHistory): def __init__(self, session_id): self.redis RedisChatMessageHistory(session_id) self.mongo MongoChatMessageHistory(session_id) property def messages(self): # 优先从Redis获取不存在则查询MongoDB if not self.redis.messages: last_hour_msgs self.mongo.get_recent_messages(hours1) self.redis.bulk_add(last_hour_msgs) return self.redis.messages4.2 对话压缩与摘要技术长期对话会产生大量历史消息可能超出大模型的上下文窗口限制。解决方案是自动生成对话摘要from langchain.chains.summarize import load_summarize_chain def summarize_dialog(messages): text \n.join([f{msg.type}: {msg.content} for msg in messages]) summary_chain load_summarize_chain(llm, chain_typemap_reduce) return summary_chain.run(text)在实际部署中建议当对话轮次超过10轮时自动触发摘要生成并将摘要作为新的系统消息插入。5. 安全合规与隐私保护5.1 敏感信息处理方案对话系统必须妥善处理用户隐私数据。我采用的三层过滤机制在实践中效果显著实时过滤使用预定义规则过滤明显敏感信息如信用卡号模式匹配存储加密对持久化存储的内容进行字段级加密访问控制基于RBAC模型限制历史记录的访问权限from cryptography.fernet import Fernet class EncryptedChatHistory(MongoChatMessageHistory): def __init__(self, encryption_key, **kwargs): self.cipher Fernet(encryption_key) super().__init__(**kwargs) def add_message(self, message): encrypted_content self.cipher.encrypt(message.content.encode()) message.content encrypted_content.decode() super().add_message(message) property def messages(self): raw_messages super().messages for msg in raw_messages: msg.content self.cipher.decrypt(msg.content.encode()).decode() return raw_messages5.2 合规性设计要点根据GDPR等法规要求对话系统必须实现数据保留策略自动过期删除用户数据导出功能全量删除能力Right to be Forgotten在MongoDB实现中可以通过TTL索引和定期作业来实现// 创建30天过期的TTL索引 db.chat_history.createIndex( { timestamp: 1 }, { expireAfterSeconds: 2592000 } )6. 实战问题排查与调试技巧6.1 常见问题速查表问题现象可能原因解决方案对话丢失上下文会话ID不一致确保前后使用相同的session_id历史记录加载慢未创建合适索引为session_id和timestamp创建复合索引存储空间增长过快未设置数据过期配置TTL或定期归档旧数据敏感信息泄露未做加密处理实施字段级加密或脱敏6.2 调试日志配置在开发阶段启用LangChain的详细日志有助于理解内部工作机制import logging logging.basicConfig(levellogging.DEBUG) logger logging.getLogger(langchain) logger.setLevel(logging.DEBUG) # 在历史记录类中添加调试日志 class LoggingChatHistory(MongoChatMessageHistory): def add_message(self, message): logger.debug(fAdding message: {message}) super().add_message(message) property def messages(self): msgs super().messages logger.debug(fRetrieved {len(msgs)} messages) return msgs7. 高级应用场景扩展7.1 跨会话记忆聚合通过用户ID关联多个会话实现真正的长期记忆class UserCentricHistory: def __init__(self, user_id): self.user_id user_id self.sessions self._load_user_sessions() def _load_user_sessions(self): # 从数据库查询该用户的所有历史会话 return db.sessions.find({user_id: self.user_id}) property def lifetime_messages(self): all_msgs [] for session in self.sessions: history MongoChatMessageHistory(session[session_id]) all_msgs.extend(history.messages) return sorted(all_msgs, keylambda x: x.timestamp)7.2 基于记忆的个性化响应利用历史对话数据定制回答风格def personalize_response(memory, new_query): history memory.load_memory_variables({})[history] user_style analyze_communication_style(history) if user_style[prefers_formal]: prompt f请用正式商务语气回答以下问题{new_query} else: prompt f请用轻松口语化的方式回答{new_query} return llm(prompt)这种个性化处理能让对话体验更加自然亲切大幅提升用户满意度。

相关新闻

hot100 最长公共子序列(1143)

hot100 最长公共子序列(1143)

本题采用二维动态规划 (2D Dynamic Programming) 算法解决双字符串最长公共子序列 (LCS, Longest Common Subsequence) 的求解问题。其核心本质是将两个序列的全局拓扑匹配问题,拆解为二维状态空间阵列中的自底向上一维步进收敛模型。通过构建大小为 (m 1) * (n 1…

2026/10/6 12:29:24 阅读更多 →
瑞德克斯平台:流程清晰度的路径梳理

瑞德克斯平台:流程清晰度的路径梳理

在外汇相关服务里,瑞德克斯平台是否值得长期关注,往往取决于几个清晰的体验点:说明是否好理解、提示是否到位、流程是否连贯、支持是否稳定。下面从这些维度对瑞德克斯平台做一次正向梳理与要点归纳。外汇相关信息更新频繁,平台将…

2026/10/6 11:48:34 阅读更多 →
量化研究变成了自动化工厂:AI提假设、AI写代码、AI自己做回测

量化研究变成了自动化工厂:AI提假设、AI写代码、AI自己做回测

RD-Agenthttps://github.com/microsoft/RD-Agent RD-Agent是微软亚洲研究院开源的自动化研发框架——14K星,NeurIPS2025收录。跟前十五篇写的TradingAgents、Qlib、FinRL这些项目完全不同:那些帮你分析数据、训练模型、执行交易——但因子从哪来、策略怎…

2026/10/3 9:45:57 阅读更多 →

最新新闻

网络安全术语汇编v9.5使用指南:从背词到搭知识索引

网络安全术语汇编v9.5使用指南:从背词到搭知识索引

简介:《网络安全词汇术语汇编 v9.5(上下册合集)》是一份面向网络安全从业者、学者及学生的专业术语工具书,由Rick Kang编纂并持续更新,旨在帮助读者准确理解从基础到高阶的网络安全概念;资源为PDF格式&…

2026/10/7 5:14:58 阅读更多 →
Chrome渲染机制拆解:从多进程架构到关键渲染路径的性能优化

Chrome渲染机制拆解:从多进程架构到关键渲染路径的性能优化

很多人把 Chrome 当成一个“能打开网页的框”,但如果你做前端或者经常折腾浏览器内核相关的问题,你会越来越觉得它其实是一条高度自动化的工业流水线。Chrome 的渲染机制,简单说就是把 URL 变成屏幕上像素的完整过程——从网络请求开始&#…

2026/10/7 5:14:57 阅读更多 →
一次性授权令牌设计拆解:防重放、签名校验与车联网指令安全实践

一次性授权令牌设计拆解:防重放、签名校验与车联网指令安全实践

1. 从一次“取车失败”说起:token-1002 到底是什么前阵子我们线上有一个租车订单频繁报“token校验失败”,用户已经支付成功、人也站在门店门口,结果手机端一直弹“操作超时,请重新打开订单”。排查到最后,问题出在一个…

2026/10/7 5:14:57 阅读更多 →
防火墙验收测试报告复现:NAT、代理与日志验证全解析

防火墙验收测试报告复现:NAT、代理与日志验证全解析

简介:一份网络安全系统测试报告PDF文档,面向网络安全测试、系统运维及设备验收技术人员,用来评估网络安全设备在常见部署场景下的功能与性能表现。文档以功能测试和配置规则测试为主线,细致覆盖网络地址转换、端口映射、IP与MAC地…

2026/10/7 5:14:56 阅读更多 →
数字谐音“555”背后的网络社交情绪表达与沟通技巧

数字谐音“555”背后的网络社交情绪表达与沟通技巧

“555555555”——这九个5放在一起,如果你常刷视频或泡论坛,大概率不会觉得它是一串乱码,而是一声拖长了尾音的“呜呜呜呜呜呜”,带着三分委屈、七分撒娇,甚至还有点表演性质的崩溃。这个标题乍一看全是数字&#xff0…

2026/10/7 5:14:56 阅读更多 →
COMSOL模拟低渗煤层N₂/CO₂注气驱替瓦斯

COMSOL模拟低渗煤层N₂/CO₂注气驱替瓦斯

1. 低渗煤层为何需要“注气置换”这张牌——从抽采瓶颈说起干煤矿瓦斯治理这一行的人,最头疼的不是瓦斯浓度超标,而是钻孔打得下去、负压抽得上,产气量却长期趴在个位数。尤其进入深部开采以后,煤层渗透率普遍降到 0.5 mD 以下&am…

2026/10/7 5:13:55 阅读更多 →

日新闻

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:01:58 阅读更多 →
用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →
芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 7:15:40 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 5:29:09 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 6:26:51 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 8:21:32 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 4:21:51 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 1:18:13 阅读更多 →