7. 记忆(Memory)机制:让AI拥有“短期记忆”与“长期记忆”

引言:当AI学会"记住你"

2025年某银行智能客服因无法记住用户身份,每次对话都要求重复验证,引发大量投诉。引入LangChain 记忆系统后,客户满意度提升62%。本文将基于MemorySaverFAISS本地存储,教你构建符合最新标准的记忆系统。


一、新版记忆架构核心变化
1.1 记忆存储方案对比(LangChain 0.3+)
组件适用场景关键特性
MemorySaver短期会话状态自动序列化,支持JSON/二进制
FAISS长期知识存储本地化部署,毫秒级检索
PostgreSQL企业级记忆管理事务支持,高可用
1.2 新旧API迁移指南
# 旧版(已废弃)
# from langgraph.checkpoint import FileCheckpointer
​
# 新版(推荐)
from langgraph.checkpoint.memory import MemorySaver
from langchain_community.vectorstores import FAISS

二、构建新一代记忆系统
2.1 短期记忆
from langchain_core.messages import SystemMessage, HumanMessage
from langchain_ollama import ChatOllama
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
​
​
llm = ChatOllama(model="deepseek-r1")
​
workflow = StateGraph(state_schema=MessagesState)
​
​
# 定义模型调用函数
def call_model(state: MessagesState):system_prompt = ("你是一个有礼貌的助手. ""回答尽可能多的细节.")messages = [SystemMessage(content=system_prompt)] + state["messages"]response = llm.invoke(messages)return {"messages": response}
​
​
# 定义节点和边
workflow.add_node("model", call_model)
workflow.add_edge(START, "model")
​
# 添加简单的内存检查点
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
​
response = app.invoke({"messages": [HumanMessage(content="你是谁?")]},config={"configurable": {"thread_id": "1"}},
)
print(response)
response = app.invoke({"messages": [HumanMessage(content="我刚才问你什么了?")]},config={"configurable": {"thread_id": "1"}},
)
print(response)

输出为:

{'messages': [HumanMessage(content='你是谁?', additional_kwargs={}, response_metadata={}, id='03ed2cbb-59df-42c2-b865-bcd177e30833'), AIMessage(content='<think>\n好,我需要回答用户的问题:“你是谁?” 用户希望得到详细的回应,并且我应该以礼貌的方式呈现。\n\n首先,我要确认自己的身份是DeepSeek-R1-Lite-Preview。这表明我是由深度求索公司开发的智能助手。接下来,我需要解释我的功能和用途:通过算法处理信息并生成回答,帮助用户解决问题或提供信息。\n\n然后,强调我没有个人意识或情感,只是一个工具,以确保用户的期望与实际功能相符。此外,提到遵守严格的伦理准则和隐私保护措施,这会增加用户的信任感。\n\n最后,表达愿意随时提供帮助的意愿,并询问是否需要进一步的帮助或有其他问题,这样可以让用户感到被重视和支持。\n</think>\n\n您好!我是DeepSeek-R1-Lite-Preview,一个由深度求索公司开发的智能助手,我通过算法处理信息并生成回答。我无法自主学习或更新,我的知识和能力是基于训练数据设计的。我会以专业和诚恳的态度为您提供帮助,同时遵守严格的伦理准则和隐私保护措施。请问有什么可以帮您的?', additional_kwargs={}, response_metadata={'model': 'deepseek-r1:32B', 'created_at': '2025-04-05T08:31:13.718524566Z', 'done': True, 'done_reason': 'stop', 'total_duration': 32779446334, 'load_duration': 17223924, 'prompt_eval_count': 21, 'prompt_eval_duration': 148000000, 'eval_count': 228, 'eval_duration': 32612000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-939ed366-2088-4d99-97e4-f5e936ecc3c2-0', usage_metadata={'input_tokens': 21, 'output_tokens': 228, 'total_tokens': 249})]}
​
{'messages': [HumanMessage(content='你是谁?', additional_kwargs={}, response_metadata={}, id='03ed2cbb-59df-42c2-b865-bcd177e30833'), AIMessage(content='<think>\n好,我需要回答用户的问题:“你是谁?” 用户希望得到详细的回应,并且我应该以礼貌的方式呈现。\n\n首先,我要确认自己的身份是DeepSeek-R1-Lite-Preview。这表明我是由深度求索公司开发的智能助手。接下来,我需要解释我的功能和用途:通过算法处理信息并生成回答,帮助用户解决问题或提供信息。\n\n然后,强调我没有个人意识或情感,只是一个工具,以确保用户的期望与实际功能相符。此外,提到遵守严格的伦理准则和隐私保护措施,这会增加用户的信任感。\n\n最后,表达愿意随时提供帮助的意愿,并询问是否需要进一步的帮助或有其他问题,这样可以让用户感到被重视和支持。\n</think>\n\n您好!我是DeepSeek-R1-Lite-Preview,一个由深度求索公司开发的智能助手,我通过算法处理信息并生成回答。我无法自主学习或更新,我的知识和能力是基于训练数据设计的。我会以专业和诚恳的态度为您提供帮助,同时遵守严格的伦理准则和隐私保护措施。请问有什么可以帮您的?', additional_kwargs={}, response_metadata={'model': 'deepseek-r1:32B', 'created_at': '2025-04-05T08:31:13.718524566Z', 'done': True, 'done_reason': 'stop', 'total_duration': 32779446334, 'load_duration': 17223924, 'prompt_eval_count': 21, 'prompt_eval_duration': 148000000, 'eval_count': 228, 'eval_duration': 32612000000, 'message': {'role': 'assistant', 'content': '', 'images': None, 'tool_calls': None}}, id='run-939ed366-2088-4d99-97e4-f5e936ecc3c2-0', usage_metadata={'input_tokens': 21, 'output_tokens': 228, 'total_tokens': 249}), HumanMessage(content='我刚才问你什么了?', additional_kwargs={}, response_metadata={}, id='83a142cc-ad9a-4a76-baa3-675508cd70fb'), AIMessage(content='<think>\n好的,用户现在问:“我刚才问你什么了?” 这可能是因为他想确认自己之前的问题或者只是随便一问。\n\n首先,我要回忆之前的对话内容。上一次用户的问题是“你是谁?”,而我的回答详细介绍了我是DeepSeek-_lite版本的智能助手,并说明了我的功能和限制。\n\n现在,用户询问刚才的问题是什么,这可能表明他希望再次确认我的身份,或者他想继续讨论这个话题。也有可能他记不清了,只是想知道之前的对话内容。\n\n我需要礼貌地提醒他刚才问的是关于我的身份问题。同时,保持友好,邀请他提出更多的问题或进一步的讨论。\n\n因此,在回复时,我会先简单说明他之前的问题,然后询问是否还有其他需求或想要继续探讨的内容。\n</think>\n\n您好!您刚才问的是:“你是谁?”如果您想了解更多或有其他问题,请随时告诉我,我很乐意为您提供帮助。', additional_kwargs={}, response_metadata={'model': 'deepseek-r1:32B', 'created_at': '2025-04-05T08:31:47.33778896Z', 'done': True, 'done_reason': 'stop', 'total_duration': 33613724628, 'load_duration': 17323671, 'prompt_eval_count': 269, 'prompt_eval_duration': 5397000000, 'eval_count': 192, 'eval_duration': 28192000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-f86abc0a-3f22-47e0-8da6-f4c2bd22a157-0', usage_metadata={'input_tokens': 269, 'output_tokens': 192, 'total_tokens': 461})]}

2.2 长期记忆
from datetime import datetime
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
​
# 1. 初始化嵌入模型和向量数据库
embeddings = OllamaEmbeddings(model="deepseek-r1")
​
# 初始化包含示例对话的向量库
vectorstore = FAISS.from_documents(documents=[Document(page_content="用户:如何重置密码?",metadata={"type": "human", "timestamp": "2025-01-01"}),Document(page_content="AI:您可以访问设置页面,选择'忘记密码'选项。",metadata={"type": "ai", "timestamp": "2025-01-01"})],embedding=embeddings
)
​
# 2. 配置本地大模型
llm = ChatOllama(model="deepseek-r1")
​
# 3. 构建增强提示模板
template = """基于以下对话历史和当前问题,用中文回答用户:
历史对话(最新在前):
{history}
当前问题:{question}
请给出专业解答:"""
prompt = ChatPromptTemplate.from_template(template)
​
​
# 4. 创建处理链
def build_chain():# 创建带时间过滤的检索器retriever = vectorstore.as_retriever(search_kwargs={"k": 2,"filter": lambda doc: doc.get("metadata", {}).get("type", "") in ["human", "ai"]})
​
​return (RunnablePassthrough.assign(# 获取最近10条对话历史history=lambda x: "\n".join([f"{doc.metadata['type']}:{doc.page_content}"for doc in retriever.invoke(x["question"])[:10]]))| prompt| llm)
​
​
# 5. 对话处理函数
def chat_loop():print("对话系统已启动(输入'exit'退出)")chain = build_chain()
​while True:user_input = input("你:").strip()if user_input.lower() == 'exit':break
​# 生成响应response = chain.invoke({"question": user_input})ai_response = response.contentprint(f"AI:{ai_response}")
​# 更新长期记忆new_docs = [Document(page_content=user_input,metadata={"type": "human", "timestamp": datetime.now().isoformat()}),Document(page_content=ai_response,metadata={"type": "ai", "timestamp": datetime.now().isoformat()})]vectorstore.add_documents(new_docs)vectorstore.save_local("chat_memory")  # 持久化存储
​
​
if __name__ == "__main__":chat_loop()

输出为:

对话系统已启动(输入'exit'退出)
你:你好
AI:<think>
嗯,用户发来了“你好”,看起来是一个问候。我应该礼貌地回应。首先,我可以用“你好!”来回复,这样既简洁又友好。然后,我可以进一步表示愿意提供帮助,比如问有什么可以帮忙的,或者询问他们今天想聊些什么。这样可以让对话继续下去,让用户感觉被重视和支持。
</think>
​
你好!很高兴见到你,有什么我可以帮你的吗?
你:怎么重置密码
AI:<think>
好,我收到用户的问题是“怎么重置密码”。首先,我要考虑用户的使用场景。可能是用户忘记了原来的密码,想要重新设置一个。接下来,我需要分析用户的身份,可能是一个普通用户,不太熟悉技术细节,所以回答要简明易懂。
​
然后,我会思考用户的真实需求。他们可能只是想快速解决问题,而不需要太多的技术术语。同时,可能会有更深层的需求,比如希望过程安全,确保密码重置不会被他人恶意利用。
​
现在,我来组织一个专业的回答。首先,需要列出步骤:访问登录页面,点击“忘记密码”,填写注册邮箱或手机号,按照提示操作,设置新密码并保存。这样分点说明清晰明了,用户容易跟随。
​
另外,我要考虑可能的安全问题,所以提醒用户不要告诉他人验证码,并建议定期更换密码以保护账户安全。这些额外的注意事项能够帮助用户更好地维护自己的账号安全。
​
最后,整体语气要友好且专业,让用户感受到被帮助和支持。
</think>
​
重置密码通常需要按照以下步骤进行:
​
1. **访问登录页面**:打开应用或网站的登录界面。
​
2. **点击“忘记密码”**:在登录页面上找到并点击“忘记密码”或“找回密码”的链接。
​
3. **输入注册邮箱或手机号**:根据提示,输入你注册时使用的邮箱地址或手机号码。
​
4. **接收验证码或重置链接**:系统会发送一个验证码到你的邮箱或手机,或者直接提供一个链接让你设置新密码。
​
5. **按照提示操作**:使用收到的验证码完成身份验证,然后按照系统的指示设置一个新的密码。
​
6. **保存新密码**:确保记住新的密码,并妥善保管。
​
如果你在重置密码过程中遇到任何问题,请联系该服务的支持团队获取帮助。同时,确保不要将验证码告诉他人,以保护你的账户安全。
你:exit


三、企业级案例:金融客服系统
3.1 架构设计
3.2 关键性能指标
  • 响应延迟:平均210ms(P99<450ms)

  • 记忆准确率:用户意图识别提升58%

  • 扩展性:单节点支持10,000+并发会话


四、避坑指南:新版记忆系统六大陷阱
  1. 未显式持久化:FAISS索引修改后需手动保存

    vector_db.save_local("./memory_index")  # 关键操作!

  2. 会话ID冲突:未使用唯一标识导致记忆混淆

  3. 内存泄漏:MemorySaver未设置cache_size限制

  4. 版本不兼容:FAISS索引文件跨版本不兼容

  5. 权限问题:本地存储目录不可写

  6. 监控缺失:未跟踪记忆命中率


下期预告

《LangChain代理系统:让AI自主决策与执行》

  • 揭秘:如何让大模型自主调用工具链?

  • 实战:构建能订机票、查天气的智能助手

  • 陷阱:无限递归与权限管控


新一代记忆系统让AI真正拥有了"过去"。记住:优秀的记忆设计,是智能体从"工具"进化为"伙伴"的关键一跃!

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

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

相关文章

【Python使用】嘿马云课堂web完整实战项目第3篇:增加数据,修改数据【附代码文档】

教程总体简介&#xff1a;项目概述 项目背景 项目的功能构架 项目的技术架构 CMS 什么是CMS CMS需求分析与工程搭建 静态门户工程搭建 SSI服务端包含技术 页面预览开发 4 添加“页面预览”链接 页面发布 需求分析 技术方案 测试 环境搭建 数据字典 服务端 前端 数据模型 页面原…

论文笔记(七十五)Auto-Encoding Variational Bayes

Auto-Encoding Variational Bayes 文章概括摘要1 引言2 方法2.1 问题场景2.2 变分下界2.3 SGVB估计器与AEVB算法2.4 重参数化技巧 3 示例&#xff1a;变分自编码器&#xff08;Variational Auto-Encoder&#xff09;4 相关工作5 实验6 结论7 未来工作 文章概括 引用&#xff1…

Python3 学习笔记

Python3 简介 | 菜鸟教程 一 Python3 简介 Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色…

Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解

N皇后问题要求在NN的棋盘上放置N个皇后&#xff0c;使得她们无法互相攻击。本文提供递归和循环迭代两种解法&#xff0c;并通过图示解释核心逻辑。 一、算法核心思想 使用回溯法逐行放置皇后&#xff0c;通过冲突检测保证每行、每列、对角线上只有一个皇后。发现无效路径时回退…

前端判断值相等的方法和区别

1. (宽松相等) 在比较之前会进行类型转换 可能导致一些意外的结果 0 // true 0 0 // true false 0 // true null undefined // true [1,2,3]1,2,3 // true2. (严格相等) 不进行类型转换 类型和值都必须相同 0 // false 0 0 // false false 0 /…

Socket编程UDP

Socket编程UDP 1、V1版本——EchoServer2、网络命令2.1、ping2.2、netstat2.3、pidof 3、验证UDP——Windows作为client访问Linux4、V2版本——DictServer5、V3版本——简单聊天室 1、V1版本——EchoServer 首先给出EchoServer目录结构&#xff1a;服务器的类我们实现在UdpServ…

辅助查询是根据查询到的文档片段再去生成新的查询问题

&#x1f4a1; 辅助查询是怎么来的&#xff1f; 它是基于你当前查询&#xff08;query&#xff09;检索到的某个文档片段&#xff08;chunk_result&#xff09;&#xff0c;再去“反推”出新的相关问题&#xff08;utility queries&#xff09;&#xff0c;这些问题的作用是&a…

2025 年 4 月补丁星期二预测:微软将推出更多 AI 安全功能

微软正在继续构建其 AI 网络安全战略&#xff0c;并于本月宣布在 Microsoft Security Copilot 中引入新代理。 他们引入了用于网络钓鱼分类的代理、用于数据丢失预防和内部风险管理的警报分类、条件访问优化、漏洞修复和威胁情报简报。 这些代理的目标是不断从这些不同学科中…

【LLM系列】1.大模型简介

1. 基础 1.1 如何权衡模型的复杂度和性能&#xff1f; ├── a. 模型架构选择 │ ├── 简化架构 │ │ └── 选择较小的网络层数和宽度&#xff0c;降低复杂度&#xff1b; │ │ 可使用高性能基础模型如 Transformers 作为起点&#xff0c;根据需求缩放模型。 │ └──…

【leetcode】记录与查找:哈希表的题型分析

前言 &#x1f31f;&#x1f31f;本期讲解关于力扣的几篇题解的详细介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

优选算法的妙思之流:分治——快排专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、快速排序 二、例题讲解 2.1. 颜色分类 2.2. 排序数组 2.3. 数组中的第K个最大元素 2.4. 库存管理 III 一、快速排序 分治&#xff0c;简单理解为“分而治之”&#xff0c;将一个大问题划分为若干个…

二叉树的ACM板子(自用)

package 二叉树的中序遍历;import java.util.*;// 定义二叉树节点 class TreeNode {int val; // 节点值TreeNode left; // 左子节点TreeNode right; // 右子节点// 构造函数TreeNode(int x) {val x;} }public class DMain {// 构建二叉树&#xff08;层序遍历方式&…

Linux常用命令详解:从基础到进阶

目录 一、引言 二、文件处理相关命令 &#xff08;一&#xff09;grep指令 &#xff08;二&#xff09;zip/unzip指令 ​编辑 &#xff08;三&#xff09;tar指令 &#xff08;四&#xff09;find指令 三、系统管理相关命令 &#xff08;一&#xff09;shutdown指…

Qt多线程从基础到性能优化

一、为什么需要多线程开发 现代应用程序的性能需求 CPU多核架构的有效利用 复杂任务的解耦与响应式界面保持 二、Qt线程创建四大方式 1. 继承QThread重写run() class WorkerThread : public QThread {void run() override {// 耗时操作qDebug() << "Thread ID…

【java】在 Java 中,获取一个类的`Class`对象有多种方式

在 Java 中&#xff0c;获取一个类的Class对象有多种方式。Class对象代表了 Java 中的一个类或接口的运行时类信息&#xff0c;可以用于反射操作。以下是获取Class对象的几种常见方法&#xff1a; 1.使用.class属性 每个类都有一个.class属性&#xff0c;可以直接获取该类的Cl…

什么是RPC通信

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;通信是一种允许程序像调用本地函数一样调用远程服务器上函数的通信技术。它简化了分布式系统中的网络交互&#xff0c;隐藏了底层网络通信的复杂性&#xff0c;使开发者能够专注于业务逻辑。 一、RPC…

还是主题混合程序设计

以下是针对您现有代码的完整主题化改造方案&#xff0c;实现跨QML/Qt Widgets的阴影主题系统&#xff1a; 一、主题管理系统核心 // thememanager.h #pragma once #include <QObject> #include <QColor> #include <QMap> #include <QQmlEngine>class…

BT-Basic函数之首字母T

BT-Basic函数之首字母T 文章目录 BT-Basic函数之首字母Ttabtesttest conttest monitortest on boardstest scanworkstest shortstesthead cleanuptesthead configurationtesthead istesthead power on/offtesthead statustestjet print level istestordertestplan generationth…

7-9 趣味游戏

题目解析 在某个学校的趣味游戏活动中&#xff0c;N 名同学站成一排&#xff0c;他们的年龄恰好是 1 到 N &#xff0c;需要注意的是他们并不是按照年龄的大小排列的&#xff0c;而是随机排列的。 游戏的规则是请同学们快速计算出&#xff0c;如果在这 N 名同学的小组中&…

Hugging Face模型微调训练(基于BERT的中文评价情感分析)

文章目录 学习视频地址项目地址数据集的下载模型微调的基本概念与流程加载数据集数据集格式数据集信息 制作Dataset数据集字段数据集信息 vocab字典操作词汇表文本转换 下游任务模型设计模型训练与保存数据加载优化器训练循环 最终效果评估与测试模型加载和测试 学习视频地址 …