Mem0 技术原理、架构设计与实现方法(Photo by Mohammad Rahmani on Unsplash)

目录快速导航本篇内容:

目录1. 基础概念1.1 背景1.2 核心概念2. 理论框架2.1 记忆层架构2.2 Mem0 如何实现长期记忆2.3 Mem0 图记忆2.4 OpenMemory MCP2.5 原理描述3. 实践过程3.1 环境搭建3.2 基本使用示例3.3 Mem0 与 LangGraph 集成3.4 使用 Mem0 与 Dify 集成4. 高级探索4.1 高级功能4.2 高级 API 使用与最佳实践4.3 插件机制与二次开发5. 总结资源获取1. 基础概念1.1 背景Mem0(发音为 "mem-zero")是一款专为 AI 智能体设计的开源记忆管理系统,致力于解决 AI 交互过程中的"遗忘"难题。在传统应用中,用户在不同 AI 工具间切换时,常常会遇到上下文丢失、体验割裂等问题。Mem0 通过提供统一的记忆层,使智能体能够跨会话、跨应用持续保留用户偏好与历史交互信息,从而实现真正的个性化和持续学习体验。

Mem0 的核心愿景是成为用户的"记忆背包",让关键上下文信息能够在不同 AI 工具之间自由携带和共享。无论是客户支持、个人助手还是医疗咨询等场景,Mem0 都能为智能体赋予持久记忆和上下文感知能力,极大提升个性化交互体验和智能体的实用性。

根据 Mem0 最新的研究论文数据,Mem0 相较于 OpenAI Memory 方案,在准确率上提升了 26%,延迟降低了 91%,同时实现了 90% 的令牌消耗节省。这些显著的性能优势,使 Mem0 成为构建生产级 AI 智能体系统的理想选择。

Announcing our research paper: Mem0 achieves 26% higher accuracy than OpenAI Memory, 91% lower latency, and 90% token savings! Read the paper to learn how we're revolutionizing AI agent memory.'

1.2 核心概念Mem0 的核心理念体现在以下几个方面:

记忆处理:利用大语言模型(LLM)自动从对话中提取关键信息,并将其结构化存储,确保上下文的完整性和可追溯性。记忆管理:系统能够持续更新和维护存储的记忆内容,自动检测并解决信息冲突,保证记忆的准确性和一致性。双重存储架构:创新性地结合了向量数据库(用于高效语义检索)和图数据库(用于实体关系追踪),实现了记忆的多维度管理。智能检索系统:通过语义搜索与图查询相结合,能够基于记忆的重要性、时效性等多维度条件,精准检索出最相关的历史信息。模型上下文协议(MCP):提供标准化的协议接口,支持不同 AI 应用间的记忆共享与互通,打破信息孤岛。本地化处理:所有数据处理与存储均可在本地完成,极大保障了用户隐私和数据安全,用户对数据拥有完全控制权。Mem0 支持多级记忆架构,包括:

用户级记忆:跨会话持久化保存用户偏好和历史行为会话级记忆:记录当前交互的上下文信息智能体级记忆:存储 AI 系统自身的知识和学习成果2. 理论框架2.1 记忆层架构Mem0 的记忆层架构巧妙结合了大语言模型(LLM)与向量存储技术。LLM 负责从用户与智能体的对话中自动提取关键信息,而向量存储则将这些信息转化为高维向量,实现高效的语义检索。通过这种架构,AI 智能体能够将历史交互与当前上下文有机结合,生成更加相关和个性化的响应。

记忆层的核心工作流程包括:

信息提取:LLM 对对话内容进行深度分析,自动识别并提取出具有长期价值的关键信息点。向量化:将提取出的信息通过嵌入模型转化为向量表示,便于后续的高效检索。存储:将向量化后的记忆单元存储到向量数据库中,支持大规模、低延迟的语义检索。检索:根据当前用户查询,系统在向量空间中检索出最相关的历史记忆。整合:将检索到的记忆与当前对话上下文进行整合,辅助智能体生成更具针对性和连贯性的响应。这种架构设计,使 Mem0 能够在保证高效率的同时,提供精准且可扩展的记忆检索服务。

2.2 Mem0 如何实现长期记忆Mem0 的长期记忆系统基于以下核心机制:

