跳至主要内容

Mem0 教程:为 AI 应用提供持久化记忆层

学习使用 Mem0 为 LLM 添加持久化记忆。在这份循序渐进的教程中,借助自定义筛选与图谱搜索,构建一个聪明的学习助手机器人。
· 11分钟 阅读

使用 AI 探索

您告诉聊天机器人您是素食者。第二天,它却给您推荐牛排食谱。这不是 bug,而是大语言模型(LLM)的工作方式。它们在会话之间没有记忆,把每次对话都当作白纸。

日常使用尚可,但如果您要为真实用户构建应用,这种无状态就会成为问题。用户会期望 AI 记得他们。

Mem0 为任意 LLM 添加记忆层来解决这一点。它在跨会话存储、检索并更新用户信息,让您的 AI 能够真正随时间学习和适应。

在本教程中,您将构建一个能记住用户偏好、跟踪对话历史,并在每次交互中变得更聪明的个人 AI 助手。我们将同时介绍云端与自托管两种部署方式,便于您按项目需求选择。

如果您尚未使用过,请学习这门课程,了解 如何使用 OpenAI API。

什么是 Mem0?

Mem0 是一个位于应用与 LLM 之间的开源记忆层。它会自动从对话中提取相关信息、进行存储,并在需要时检索。该项目于 2025 年 10 月融资 2400 万美元,且可与任意 LLM 提供商配合使用:OpenAI、Anthropic、Ollama,或您的自有模型。

Mem0 将记忆组织为三个范围:

  • 用户记忆:在与特定用户的所有对话中持续存在。如果某人提到更喜欢早晨学习,这一事实将在每次未来会话中可用。

  • 会话记忆:跟踪单次对话内的上下文,比如当前讨论的食谱。

  • 代理记忆:存储某个特定 AI 代理实例的专属信息。

您可以组合这些范围,构建不同代理共享(或隔离)其所知用户信息的复杂应用。

The three memory scopes: user, session, and agent, with examples.

三种记忆范围:用户、会话与代理,并附示例。

在底层,Mem0 结合了向量搜索与图谱关系。当您将对话加入记忆时,它会自动提取关键信息,您无需手动标注哪些内容应被记住。

当应用需要上下文时,Mem0 会基于当前查询取回相关记忆,并注入到提示词中。这比在每次请求里塞入整段对话历史要高效得多。

您可以通过两种方式运行 Mem0:

  • 平台版:位于 app.mem0.ai 的云端托管服务,提供快速上手与 API。

  • 自托管:让您完全掌控基础设施,可自选向量数据库与嵌入模型。

两种方式都使用相同的 Python SDK,因此在它们之间切换十分简单。

性能提升是确凿的,正如Mem0 的论文所示。在 LOCOMO 基准上,Mem0 比 OpenAI 的内置记忆功能高出 26%。它还通过有选择地检索相关记忆,而不是处理全部对话历史,使响应速度快了 91%。与全上下文方案相比,Token 使用量约降至十分之一。

现在您已了解 Mem0 能做什么,我们来开始配置。

Mem0 快速上手

安装依赖包,并使用 python-dotenv 管理 API 密钥:

pip install mem0ai python-dotenv

在 app.mem0.ai 注册并在仪表盘获取您的 API 密钥。在项目目录创建一个 .env 文件:

MEM0_API_KEY=your-api-key-here

现在,使用该 API 密钥初始化客户端:

from mem0 import MemoryClient
from dotenv import load_dotenv
import os

load_dotenv()

client = MemoryClient(api_key=os.getenv("MEM0_API_KEY"))

要存储记忆,请以 OpenAI 聊天格式传入一段对话。user_id 参数用于将记忆限定到特定用户:

messages = [
	{"role": "user", "content": "I'm a vegetarian and allergic to nuts."},
	{"role": "assistant", "content": "Got it! I'll remember that."}
]
client.add(messages, user_id="user123")

记忆处理在后台进行。add() 方法会立即返回待处理状态,随后 Mem0 会提取并存储相关事实。

要检索记忆,使用 search() 并配合自然语言查询:

results = client.search("dietary restrictions", filters={"user_id": "user123"})

响应会包含提取出的记忆及其相关性分数:

