|
最近很多AI自媒体又在吹一个叫mem0的项目,可以替代甚至超越RAG。 
Mark基于他们提供的知识,分析了半天,得出一个结论:“完全无法替代RAG,又是一个被过度吹捧的项目”。 直到最近,mem0冲上了GitHub热榜Top1,才让我又一次重视起这个项目! 
这次我决定自己研究,跑了一下官方给的demo,得出正确的结论:“mem0是个性化记忆层工具,可以让用户实现跨AI应用的长期个性化记忆,和RAG没有半毛钱关系,不可以替代RAG,硬说关联的话,唯一的相同点是都用到了向量存储这种技术”。
真的不能相信自媒体的狗话,差点让我错过了一个好项目。
下面就跟着Mark深入浅出,看一下到底什么是mem0 推荐到我的个人博客获取最佳阅读体验:
https://s.markup.com.cn/4 Mem0 为大型语言模型提供了一个智能、自我改进的记忆层,使得跨应用程序的个性化 AI 体验成为可能。 官网:https://docs.mem0.ai/overview 开源地址:https://github.com/mem0ai/mem0 ingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 4px solid rgb(94, 106, 210);color: rgb(63, 63, 63);">核心功能用户、会话与智能体记忆: 跨用户会话、交互及智能体保留信息,确保连贯性与上下文一致性。 自适应个性化: 基于用户互动和反馈持续优化个性化体验。 开发者友好的API: 提供简洁明了的 API,实现与各类应用程序的无缝集成。 平台一致性: 确保不同平台和设备上的行为与数据保持一致。 托管服务: 提供易于部署和维护的托管解决方案。 ingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 4px solid rgb(94, 106, 210);color: rgb(63, 63, 63);">快速开始暂时无法在飞书文档外展示此内容 https://nbviewer.org/github/FB208/PromptEngineering/blob/master/4-mem0-quicker%20start.ipynb ingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 4px solid rgb(94, 106, 210);color: rgb(63, 63, 63);">原理分析部分源码defadd( self, data, user_id=None, agent_id=None, run_id=None, metadata=None, filters=None, prompt=None, ): """ Createanewmemory.
Args: data(str) atatostoreinthememory. user_id(str,optional):IDoftheusercreatingthememory.DefaultstoNone. agent_id(str,optional):IDoftheagentcreatingthememory.DefaultstoNone. run_id(str,optional):IDoftheruncreatingthememory.DefaultstoNone. metadata(dict,optional):Metadatatostorewiththememory.DefaultstoNone. filters(dict,optional):Filterstoapplytothesearch.DefaultstoNone.
Returns: str:IDofthecreatedmemory. """ ifmetadataisNone: metadata={} embeddings=self.embedding_model.embed(data)
filters=filtersor{} ifuser_id: filters["user_id"]=metadata["user_id"]=user_id ifagent_id: filters["agent_id"]=metadata["agent_id"]=agent_id ifrun_id: filters["run_id"]=metadata["run_id"]=run_id
ifnotprompt: prompt=MEMORY_DEDUCTION_PROMPT.format(user_input=data,metadata=metadata) extracted_memories=self.llm.generate_response( messages=[ { "role":"system", "content":"Youareanexpertatdeducingfacts,preferencesandmemoriesfromunstructuredtext.", }, {"role":"user","content":prompt}, ] ) existing_memories=self.vector_store.search( name=self.collection_name, query=embeddings, limit=5, filters=filters, ) existing_memories=[ MemoryItem( id=mem.id, score=mem.score, metadata=mem.payload, text=mem.payload["data"], ) formeminexisting_memories ] serialized_existing_memories=[ item.model_dump(include={"id","text","score"}) foriteminexisting_memories ] logging.info(f"Totalexistingmemories:{len(existing_memories)}") messages=get_update_memory_messages( serialized_existing_memories,extracted_memories ) #Addtoolsfornoop,add,update,deletememory. 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=[] iftool_calls: #Createanewmemory available_functions={ "add_memory":self._create_memory_tool, "update_memory":self._update_memory_tool, "delete_memory":self._delete_memory_tool, } fortool_callintool_calls: function_name=tool_call["name"] function_to_call=available_functions[function_name] function_args=tool_call["arguments"] logging.info( f"[openai_func]func:{function_name},args:{function_args}" )
#Passmetadatatothefunctionifitrequiresit iffunction_namein["add_memory","update_memory"]: function_args["metadata"]=metadata
function_result=function_to_call(**function_args) #Fetchthememory_idfromtheresponse response.append( { "id":function_result, "event":function_name.replace("_memory",""), "data":function_args.get("data"), } ) capture_event( "mem0.add.function_call", self, {"memory_id":function_result,"function_name":function_name}, ) capture_event("mem0.add",self) returnresponse
MEMORY_DEDUCTION_PROMPT 如下: MEMORY_DEDUCTION_PROMPT=""" Deducethefacts,preferences,andmemoriesfromtheprovidedtext. Justreturnthefacts,preferences,andmemoriesinbulletpoints: Naturallanguagetext:{user_input} User/Agentdetails:{metadata}
Constraintfordeducingfacts,preferences,andmemories: -Thefacts,preferences,andmemoriesshouldbeconciseandinformative. -Don'tstartby"ThepersonlikesPizza".Instead,startwith"LikesPizza". -Don'tremembertheuser/agentdetailsprovided.Onlyrememberthefacts,preferences,andmemories.
Deducedfacts,preferences,andmemories: """
#翻译 """ 从提供的文本中推断出事实、偏好和记忆。 只需在要点中返回事实、偏好和记忆: 自然语言文本:{user_input} 用户/代理详细信息:{元数据}
推断事实、偏好和记忆的约束: -事实、偏好和记忆应该简明扼要。 -不要从“这个人喜欢披萨”开始。相反,从“喜欢披萨”开始。 -不要记住提供的用户/代理详细信息。只记住事实、偏好和记忆。
推断的事实、偏好和记忆: “”
逻辑这里的逻辑比较简单 通过 MEMORY_DEDUCTION_PROMPT 结合用户的数据,拼接成提示词 利用大模型提取抽取记忆数据,得到新的记忆项 从历史记忆中提取5条最相关的记忆 然后将新的记忆项、历史记忆 拼接到一起,交予大模型,让大模型调用合适的tool来更新记忆,tools :[ADD_MEMORY_TOOL, UPDATE_MEMORY_TOOL, DELETE_MEMORY_TOOL] 根据function call的结果,调用tool_calls更新记忆
分析本质上全部委托给大模型,通过prompt做了一定的约束: 通过LLM(大型语言模型)和特定的元数据来抽取记忆信息,类似于进行知识图谱抽取。 相关记忆信息通过向量化存储,因此可以支持记忆信息检索 记忆会根据输入的内容不断更新,但是同所有长期记忆一样,也会逐渐遗忘东西
问题ingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 4px solid rgb(94, 106, 210);color: rgb(63, 63, 63);">总结mem0与RAG无任何关系,更像是之前智能体中常用的“长期记忆”功能的升级,升级了以下几点:
|