给大模型加上“记忆”,深入探索 Mem0 项目

背景介绍

在之前的软件应用中,我们总会在应用中保留大量的用户历史操作记录,方便用户下次使用时可以快速查看和复用,甚至基于这些用户记录可以为用户提供个性化的服务。而这些记录往往都保存在传统的结构化或非结构化数据库中。

在大模型的应用,特别是助手类的大模型应用中,我们往往需要处理大量语义化的文本或多模态的信息,方便后续快速匹配,从而提供个性化的服务。为了支持这种语义检索的需求,往往会将数据保存至向量数据库中。

向量数据库执行语义检索相对方便,但是包含语义内容的文本管理比较困难,特别是涉及到相关内容的更新和替换。在这种背景下,Mem0 应运而生。Mem0 可以给大模型应用提供智能记忆层,可以记住用户偏好,适应个人需求,并随着时间的推移不断改进,从而方便应用提供更加个性化的体验和服务。
请添加图片描述

从开源依赖,Github 上的 star 数量一路飙升,截止目前已经 20.6k 的 star 了。

上手体验

Mem0 提供了两种接入方案,一种是使用官方的托管平台,另一种是使用官方提供的 python 依赖包 mem0ai执行。下面以本地依赖包形式了解下 Mem0 的使用。

依赖配置

首先需要通过 pip 安装所需的依赖包:

pip install mem0ai

Mem0 需要依赖大模型才能执行,默认使用的 gpt-4o, 因此需要配置对应的 ChatGPT API 秘钥,需要将秘钥配置至环境变量中:

import os
os.environ["OPENAI_API_KEY"] = "sk-xxx"
动手实践

Mem0 实际使用在大模型应用中,我们主要关注下面的能力:

  1. 针对特定用户添加非结构化的文本信息;
  2. 特定用户根据查询问题进行文本检索;

针对上面的关注的能力,使用 Mem0 可以简单满足需求:

from mem0 import Memory# 初始化记忆对象m = Memory()# 1. 针对特定用户添加非结构化的文本信息result = m.add("I am working on improving my tennis skills. Suggest some online courses.", user_id="alice", metadata={"category": "hobbies"})# 2. 特定用户根据查询问题进行文本检索related_memories = m.search(query="What are Alice's hobbies?", user_id="alice")

可以看到常规的功能使用比较简单,看起来几行代码就可以快速为大模型应用加上“记忆”。

实现方案

官方方案概述

首先可以从官方描述中大致了解 Mem0 的实现方案,从官方文档了解到下面的信息:

Mem0 利用混合数据库方法来管理和检索人工智能代理和助手的长期记忆。每个内存都与一个唯一的标识符相关联,例如用户 ID 或代理 ID,允许 Mem0 组织和访问特定于个人或上下文的内存。

当使用 add() 方法将消息添加到 Mem0 时,系统会提取相关事实和偏好并将其存储在数据存储中:矢量数据库、键值数据库和图形数据库。这种混合方法可确保以最有效的方式存储不同类型的信息,从而使后续搜索快速有效。

当人工智能代理或LLM需要回忆记忆时,它会使用 search() 方法。然后 Mem0 在这些数据存储中执行搜索,从每个源检索相关信息。然后,该信息通过评分层,根据相关性、重要性和新近度评估其重要性。这确保了只显示最个性化和最有用的上下文。

可以大致了解到 Mem0 是基于混合数据库来管理,同时支持向量、键值和图形数据库,但是具体的实现细节依旧不清楚,这种情况下 Talk is cheap, show me the code.,下面我们通过源码来了解 Mem0 的实现方案。

方案深入解析

文本检索

Mem0 中的文本检索是通过调用 Memory.search() 方法实现,文本检索的主要流程如下所示:

  1. 检索文本向量化,构造过滤条件,方便基于用户 id 等进行过滤;
  2. 基于向量数据库进行检索和过滤,默认使用的向量数据库为 Qdrant;
  3. 可选基于知识图谱的检索(从 v1.1 开始支持);

从上面的流程来看,主流程就是简单的向量检索,同时利用向量数据库提供的元信息过滤的能力进行用户区分的封装,实现如下所示:

filters = filters or {}
if user_id:filters["user_id"] = user_id
if agent_id:filters["agent_id"] = agent_id
if run_id:filters["run_id"] = run_id# 查询向量化embeddings = self.embedding_model.embed(query)# 向量检索memories = self.vector_store.search(query=embeddings, limit=limit, filters=filters
)# 可选的知识图谱检索if self.version == "v1.1":if self.enable_graph:graph_entities = self.graph.search(query)

文本添加

Mem0 中非结构化文本添加是通过调用 Memory.add() 方法实现,文本添加的主要流程如下所示:

  1. 将添加的文本进行向量化,从向量数据库中检索相关内容;
  2. 将检索的相关内容与新增的文本提供给大模型,大模型判断所需采取的动作列表,可选动作包含 新增文本, 更新原有的文本, 删除原有文本
  3. 根据大模型给出的动作列表依次执行;

可以看到上面的流程中主要基于大模型提供的能力处理历史信息的更新问题,对应的实现如下所示:

# 从向量库中检索已有的文本内容embeddings = self.embedding_model.embed(data)
existing_memories = self.vector_store.search(query=embeddings,limit=5,filters=filters,
)# 转换检索到的文本内容,构造成特定格式,方便调用大模型existing_memories = [MemoryItem(id=mem.id,score=mem.score,metadata=mem.payload,memory=mem.payload["data"],)for mem in existing_memories
]
serialized_existing_memories = [item.model_dump(include={"id", "memory", "score"})for item in existing_memories
]
messages = get_update_memory_messages(serialized_existing_memories, extracted_memories
)# 调用大模型,确定需要采取的动作列表tools = [ADD_MEMORY_TOOL, UPDATE_MEMORY_TOOL, DELETE_MEMORY_TOOL]
response = self.llm.generate_response(messages=messages, tools=tools)tool_calls = response["tool_calls"]response = []
if tool_calls:available_functions = {"add_memory": self._create_memory_tool,"update_memory": self._update_memory_tool,"delete_memory": self._delete_memory_tool,}# 依次执行动作列表,可选动作为 `新增文本`, `更新原有的文本`, `删除原有文本`for tool_call in tool_calls:function_name = tool_call["name"]function_to_call = available_functions[function_name]function_args = tool_call["arguments"]if function_name in ["add_memory", "update_memory"]:function_args["metadata"] = metadatafunction_result = function_to_call(**function_args)response.append({"id": function_result,"event": function_name.replace("_memory", ""),"data": function_args.get("data"),})

可以看到此流程主要依赖大模型的判断能力,利用常规向量库的 CRUD 作为基础操作,实现一个有语义的文本向量更新。

为什么需要做这么复杂,而不是直接插入向量数据库呢?可以参考官网提供的一个简单的例子:

用户 Alice 先插入了两条记录 I like going to hikesI love to play badminton,此时的关系如下所示:

请添加图片描述

当 Alice 隔一段时间不再喜欢羽毛球,新增了 I do not like badminton any more, 此时预期的关系应该更新为如下所示:

请添加图片描述

此时更符合语义的新增方案是更新原有的文本,如果直接插入,则 Alice 可能会关联到两条互相冲突的记录,最终导致可能出现判断问题。

总结

本文是对 Mem0 的实现方案的探索,可以看到 Mem0 提供了一套比较友好的记忆管理接口,可以方便地检索和更新相关的信息,比较适配于大模型应用的场景。

从实现原理上来看,Mem0 主要基于向量数据库实现了相关内容的检索,在文本的更新上,基于大模型进行历史信息的判断,通过组合向量数据库的基础 CRUD 能力,实现了一个有语义的文本更新能力流程。

当然新版本的 Mem0 开始引入了知识图谱进行文本的管理,有兴趣也可以详细了解下。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA毕业设计168—基于Java+Springboot+vue3的高校就业管理系统(源代码+数据库+14000字论文+开题+PPT)

毕设所有选题: https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue3的高校就业管理系统(源代码数据库14000字论文开题PPT)169 一、系统介绍 本项目前后端分离(可以改为ssm版本),分为用户、企业、管理员三种角色 …

shopify独立站分别有哪几类?难点在哪?

对于刚开独立站的业内人士来说,今天的文章将向您介绍Shopify店铺的类型以及运营店铺的难点。这使您可以更好地计划销售哪些产品以及如何运营。 ✅Shopify 类型 综合商店:又称全能商店 这种类型通常采用直销模式。卖家不需要提供自己的产品。您可以选择…

git 配置、下载、提交、更新、冲突解决学习