{'results': [
	{'memory': 'User is allergic to nuts', 'user_id': 'user123', 'score': 0.66},
	{'memory': 'User is a vegetarian', 'user_id': 'user123', 'score': 0.65}
]}

请注意,Mem0 会自动把“vegetarian”和“allergic to nuts”拆分为两条独立事实。系统负责抽取;当您搜索时,会基于语义相似度返回最相关的记忆。

了解基础后,我们来构建更实用的内容。

构建一个基于 Mem0 的 AI 代理

基础的添加/搜索流程很有用,但真实应用需要更强的能力。我们来构建一个学习助手机器人,使其能自主决定何时存储、检索与更新记忆。我们将使用 OpenAI Agents SDK,让代理可以自行调用其记忆工具。

如果您刚接触用 LLM 构建代理,可先阅读我们关于构建 LangChain 代理的教程,了解相关概念。若要更深入了解 OpenAI Agents SDK,请参阅这篇OpenAI Agents SDK 教程。

设置依赖

安装 OpenAI Agents SDK 与 Mem0:

pip install openai-agents mem0ai python-dotenv

将您的 OpenAI API 密钥加入 .env 文件:

MEM0_API_KEY=your-mem0-key
OPENAI_API_KEY=your-openai-key

现在,初始化两个客户端,并创建一个用于向工具传递用户信息的上下文类:

import os
from dataclasses import dataclass
from agents import Agent, Runner, function_tool, RunContextWrapper
from mem0 import MemoryClient
from dotenv import load_dotenv

load_dotenv()

mem0 = MemoryClient(api_key=os.getenv("MEM0_API_KEY"))

@dataclass
class UserContext:
	user_id: str

UserContext 数据类保存工具所需的用户相关数据。RunContextWrapper 使我们能将该上下文传递给代理调用的任意工具。

创建记忆工具

代理需要三个工具:搜索、保存与更新。我们使用 @function_tool 装饰器将这些工具暴露给代理。

首先,搜索工具用于检索相关记忆。我们在输出中包含记忆 ID,便于代理后续引用并更新:

@function_tool
def search_memory(ctx: RunContextWrapper[UserContext], query: str) -> str:
	"""Search through past learning history and memories."""
	memories = mem0.search(
    	query,
    	filters={"user_id": ctx.context.user_id},
    	limit=5
	)
	if memories and memories.get("results"):
    	return "\n".join([
         	f"- [ID: {m['id']}] {m['memory']}" for m in memories["results"]
     	])
 	return "No relevant memories found."

接着,保存工具用于存储新信息:

@function_tool
def save_memory(ctx: RunContextWrapper[UserContext], content: str) -> str:
 	"""Save new information about the user's learning journey."""
 	mem0.add(
     	[{"role": "user", "content": content}],
     	user_id=ctx.context.user_id
 	)
 	return "Memory saved successfully."

最后,更新工具用于在信息变更时修改已有记忆:

@function_tool
def update_memory(ctx: RunContextWrapper[UserContext], memory_id: str, new_text: str) -> str:
 	"""Update an existing memory with new information."""
 	mem0.update(memory_id=memory_id, text=new_text)
 	return f"Memory {memory_id} updated."

定义代理

现在我们创建代理,并为其提供何时使用各工具的说明:

agent = Agent(
 	name="Learning Companion",
 	instructions="""You are a helpful learning companion with memory. 
            Use search_memory to recall what the user is learning and their level.
            Search results include memory IDs in format [ID: xxx].
            Use save_memory to store new topics, preferences, or progress.
            Use update_memory when information changes. First search to find the memory ID, then call update_memory with that ID and the new text.
            Always check memory before responding to personalize your answers.""",
 	tools=[search_memory, save_memory, update_memory],
 	model="gpt-4o"
)

此处使用 gpt-4o,但若想提升工具使用的推理能力,我建议使用 GPT-5。欢迎查看我们的 GPT-5 API 教程,了解它的新功能实战。

运行代理

聊天函数会将用户上下文传给代理:

def chat(user_input: str, user_id: str) -> str:
	result = Runner.run_sync(
     	agent,
     	user_input,
         context=UserContext(user_id=user_id)
	)
	return result.final_output

每次调用 Runner.run_sync() 都与其他调用完全独立。OpenAI Agents SDK 默认不会在调用之间维护对话历史。