采用向量嵌入技术,将语义信息高效存储与检索,确保记忆内容的可扩展性与相关性。支持跨会话、跨应用维护用户特定的上下文,实现真正的"记忆不丢失"。内置高效的检索机制,能够快速定位并返回与当前查询最相关的历史互动内容。核心操作接口Mem0 对外提供了两大核心 API 接口,便于开发者与记忆层进行交互:

add:用于提取对话内容并将其存储为结构化记忆单元。search:根据用户查询,检索并返回最相关的历史记忆内容。添加记忆流程添加记忆的操作流程如下图所示:

信息提取:LLM 从对话中自动提取出相关记忆,识别重要实体及其关系。冲突解决:系统会将新提取的信息与现有记忆进行比对,自动识别并解决潜在的矛盾或重复内容,确保记忆的准确性。记忆存储:最终的记忆内容会被存储到向量数据库中,同时相关的实体关系会同步到图数据库中。每次用户与智能体的互动,都会不断丰富和完善记忆库。检索记忆流程记忆检索的操作流程如下图所示:

查询处理:LLM 首先对用户的查询进行理解和优化,系统自动生成针对性的检索过滤条件。向量搜索:系统在向量数据库中执行高效的语义搜索,根据与查询的相关性对结果进行排序,并可按用户、代理、元数据等多维度进行过滤。结果处理:系统将检索到的结果进行合并和排序,最终返回带有相关性分数、元数据和时间戳的记忆内容,供智能体进一步使用。这种多步骤、语义驱动的检索方式,确保了无论是查找特定信息还是探索相关概念,Mem0 都能提供高质量的记忆检索体验。

本小节内容来源于 mem0.ai : Memory Operations

2.3 Mem0 图记忆Mem0 现已支持图形记忆(Graph Memory),通过引入图数据库,用户可以创建和利用信息片段之间的复杂关系,实现更细致入微且具备情境感知的响应。这种集成让用户能够同时发挥基于向量和基于图结构的优势,提升信息检索的准确性和全面性。

示例用法以下示例展示了如何使用 Mem0 的图形操作:

首先,为名为 Alice 的用户添加一些记忆。随着记忆的不断添加,图结构会自动演化,实体和关系被自动提取和连接。用户可以直观地看到记忆网络的变化。添加记忆(1)添加记忆"我喜欢去远足"

Python 代码: m.add("I like going to hikes", user_id="alice123")

(2)添加记忆"我喜欢打羽毛球"

Python 代码: m.add("I love to play badminton", user_id="alice123")

(3)添加记忆"我讨厌打羽毛球"

Python 代码: m.add("I hate playing badminton", user_id="alice123")

(4)添加记忆"我的朋友叫约翰,约翰有一只名叫汤米的狗"

Python 代码: m.add("My friend name is john and john has a dog named tommy", user_id="alice123")

(5)添加记忆"我的名字是爱丽丝"

Python 代码: m.add("My name is Alice", user_id="alice123")

(6)添加记忆"约翰喜欢徒步旅行,哈利也喜欢徒步旅行"

Python 代码: m.add("John loves to hike and Harry loves to hike as well", user_id="alice123")

(7)添加记忆"我的朋友彼得是蜘蛛侠"

Python 代码: m.add("My friend peter is the spiderman", user_id="alice123")

搜索记忆(1)搜索名字

Python 代码: m.search("What is my name?", user_id="alice123")

(2)搜索:蜘蛛侠

Python 代码: m.search("Who is spiderman?", user_id="alice123")

备注:图记忆的实现并非独立,而是与向量存储协同工作。每次添加或检索记忆时,系统会同时操作向量数据库和图数据库,实现信息的多维度管理。

本小节内容来源于 mem0.ai : Example Usage

2.4 OpenMemory MCPOpenMemory MCP(模型上下文协议)是 Mem0 的核心协议层,旨在为 AI 交互提供本地化的"记忆背包"。MCP 作为统一的记忆基础设施,支持多种 AI 应用(如 Claude Desktop、Cursor、Windsurf 等)通过标准化协议连接,实现跨工具的记忆共享。所有数据均在本地存储,确保用户对数据的绝对隐私和控制权。

MCP 提供了四个核心 API:

add_memories:存储新的记忆对象search_memory:基于相关性和上下文检索记忆list_memories:查看所有存储的记忆delete_all_memories:清除所有记忆接口示例:

add_memories:存储新的记忆对象

POST /add_memories

{

"memories": [

{

"role": "user",

"content": "我喜欢科幻电影,尤其是星际穿越。"

},

{

"role": "assistant",

"content": "星际穿越确实是一部经典的科幻电影!我会记住你喜欢这类电影。"

}

],

"user_id": "alice",

"metadata": {

"category": "movies"

}

}

search_memory:基于相关性和上下文检索记忆

POST /search_memory

{

"query": "我喜欢什么类型的电影?",

"user_id": "alice",

"limit": 5

}

list_memories:查看所有存储的记忆

POST /list_memories

{

"user_id": "alice"

}

delete_all_memories:清除所有记忆

POST /delete_all_memories

{

"user_id": "alice"

}

OpenMemory MCP 的最大优势在于其完全本地化运行,既保障了用户数据的隐私和安全,又通过标准化协议实现了跨应用的记忆共享和无缝集成。

2.5 原理描述记忆提取与存储Mem0 利用 LLM 从对话中自动提取关键信息。该过程包括:

分析对话内容,识别重要信息点将信息结构化为可检索的记忆单元为记忆分配相关性标签和类别将记忆存储在向量数据库中以下是一个简化的记忆提取流程示例:

def extract_and_store_memory(messages, user_id, metadata=None):

# 使用 LLM 提取关键信息

extracted_info = llm.extract_key_information(messages)

# 结构化为记忆单元

memory_unit = {

"content": extracted_info,

"source_messages": messages,

"user_id": user_id,

"timestamp": datetime.now(),

"metadata": metadata or {}

}

# 向量化记忆

vector = embedder.embed(extracted_info)

# 存储在向量数据库中

vector_store.add(vector, memory_unit)

return memory_unit

记忆检索机制当需要检索记忆时,Mem0 会:

将用户查询转换为向量表示在向量空间中搜索相似的记忆根据相关性、时效性和重要性对结果排序返回最相关的记忆供 AI 使用以下是一个简化的记忆检索流程示例:

def retrieve_memories(query, user_id, limit=5):

# 向量化查询

query_vector = embedder.embed(query)

# 在向量空间中搜索相似记忆

similar_memories = vector_store.search(

query_vector,

filter={"user_id": user_id},

limit=limit

)

# 根据相关性、时效性和重要性排序

ranked_memories = rank_memories(similar_memories)

return ranked_memories

架构组件分析Mem0 的架构包含以下关键组件:

LLM 处理器:负责记忆提取和自然语言理解向量存储:用于高效的语义搜索图数据库:用于追踪记忆间的关系MCP 服务器:提供标准化 API 接口客户端 SDK:便于开发者集成 Mem0 功能这些组件协同工作,为 AI 智能体提供完整的记忆管理解决方案。

3. 实践过程3.1 环境搭建(1)安装 Mem0Mem0 支持托管平台和自托管开源两种使用方式。

托管平台:在 Mem0 平台 注册账号,通过 SDK 或 API 密钥集成记忆层。自托管:适合对数据隐私和本地化有更高要求的开发者。本文以自托管为例,结合 DeepSeek 和 Ollama,适配 OpenAI 访问不畅的场景。主要依赖如下:

LLM 提供商:默认支持 OpenAI gpt-4o-mini,也可选 DeepSeek、Claude 等。向量嵌入模型:如 Ollama 的 mxbai-embed-large。向量存储:如 Qdrant。(2) 安装 mxbai-embed-large如无法使用 OpenAI 嵌入模型,可用本地模型替代。以 Ollama 的 mxbai-embed-large 为例:

ollama pull mxbai-embed-large

# 验证

curl http://localhost:11434/api/embeddings -d '{

"model": "mxbai-embed-large",

"prompt": "Represent this sentence for searching relevant passages: The sky is blue because of Rayleigh scattering"

}'

如返回 embedding 信息,说明模型可用。

(3)安装 Qdrant数据库安装:

docker pull qdrant/qdrant

docker run -p 6333:6333 --name qdrant -d qdrant/qdrant

UI 界面可用 qdrant-web-ui:

git clone https://github.com/qdrant/qdrant-web-ui.git

cd qdrant-web-ui

npm install

npm start

访问 http://localhost:5173/ 查看向量数据库状态。