目录 一. 安装教程 二. git配置 1. 查看git配置参数 2. 设置邮箱和用户名 3. SSH配置 4. 配置git远程库公钥 5. 编码设置 三. git 提交流程 1. 整体操作流程图 2. Git仓库包含5个区域 3. 下载、提交、更新命令 3.1. 下载 3.2. 提交 3.3. 更新(两种方式…

前端框架有哪些?

成长路上不孤单😊【14后,C爱好者,持续分享所学,如有需要欢迎收藏转发😊😊😊😊😊😊😊!!!!&#xff…

游戏应用|空地模型实景融合,还原《黑神话:悟空》游戏场景

古色斑驳,巍峨险峻,是历史的低语,诉说着千百年的沧桑与辉煌;飞檐翘角,雕梁画栋,凝聚着时代的文明与智慧。在数字化浪潮下,我们利用实景三维技术,翻开了中华古建筑这本伟大的史诗。 P…

基于物联网的低成本便携式传感器节点用于火灾和空气污染的检测与报警

目录 摘要 引言 材料和方法 传感器节点 IoT 微控制器 颗粒物传感器 环境和气体传感器 MQTT代理 Node-Red监控平台 系统结构 数据存储 工作描述 实验结果 讨论 结论 致谢 参考文献 这篇论文的标题是《Low-cost IoT-based Portable Sensor Node for Fire and Air…

【算法每日一练及解题思路】计算以空格隔开的字符串的最后一个单词的长度

【算法每日一练及解题思路】计算以空格隔开的字符串的最后一个单词的长度 一、题目:计算以空格隔开的字符串的最后一个单词的长度 二、举例: 输入:hello nowcoder 输出:8 说明:最后一个单词为nowcoder,长…

【超详细】Linux开发环境搭建指南 | Ubuntu

文章目录 虚拟机安装对比Virtual Box 下载ubuntu 操作系统下载Virtual Box 安装安装ubuntu设置中文语言共享文件夹设置添加输入法安装步骤,参考官方教程 安装 vscode解决主机不能通过ssh连接宿主机网络连接几种网络连接区别主机和宿主机相互 ping通 网络代理 虚拟机…

AI 网关基于 IP 地理位置,增强 Prompt 修饰能力

作者:沈鑫糠,来自昆仑数智瑞道云团队,专注于云原生领域产品研发和相关技术。 前言 什么是 Prompt Engineering 提示词工程(Prompt Engineering),也被称为上下文提示(In-Context Prompting&am…

云服务器+docker:还在为项目上线苦恼?一文包你解决(保姆级教程,图文并茂,万字起步!!!)

目录 Blue留言机: 学习视频以及参考资料 : 1、学习之前的必备操作: 第一步:购买服务器 选择一台免费的云服务器(包白嫖的) 配置服务器的一点说明: 查看自己是否购买成功: 第…

Codeforces Round 920 (Div. 3)(A,B,C,D)

A 在二维坐标轴上有一个正方形&#xff0c;给你一个正方形的四个顶点坐标&#xff0c;求面积 知道一个边长&#xff0c;平方即可 for(int i0;i<4;i)x[i]x1; Arrays.sort(x); //1122 kMath.abs(x[2]-x[1]); System.out.println(k*k); B 操作1、2是添加和修改&#xff0c;操…

Django+Vue二手交易平台的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 需要的环境3.2 Django接口层3.3 实体类3.4 config.ini3.5 启动类3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作者&…

ubuntu14.04.5出现配环境后重启进不了图形化界面解决记录

前言 这段时间给公司接了一个需要使用到linux环境进行交叉编译的工程&#xff0c;就采用了简单易操作的图形化ubuntu系统。 镜像采用的是&#xff1a;ubuntu14.04.5-desktop-amd64.iso(官网下载的&#xff09; 配置环境的过程下载了众多依赖包&#xff0c;总之就是缺啥下载啥…

vue通过html2canvas+jspdf生成PDF问题全解(水印,分页,截断,多页,黑屏,空白,附源码)

前端导出PDF的方法不多&#xff0c;常见的就是利用canvas画布渲染&#xff0c;再结合jspdf导出PDF文件&#xff0c;代码也不复杂&#xff0c;网上的代码基本都可以拿来即用。 如果不是特别追求完美的情况下&#xff0c;或者导出PDF内容单页的话&#xff0c;那么基本上也就满足业…

HOW DO VISION TRANSFORMERS WORK

HOW DO VISION TRANSFORMERS WORK Namuk Park1,2, Songkuk Kim1 1Yonsei University, 2NAVER AI Lab{namuk.park,songkuk}yonsei.ac.kr 总结 MSA 改善模型泛化能力&#xff1a; MSA 不仅提高了模型的准确性&#xff0c;还通过平滑损失景观来提高泛化能力。损失景观的平坦化使…

ArkUI-动画

ArkUI-动画 系统能力属性动画显式动画 关键帧动画转场动画路径动画粒子动画 资源调用GIF动画帧动画 三方库LottieSVG 提升动画的流畅度使用renderGroup概述使用约束 系统能力 属性动画 通过更改组件的属性值实现渐变过渡效果&#xff0c;例如缩放、旋转、平移等。支持的属性包…

乐鑫 ESP32-P4 无线连接解决方案

ESP32-P4 是乐鑫信息科技推出的一款功能强大的芯片 (SoC) &#xff0c;专为高性能的应用打造。尽管 ESP32-P4 集成了一系列先进特性&#xff0c;但它并未设置无线连接功能&#xff0c;因此需要额外的连接方案来满足嵌入式系统的多样化需求。乐鑫为 ESP32-P4 提供了三种主要的连…

2分钟学会使用createrepo制作本地yum仓库

华子目录 createrepo介绍实验主题实验前提实验前的准备1.server端配置yum网络源&#xff08;这里以阿里云为主&#xff09;2.server端配置本地yum源&#xff08;需要挂载本地镜像&#xff09;3.关闭selinux和firewalld4.安装createrepo包 server端实验步骤1.只下载&#xff0c;…

检测SSRF漏洞的工具

免责声明此文档仅限于学习讨论与技术知识的分享&#xff0c;不得违反当地国家的法律法规。对于传播、利用文章中提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;本文作者不为此承担任何责任&#xff0c;一旦造成后果请自行承担&…

Self-study Python Fish-C Note19 P62to63

类和对象 (part 2) 本节主要介绍 类和对象的构造函数、重写、钻石继承、Mixin及案例源码剖析&#xff08;原视频P62-63)\ 构造函数 之前我们在函数章节里说&#xff0c;函数是可以通过参数来进行个性化定制的。类在实例化的时候其实也是支持个性化定制对象的。 定义类的时候…