这在我们的演示中是有意为之:当代理能在多次调用间记住用户信息时,该记忆必须来自 Mem0,而非任何隐藏的代理状态。

测试记忆持久性

我们用需要真实记忆检索的查询进行测试。如果不访问已存信息,代理无法准确给出答案。

先存一些用户信息:

response = chat(
	"My name is Alex. I am learning data visualization with matplotlib. "
	"I am at intermediate level.",
	"student_01"
)
print(response)
Got it, Alex! You're learning data visualization with Matplotlib at an intermediate level. How can I assist you today?

等待几秒以完成异步处理后,测试回忆:

response = chat("What is my name and what library am I learning?", "student_01")
print(response)
Your name is Alex, and you're learning data visualization using Matplotlib at an intermediate level.

现在测试更新功能:

response = chat(
	"I switched from matplotlib to seaborn. Please update your memory.",
	"student_01"
)
print(response)
Got it! I've updated your learning preference to Seaborn for data visualization at an intermediate level. If you need help with anything specific, just let me know!

验证更新是否生效:

response = chat("What visualization library am I using now?", "student_01")
print(response)
You are currently using Seaborn for data visualization at an intermediate level.

最后,测试跨会话的持久性:

response = chat("Give me a summary of everything you know about me.", "student_01")
print(response)
Here's what I know about you:

- Your name is Alex.
- You are learning data visualization with Seaborn at an intermediate level.

Is there anything else you'd like to update or add?

我们的 Mem0 代理如何工作

代理会根据对话选择要调用的工具。

当用户询问个人资料时,它会调用 search_memory;当用户分享新信息时,它会调用 save_memory;当用户表示信息变更时,它会先搜索以获取记忆 ID,然后调用 update_memory。

我们从不显式告知每条消息该用哪个工具。

这与第 3 节的手动添加/搜索流程不同。那里我们是显式调用方法;这里由代理做决定。该模式更易扩展,适用于无法预判每种交互类型的复杂应用。

Comparison of manual and agent-driven workflows for scalability

手动与代理驱动流程的可扩展性对比

重要提示:记忆处理是异步的。调用 save_memory 后,新记忆在可被搜索前会有短暂延迟。在生产环境中,您需要在界面上考虑这一点。

微调 Mem0 的行为

基础代理能处理记忆操作,但生产应用需要更精细的控制,以决定存什么、如何取。Mem0 提供项目级设置,可提升记忆质量,包括用于组织的自定义类别、用于筛选的用户自定义指令、定向搜索与清理操作。

为学习领域定制类别

默认情况下,Mem0 使用“美食”“旅行”“爱好”等通用类别。对我们的学习助手这类特定应用来说,这些帮助不大。您可以自定义类别,以匹配您的领域:

client.project.update(custom_categories=[
	{"name": "topics", "description": "Programming languages, frameworks, or subjects"},
	{"name": "skill_levels", "description": "Proficiency: beginner, intermediate, advanced"},
	{"name": "goals", "description": "Learning objectives and targets"},
	{"name": "progress", "description": "Completed courses, chapters, or milestones"},
	{"name": "preferences", "description": "Learning style, schedule, or format preferences"}
])

设置完成后,Mem0 的分类器会自动用您的类别标注新进入的记忆。当 Alex 说 “I'm learning Python at a beginner level.” 时,系统会同时用 topics 与 skill_levels 进行标注。您无需改动代理代码,分类发生在记忆抽取阶段。

用自定义指令进行选择性记忆

自定义指令能让您精确控制要从对话中提取哪些内容。您用自然语言编写准则,Mem0 在处理新记忆时会遵循这些准则:

client.project.update(custom_instructions="""
Extract and remember:
- Programming topics and technologies mentioned
- Current skill level for each topic
- Learning goals and deadlines
- Progress updates and completions
- Preferred learning resources (videos, docs, exercises)

Do not store:
- Personal identifiers beyond the user_id
- Payment or financial information
- Off-topic conversation that isn't about learning
""")

这对生产应用尤为重要。没有指令时,Mem0 可能会存储无关细节或敏感信息。自定义指令起到过滤器作用,使记忆聚焦于应用真正需要的内容。对于 GDPR 等合规场景,您可以明确排除个人数据类别。