3.2 基本使用示例以下为 Mem0 的完整使用流程,涵盖初始化、添加记忆、检索记忆等操作:

uv add dotenv langchain langgraph mem0ai ollama

代码示例:

import os

import json

from mem0 import Memory

from mem0.configs.base import MemoryConfig, LlmConfig, EmbedderConfig

# 设置 API 密钥

os.environ["DEEPSEEK_API_KEY"] = "sk-……" # 替换为你的 DeepSeek API 密钥

# 创建配置

config = {

"llm": {

"provider": "deepseek",

"model": "deepseek-chat",

"temperature": 0.2,

"max_tokens": 2000,

"top_p": 1.0

},

"embedder": {

"provider": "ollama",

"model": "mxbai-embed-large"

},

"vector_store": {

"provider": "qdrant",

"config": {

"collection_name": "mem0_new",

"embedding_model_dims": 768,

"host": "localhost",

"port": 6333,

}

},

"reset_vector_store": True

}

# 创建 Memory 实例

m = Memory.from_config(config)

# 添加对话记忆

messages = [

{"role": "user", "content": "我喜欢科幻电影,尤其是星际穿越。"},

{"role": "assistant", "content": "星际穿越确实是一部经典的科幻电影!我会记住你喜欢这类电影。"},

{"role": "user", "content": "我也喜欢克里斯托弗·诺兰的其他电影。"},

{"role": "assistant", "content": "诺兰的作品确实很出色!除了《星际穿越》,他还导演了《盗梦空间》、《信条》、《记忆碎片》等经典作品。您对这些电影有什么特别的看法吗?"}

]

# 添加记忆,并附加元数据

m.add(messages, user_id="alice", metadata={"category": "movies"})

# 检索记忆

memories = m.search(query="我喜欢什么类型的电影?", user_id="alice")

print(json.dumps(memories, indent=2, ensure_ascii=False))

# 获取所有记忆

all_memories = m.get_all(user_id="alice")

print(json.dumps(all_memories, indent=2, ensure_ascii=False))

运行 uv run main.py,可见检索结果如下:

{

"results": [

{

"id": "b052c579-23dd-4d89-933e-4c6ceb4e8958",

"memory": "喜欢克里斯托弗·诺兰的其他电影",

"hash": "a46f8ee3dcfded0fd39d1b5006810adc",

"metadata": {

"category": "movies"

},

"score": 0.6853715,

"created_at": "2025-06-24T07:36:23.381311-07:00",

"updated_at": null,

"user_id": "alice"

},

{

"id": "2fae3fa7-0fa7-4164-b521-5c0d821d1c7a",

"memory": "喜欢科幻电影,尤其是星际穿越",

"hash": "55309121dad25e817ea0b3f132db1e6c",

"metadata": {

"category": "movies"

},

"score": 0.6162164,

"created_at": "2025-06-24T07:36:23.367111-07:00",

"updated_at": null,

"user_id": "alice"

}

]

}

3.3 Mem0 与 LangGraph 集成Mem0 可与 LangGraph 无缝集成,为智能体赋予持久记忆能力。集成步骤如下:

安装依赖:uv add dotenv langchain langgraph mem0ai ollama langchain-deepseek

配置 LLM、嵌入器和向量存储,与前述一致。在 LangGraph 流程中,调用 Mem0 的 add/search 方法,实现记忆的自动存取。代码示例略(详见原文)。

import os

from typing import TypedDict, Annotated

from langgraph.graph import StateGraph, START, END

from langgraph.prebuilt import ToolNode

from mem0 import Memory

from langchain_core.messages import HumanMessage, AIMessage

from langchain.chat_models import init_chat_model

# 设置 API 密钥

api_key = os.getenv("DEEPSEEK_API_KEY", "sk-……") # 请替换为你的 DeepSeek API 密钥

os.environ["DEEPSEEK_API_KEY"] = api_key

# 创建配置

config = {

"llm": {

"provider": "deepseek",

"model": "deepseek-chat",

"temperature": 0.2,

"max_tokens": 2000,

"top_p": 1.0

},

"embedder": {

"provider": "ollama",

"model": "mxbai-embed-large"

},

"vector_store": {

"provider": "qdrant",

"config": {

"collection_name": "mem0_new",

"embedding_model_dims": 768,

"host": "localhost",

"port": 6333,

}

},

"reset_vector_store": True

}

# 初始化 Mem0

m = Memory.from_config(config)

llm = init_chat_model(

"deepseek-chat", # 使用DeepSeek模型

api_key=api_key

)

# 定义状态类型

class State(TypedDict):

messages: list

user_id: str

memories: list

# 定义记忆检索函数

def retrieve_memories(state: State):

query = state["messages"][-1]["content"]

user_id = state.get("user_id", "alice")

memories = m.search(query=query, user_id=user_id)

return {"memories": memories["results"]}

# 定义 LLM 节点

def llm_node(state: State):

# 构建系统提示,包含记忆

memories_str = "\n".join(f"- {m['memory']}" for m in state["memories"])

system_prompt = f"你是一个有记忆能力的助手。以下是用户的相关记忆:\n{memories_str}\n请基于这些记忆回答问题。"

# 准备消息

messages = [{"role": "system", "content": system_prompt}]

messages.extend(state["messages"])

# 调用 LLM

response = llm.invoke(messages)

# 更新消息列表,转换为 dict

new_message = {"role": "assistant", "content": response.content}

return {"messages": state["messages"] + [new_message]}

# 定义记忆存储函数

def store_memories(state: State):

user_id = state.get("user_id", "alice")

# 现在 state["messages"] 已全为 dict

m.add(state["messages"], user_id=user_id)

return {}

# 构建图

graph_builder = StateGraph(State)

graph_builder.add_node("retrieve_memories", retrieve_memories)

graph_builder.add_node("llm", llm_node)

graph_builder.add_node("store_memories", store_memories)

# 添加边

graph_builder.add_edge(START, "retrieve_memories")

graph_builder.add_edge("retrieve_memories", "llm")

graph_builder.add_edge("llm", "store_memories")

graph_builder.add_edge("store_memories", END)

# 编译图

graph = graph_builder.compile()

# 使用图处理查询

result = graph.invoke({

"messages": [{"role": "user", "content": "我最喜欢什么电影?"}],

"user_id": "alice",

"memories": []

})

print(result)

运行代码 uv run main.py 得到如下结果,可以看到 LLM 已经成功使用记忆层。

{

'messages': [{

'role': 'user',

'content': '我最喜欢什么电影?'

}, {

'role': 'assistant',

'content': '根据我们的记忆,您最喜欢的电影是《星际穿越》!这部由克里斯托弗·诺兰执导的科幻杰作确实令人难忘,特别是其中关于时间、空间和人类情感的深刻探讨。您还喜欢诺兰的其他作品,比如《盗梦空间》和《黑暗骑士》三部曲等。需要聊聊最近重温《星际穿越》的新发现吗?'

}],

'user_id': 'alice',

'memories': [{

'id': '2fae3fa7-0fa7-4164-b521-5c0d821d1c7a',

'memory': '喜欢科幻电影,尤其是星际穿越',

'hash': '55309121dad25e817ea0b3f132db1e6c',

'metadata': {

'category': 'movies'

},

'score': 0.62142074,

'created_at': '2025-06-24T07:36:23.367111-07:00',

'updated_at': None,

'user_id': 'alice'

}, {

'id': 'b052c579-23dd-4d89-933e-4c6ceb4e8958',

'memory': '喜欢克里斯托弗·诺兰的其他电影',

'hash': 'a46f8ee3dcfded0fd39d1b5006810adc',

'metadata': {

'category': 'movies'

},

'score': 0.61610943,

'created_at': '2025-06-24T07:36:23.381311-07:00',

'updated_at': None,

'user_id': 'alice'

}]

}

3.4 使用 Mem0 与 Dify 集成Mem0 为 Dify AI 提供了强大的记忆层,通过持续的对话存储和检索功能增强 AI 代理能力:

在 Dify 市场中寻找并安装 Mem0 插件配置 Mem0 API 密钥将 Mem0 插件集成到项目工作流中在提示模板中添加记忆检索指令你是一个有记忆能力的助手。以下是用户的相关记忆:

{{memories}}

请基于这些记忆回答问题。

在 Dify 中调整 LLM 记忆配置,添加以下提示词模板:

你是我的得力助手。

请将以下内容作为你的知识储备,放在 标签内。