按类别过滤搜索

有了分类记忆后,搜索工具可以更精确。与其搜索所有记忆,不如按类别过滤以获取正需要的内容:

@function_tool
def search_memory(
	ctx: RunContextWrapper[UserContext],
	query: str,
	category: str = None
) -> str:
	"""Search learning history. Optionally filter by category."""
	filters = {"user_id": ctx.context.user_id}
	if category:
    	filters["categories"] = {"contains": category}

	memories = mem0.search(query, filters=filters, limit=5)
	if memories and memories.get("results"):
    	return "\n".join([
        	f"- [ID: {m['id']}] {m['memory']}" for m in memories["results"]
     	])
	return "No relevant memories found."

当代理需要回答“我学过哪些主题?”时,可以用 category="topics" 搜索,跳过与偏好或目标相关的无关记忆。请在代理说明中提及这些类别,以便它在需要时使用过滤搜索。

记忆清理与删除

用户可能希望移除过时或不正确的记忆。添加一个删除工具,赋予代理该能力:

@function_tool
def delete_memory(ctx: RunContextWrapper[UserContext], memory_id: str) -> str:
	"""Delete a specific memory by ID."""
	mem0.delete(memory_id=memory_id)
	return f"Memory {memory_id} deleted."

对于批量操作,您可以直接清空某个用户的所有记忆:

mem0.delete_all(user_id="student_01")

当信息完全变化而非更新时,删除很有用。如果用户说“把我关于 Python 学习的一切都忘了”,代理可以搜索相关记忆逐条删除,或者您也可以提供一键重置来清空其档案。

这四项配置让代理从演示走向可交付:类别自动组织记忆,指令确保只存储相关信息,过滤搜索精准检索所需,删除负责清理。由于大多发生在项目配置层,代理代码仅需极少改动。

有关这些功能的更多详情,请参阅官方 Mem0 文档。

用图谱记忆跟踪关系

标准记忆存储的是孤立事实,例如“Alex 在学习 Seaborn”与“Alex 懂 matplotlib”。但它不会体现 Alex 先学了 matplotlib,随后转为 Seaborn。图谱记忆为此添加关系层。当顺序、进程或实体间关联很重要时,图谱记忆可为代理提供更丰富的上下文。

注意:图谱记忆仅在 Pro 方案($249/月)及以上可用。

开启图谱记忆

您可以在项目级启用图谱记忆:

client.project.update(enable_graph=True)

也可以在单次请求中传入 enable_graph=True:

client.add(messages, user_id="student_01", enable_graph=True)

启用后,Mem0 会从自然对话中自动抽取实体(人物、主题、工具、日期)及其相互关系。

图谱搜索如何工作

使用图谱记忆进行搜索时,Mem0 会同时返回记忆与一个 relations 数组,展示实体如何关联:

results = client.search(
	"What has Alex learned?",
	filters={"user_id": "student_01"},
	enable_graph=True
)

# Results include both memories and relations
print(results.get("relations"))

这些关系会体现诸如 “Alex → learned → matplotlib” 与 “Alex → switched to → seaborn” 的连接。有了它,您的代理无需显式存储这些关系,也能回答有关学习进程的问题。

何时使用图谱记忆

图谱记忆会带来一定处理开销,因此在关系重要时使用:

  • 学习平台跟踪技能进阶

  • 客户支持分析交互历史

  • 项目管理映射任务依赖

  • 医疗场景中随时间关联症状与治疗

对于简单的事实回忆,标准记忆更快。当代理需要基于序列或信息间连接进行推理时,再启用图谱记忆。

Mem0:平台版 vs. 开源版

Mem0 提供两种形态:平台版与开源版。

在本教程中,我们使用的是平台版,即通过 MemoryClient 与来自 app.mem0.ai 的 API 密钥访问的托管云服务。两种形态共享核心记忆操作(add()、search()、update()、delete()),但在部署、定价与可控性上有所不同。

平台版

平台版是 Mem0 的托管服务。注册获取 API 密钥后,几分钟即可开始添加记忆。Mem0 负责基础设施、扩展性与安全认证(如 SOC 2 Type II、GDPR)。

共有四个定价梯度:

  • Free:10,000 条记忆,适合原型设计。

  • Starter:$19/月,更高配额。

  • Pro:$249/月,适合生产负载。

  • Enterprise:定制定价与专属支持。

平台版包含开源版没有的功能:用于关系跟踪的图谱记忆、实时通知的 Webhook、带说话人标注的群聊、以及内置分析。

您按使用量付费,但节省了基础设施与运维时间。

开源版

开源版运行在您自己的服务器上。您安装 mem0ai 包,配置向量数据库,并自行管理部署。虽然需要更多设置,但能获得完全控制权。

可选的基础设施组件包括:

  • 向量数据库:24+ 种选择,包括 Qdrant、Chroma、Pinecone、PostgreSQL(pgvector)与 MongoDB

  • LLM 提供商:16+ 种选择,包括 OpenAI、Anthropic、Ollama、Groq 与本地模型

  • 嵌入模型:OpenAI、HuggingFace 或自定义嵌入器

开源版使用 Memory 类,而非 MemoryClient。

您的成本取决于基础设施(云主机、数据库托管、LLM 提供商的 API 调用)。在规模化场景下可能比平台版更便宜,但维护、备份与合规均由您负责。

何时选择平台版或开源版

请参考下表,比较 Mem0 的托管版与开源版:

方面

平台版

开源版

搭建时间

数分钟

数小时至数天

基础设施

全托管

自管

定价

$0-249+/月

您的基础设施成本

向量数据库选项

托管

24+ 种选择

LLM 选项

托管

16+ 种选择

合规认证

包含 SOC 2、GDPR

需自行实现

数据位置

Mem0 服务器

您的服务器

我的建议是选用平台版进行快速原型开发、无需运维开销的生产应用,或当您需要内置合规支持时。

如果您更关注数据主权、自定义模型配置,或在高规模下进行成本优化,则开源版更适合。

有关详细部署指南,请查看 平台版快速上手 或 开源版概览。

结语

本教程介绍了如何用 Mem0 为 LLM 应用添加持久化记忆。您先从基础记忆操作入手,然后借助 OpenAI Agents SDK 构建了能自主管理记忆的学习助手;随后通过自定义类别、指令与过滤搜索配置记忆行为;最后比较了平台版与开源版的部署方案。

在生产环境中,请为记忆操作添加错误处理,并考虑保存新记忆后的短暂延迟。如果您使用平台版免费层,也要留意速率限制。

想要超越单个组件,系统性掌握 AI 应用开发的全栈?立即报名 AI Engineer for Developers 职业路线。

Mem0 常见问题

什么是 Mem0?它与对话历史有何不同?

Mem0 是一个记忆层,会从对话中抽取并存储相关事实,而非完整转录。它会按查询仅检索语境相关的记忆,与全上下文方案相比可将 Token 使用量降低约 90%。

Mem0 是否免费?

平台版提供免费层,含 10,000 条记忆,适合原型设计。付费方案起价 $19/月(Starter),$249/月(Pro)。开源版免费,但需要自托管基础设施。

我能否在 OpenAI 之外的 LLM 提供商上使用 Mem0?

是的。Mem0 可与任意 LLM 提供商配合使用,包括 Anthropic、Ollama、Groq 与本地模型。开源版支持 16+ 个 LLM 提供商与 24+ 种向量数据库。

如何删除或更新已存储的记忆?

使用 client.update(memory_id=id, text=new_text) 修改已有记忆,或使用 client.delete(memory_id=id) 删除。对于批量删除,使用 client.delete_all(user_id=”<user_id>”)。

用户、会话与代理记忆有什么区别?

用户记忆会在与特定用户的所有对话中持续存在。会话记忆跟踪单次对话内的上下文。代理记忆存储某个 AI 代理实例的专属信息。

Bexruz (Bex) Tuychiev

作者

Bexruz (Bex) Tuychiev

我是一名数据科学内容创作者,拥有超过 2 年的经验,并在 Medium 上拥有较大的读者群。我喜欢用略带讽刺的笔调撰写有关 AI 和机器学习的深度文章——毕竟总得想点办法让这些内容不那么枯燥。我已发表 130 多篇文章,并制作了一门 DataCamp 课程,另有一门正在筹备中。我的内容已被超过 500 万人次阅读,其中有 2 万人在 Medium 和 LinkedIn 上成为关注者。 

主题