{{#context#}}

根据用户的问题,检索已有记忆的结果是:

{{#1747805606313.text#}}

当回答用户问题时:

若不知道答案,就直接说不知道。

若不确定,就向用户澄清问题。

避免提及信息来源于上下文。

根据用户提问的语言进行回答。

配置 Dify 工作流集成 mem0 插件

注意:目前 Dify 的 mem0 插件仅支持托管平台版本,不支持本地版本。

4. 高级探索4.1 高级功能记忆分类与标签Mem0 支持对记忆进行多维度分类和标签管理,提升检索的精度和灵活性。例如:

# 添加带标签的记忆

m.add(messages, user_id="alice", metadata={

"category": "movies",

"tags": ["sci-fi", "preferences"],

"importance": "high"

})

# 按类别检索

memories = m.search(

query="科幻电影",

user_id="alice",

filter={"category": "movies"}

)

# 按标签检索

memories = m.search(

query="科幻电影",

user_id="alice",

filter={"tags": "sci-fi"}

)

# 按重要性检索

memories = m.search(

query="科幻电影",

user_id="alice",

filter={"importance": "high"}

)

记忆导出与迁移Mem0 支持记忆导出,采用 Pydantic schemas 格式,便于记忆的备份和迁移:

# 导出所有记忆

all_memories = m.get_all(user_id="alice")

import json

with open("alice_memories.json", "w") as f:

json.dump(all_memories, f, ensure_ascii=False, indent=2)

4.2 高级 API 使用与最佳实践复杂检索与标签/分类操作Mem0 支持基于多条件(标签、类别、重要性等)的复杂记忆检索,并可实现批量操作。

# 按标签和类别检索

memories = m.search(

query="深度学习",

user_id="alice",

filter={

"category": "ml",

"tags": ["neural-network", "research"]

},

limit=10

)

# 按重要性检索

memories = m.search(

query="紧急事项",

user_id="alice",

filter={"importance": "high"}

)

# 批量导出所有记忆(适合备份/迁移)

all_memories = m.get_all(user_id="alice")

with open("alice_memories.json", "w") as f:

import json

json.dump(all_memories, f, ensure_ascii=False, indent=2)

# 批量导入记忆

with open("alice_memories.json", "r") as f:

memories_data = json.load(f)

for memory in memories_data:

m.add([memory["source_messages"]], user_id="alice", metadata=memory.get("metadata"))

权限控制相关 APIMem0 支持多租户和权限控制,可为不同用户、组织配置隔离的数据空间。

# 创建组织并分配用户

org_id = m.create_organization(name="Acme Corp")

m.add_user_to_organization(user_id="alice", org_id=org_id, role="admin")

# 以组织维度设置隔离

memories = m.search(query="合规", user_id="alice", org_id=org_id)

高级 API 示例(RESTful)通过 OpenMemory MCP,所有操作均可通过 HTTP RESTful API 实现。

POST /search_memory

{

"query": "项目进度",

"user_id": "alice",

"org_id": "acme",

"filter": {"category": "project", "tags": "progress"},

"limit": 5

}

4.3 插件机制与二次开发插件开发Mem0 支持在 MCP Server 层开发自定义插件。插件可用于前置/后置处理、自定义嵌入器和存储适配器。

from mem0.plugins import register_preprocessor

def custom_preprocessor(memory_item):

# 增加自定义元数据

memory_item["metadata"]["custom_flag"] = True

return memory_item

register_preprocessor(custom_preprocessor)

插件生命周期与隔离插件应支持生命周期管理(初始化、热更新、卸载),并建议按功能进行隔离开发,提升健壮性和可维护性。

5. 总结Mem0 通过统一的记忆层,使 AI 智能体能够跨会话、跨应用保持对用户偏好和历史交互的记忆。无论是作为托管服务还是自托管解决方案,Mem0 都为开发者提供了构建具备持久记忆能力的 AI 应用的强大工具。

随着 AI 应用的普及,像 Mem0 这样的记忆管理系统将成为构建真正个性化、上下文感知 AI 系统的关键组件。通过结合 LLM 的理解能力和向量存储的高效检索,Mem0 为下一代 AI 应用开辟了新的可能性。

资源获取官方文档:https://docs.mem0.aiGitHub 仓库:https://github.com/mem0ai/mem0研究论文:Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory