传统的 AI agents 使用短期上下文(也称为当前对话窗口),并且在聊天结束后经常忘记之前的会话。但如果我们能赋予 agents 长期记忆呢?构建具有用户偏好、事实和历史记忆的 agents,可以让我们创建更个性化和更强大的 agents。这可以通过将 LangGraph – 一个有状态的基于图的 agent 框架 – 与 Mem0(一个专为内存设计的层)结合来实现。使用 memories,LLM agent 可以“记住”过去的信息并加以利用。
将 LangGraph 与 Mem0 结合时,你会得到具有上下文感知能力的 agents。由于 Mem0 会存储和检索 memories,每次与 LangGraph 的新会话都可以将相关先前交互的摘要添加到 prompt 中。这允许构建 agents,随着时间推移与用户进行更长、更个性化、一致的对话。本文将介绍主要内存类型,逐步讲解 LangGraph+Mem0 工作流程,提供代码示例,比较不同的内存策略(RAG 与 memory),并讨论大规模应用时需要考虑的事项(vector DBs、隐私、成本)。
关键要点
- 持久内存提升 Agents: LangGraph agents 会在会话之间持久化内存,你可以使用它来自会话到会话定制交互。Agents 会记住你是谁,并随着时间了解你。
- 内存 vs 上下文窗口: 上下文窗口提供会话结束时过期的短期上下文内存。长期内存(Mem0)持久存储用户特定事实。RAG 通过检索外部知识来增强短期和长期内存。
- LangGraph 结构: LangGraph 的图结构使得添加内存节点变得简单。定义一个包含 mem0_user_id 的 State,并构建你的 chatbot 节点来执行 memories 的搜索/索引,然后在每轮添加该内存。
- Mem0 功能: Mem0 允许提取语义内存,并提供灵活的持久存储。它兼容任何 LLM,并允许你定义自己的内存功能,不像 OpenAI Memory 这样的封闭系统。
- 内存系统设计: 使用语义搜索检索事实,过滤或合并内存以避免重复,并平衡细节与摘要以提高效率。选择合适的 vector DB 和索引策略至关重要。
- 生产环境考虑: 规划隐私、保留策略和可扩展性。内存大大减少了 token 使用并提高了响应相关性,但增加了存储和计算层。
AI 内存:短期 vs 检索 vs 长期
AI agents 根据范围使用不同的 内存类型:
- 短期(会话)内存: 也称为窗口内存,指的是单个对话线程中的当前聊天历史。这种线程范围的状态由 LangGraph 自动处理。然而,会话结束后,该窗口关闭。如果你让 agent “列出我之前保存的文档”,它只能回忆同一聊天会话中你提供过的文档。当直接操作原始聊天历史(过去消息)时,你会受限于 LLM 上下文窗口,这会导致 prompt 膨胀和更高成本。
- 检索内存(RAG): 指从外部来源(如文档或数据库)检索信息的过程。Retrieval-Augmented Generation 管道利用 vector database 根据用户当前查询动态检索相关信息。你可以把 RAG 想象成 agent 每次“阅读”外部文档。
- 长期(持久)内存: 这是一种稳定的、用户特定的内存,会跨会话持久存在。长期内存允许你存储关于用户的提炼事实、偏好和经历,这些可以在后续对话中回忆。与仅引入通用信息的 RAG 不同,长期内存存储关于用户的个性化上下文。
简而言之,短期内存处理当前对话,RAG 用外部数据增强,长期内存(Mem0)提供用户特定上下文的连续性。
LangGraph 概述
LangGraph 是一个用于构建有状态图代理的框架。与线性链不同,LangGraph 允许您构建节点和边来表示代理的工作流程。节点处理小的功能块,例如调用 LLM、执行计算或从内存中检索数据,然后返回其更新后的状态。边根据当前状态有条件地执行,负责在节点之间路由流程。有一个中央 StateGraph 对象,在整个工作流程中维护代理的共享状态。LangGraph 的关键点:
- 状态管理: LangGraph 在 State 对象中维护对话状态,该状态流经节点。这包含所有消息历史记录以及您想与用户关联的任何元数据。您可以通过检查点持久化跨节点的状态,但默认情况下,它仅在单个会话中保留。
- 条件边: 边可以是有条件的,因此 LangGraph 不仅可以简单地链式连接节点,还可以分支甚至循环。例如,您可以根据用户意图路由到不同的工具。
- 可扩展性: 您想使用不同的 LLM 提供商吗?(OpenAI?Anthropic?Google?……)您可以做到!它专为生产环境设计。支持流式传输、错误处理等功能。
- 会话范围: 默认情况下,如果您构建一个 LangGraph 代理,它仅能访问当前会话的上下文。一旦聊天“结束”,状态将被清除,除非您将其外部存储。
Mem0 提供的内容
Mem0 是 AI 代理的持久内存解决方案。可以将其视为语义内存层:Mem0 从对话和您告知的用户事实中提取、存储和检索信息。Mem0 不是 LLM。它是一个专为“AI 内存”构建的数据库 + 搜索层。Mem0 的关键特性包括:
- 语义内存: Mem0 从每个原始聊天消息中仅提取事实知识,并将其存储为简短的内存短语。例如:“I love pizza” → 存储的内存 “Loves pizza”。这有助于保持整体内存大小较小。
- 多级内存: Mem0 有多个命名空间级别可供定义(用户级、会话级、代理级)。您可以隔离每个用户的内存,或共享全局代理事实。
- 智能检索: 给定一个查询(例如,用户最新消息),Mem0 将通过向量相似性搜索并返回最相关的存储内存。它默认按用户 ID 范围限定,因此您仅访问该用户存储的历史记录。
- 灵活存储: 将 mem0 连接到任何存储后端。使用 SQLite 进行本地测试,或连接到 Qdrant、Pinecone、Weaviate 等向量数据库。在云版本中,Mem0 为您管理此过程。
- 开源 + 云端: 有开源客户端库用于自托管,以及云平台( app.mem0.ai )用于轻松设置。
集成架构
将所有部分整合在一起,集成遵循清晰的流程:
- 消息接收 – 你的 agent 通过 LangGraph node(例如,chatbot)接收用户消息。
- 记忆搜索 – 该 node 调用 mem0.search(),提供最新的用户消息和他们的 userId。这会返回一个可能包含相关记忆的记忆列表,按向量相似度排名。
- 上下文构建 – 将记忆列表格式化为人类可读的上下文字符串,并将其添加到 system prompt 前。这使得 LLM 在制定响应时能够“了解”过去的消息。
- LLM 调用 – agent 将 system message 和对话历史输入 LLM(ChatOpenAI 或其他提供商)。响应包括当前用户输入以及提供的任何记忆。
- 记忆更新 – 一旦响应发送给用户,agent 就会异步调用 mem0.add() 来存储交互(用户消息和助手响应),以便后续检索。
LangGraph 在迭代间维护状态,而 Mem0 持久化长期存储。下面是一个代码草图示例:
def chatbot(state: State):
messages = state["messages"]
user_id = state["mem0_user_id"]
try:
# 1. 使用用户过滤器检索相关记忆
memories = mem0.search(
messages[-1].content,
filters={"user_id": user_id},
version="v2"
)
memory_list = memories.get('results', [])
# 2. 构建上下文字符串
context = "Relevant information from previous conversations:\n"
for memory in memory_list:
context += f"- {memory['memory']}\n"
# 3. 添加 system message
system_message = SystemMessage(content=f"""
You are a helpful assistant. Use the provided context to personalize your response.
{context}
""")
full_messages = [system_message] + messages
# 4. 生成响应
response = llm.invoke(full_messages)
# 5. 使用明确的 user_id 存储交互
interaction = [
{"role": "user", "content": messages[-1].content},
{"role": "assistant", "content": response.content}
]
mem0.add(interaction, filters={"user_id": user_id})
return {"messages": [response]}
except Exception as e:
# 无记忆时的后备方案
response = llm.invoke(messages)
return {"messages": [response]}
内存提取、过滤和总结策略
此图表以高层级展示了 AI 应用的概念性内存架构。通过三个控制机制构建可靠的持久内存:定义应该存储什么、指定内存随时间如何更新,以及过滤写入操作以保持准确性和实用性。
首先,定义什么算作内存。Mem0 的自定义事实提取提示框架鼓励您明确定义应该存储的确切事实。如果您希望将订单号、偏好、支持历史或任务约束写入持久内存,但不希望随意闲聊进入长期存储,这将非常有用。文档清楚解释了宽泛提示如何导致内存噪声。
其次,定义内存随时间如何变化。Mem0 还提供可配置的 custom_update_memory_prompt,指示 LLM 在需要将新事实与现有内存协调时,选择 ADD、UPDATE、DELETE 或 NONE 操作。如果没有这种级别的指令,当用户自我纠正、更改偏好或撤销先前指令时,系统将无限期地将过时事实层层叠加。
第三,控制摄取质量。无控制的写入可能会将推测存储为事实。例如,如果 AI 助手不经过滤就存储每条用户消息,临时问题、误解或不完整信息可能会成为永久内存条目。这可能导致未来交互中的错误假设。健康的生產实践是实时存储仅验证的事实和重要偏好,而异步处理不太关键的对话数据。
内存方法之间的权衡取舍
将长期内存集成到 agent 中会引入权衡取舍:
- 存储 vs 延迟 – 存储完整对话允许完美回忆,但代价是更高的存储需求和检索内存时的延迟。总结可以减少存储并加快检索,但牺牲精确性。
- 隐私 vs 个性化 – 内存解决方案必须保护用户隐私。Mem0 通过按 user ID 范围隔离内存,但您还应考虑应用数据保留策略,并允许用户通过 API 删除内存。
- 准确性 vs 成本 – 检索过多内存可能会迷惑 LLM,而检索过少可能会遗漏关键信息。您需要为您的用例调整 max_memories 和相关性阈值。
- 数据库选择 – 像 pgvector、Pinecone 或 Weaviate 这样的 vector database 在可扩展性和成本上有所不同。Mem0 在其参考实现中内置 pgvector,但如果您愿意,可以替换为其他后端或托管服务。
理解这些权衡取舍将帮助您设计一个平衡性能、成本和用户体验的内存系统。
Mem0–LangGraph 集成的逐步概述
这是一个将 Mem0 连接到 LangGraph 的快速入门指南。这是官方文档的总结,并附有一些优化提示。
1. 安装依赖项
安装所需的库:
pip install langgraph langchain-openai mem0ai python-dotenv
创建一个 .env 文件并添加你的 API 密钥:
OPENAI_API_KEY=sk-your-openai-key
MEM0_API_KEY=your-mem0-key
根据你的偏好设置 embedding provider、model 和 dimensions。
2. 初始化 LangGraph 和 Mem0
创建一个 State class,用于保存对话消息和用户 ID。初始化 StateGraph 并定义 chatbot 节点:
import os
from typing import Annotated, TypedDict, List
from dotenv import load_dotenv
from langgraph.graph import StateGraph, START
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from mem0 import MemoryClient
load_dotenv()
class State(TypedDict):
messages: Annotated[List[HumanMessage | AIMessage], add_messages]
mem0_user_id: str
llm = ChatOpenAI(model="gpt-4o")
mem0 = MemoryClient() # 本地/无服务器模式下无需 API 密钥
graph = StateGraph(State)
上述代码:
- 导入状态管理、消息、OpenAI 聊天和 Mem0 内存所需的包。
- 从 .env 文件加载环境变量。
- 初始化一个包含对话历史和 Mem0 用户 ID 的 State 对象。
- 初始化 GPT-4o 聊天模型和 Mem0 客户端。
- 创建一个 LangGraph 状态图,将用于构建代理工作流。
你将按照之前所示的方式定义 chatbot 函数,用于搜索记忆、构建上下文、生成响应并存储交互。
3. 构建对话图
添加 chatbot 节点和边:
graph.add_node("chatbot", chatbot)
graph.add_edge(START, "chatbot")
graph.add_edge("chatbot", "chatbot")
compiled_graph = graph.compile()
上述代码构建了一个基本的 LangGraph 工作流,将 chatbot 节点设置为起始执行点。它指定 chatbot 函数作为主要运行步骤,然后为每次对话轮次循环回到自身;最后 graph.compile() 将该图定义转换为可执行应用。
4. 创建对话运行器
编写一个 run_conversation 函数,从编译后的图中流式传输事件:
def run_conversation(user_input: str, mem0_user_id: str):
config = {"configurable": {"thread_id": mem0_user_id}}
state = {"messages": [HumanMessage(content=user_input)], "mem0_user_id": mem0_user_id}
for event in compiled_graph.stream(state, config, stream_mode="values"):
last_message = event["messages"][-1]
if isinstance(last_message, AIMessage):
return last_message.content
# 主要交互循环
def main():
user_id = input("Enter your user ID: ")
print("Chatbot ready! Type 'quit' to exit.")
while True:
user_input = input("\nYou: ")
if user_input.lower() == 'quit':
break
response = run_conversation(user_input, user_id)
print(f"Bot: {response}")
该代码执行 chatbot,传递用户消息,组装根对话状态,并通过编译后的 LangGraph 工作流流式传输以接收 AI 的响应。main() 函数创建一个基本的命令行聊天循环,提示用户输入并显示 bot 的响应,直到用户输入退出。
5. 部署和监控
在你偏好的环境中部署代理。将记忆存储在向量数据库中(pgvector、Pinecone、Weaviate 等)。跟踪记忆增长。调整清理频率。调整检索设置以平衡个性化、相关性和系统性能。
生产环境注意事项
在生产环境中运行 LangGraph+Mem0 agent 时,您可能需要考虑以下几点:
| 主题 | 主要思路 | 实用说明 |
|---|---|---|
| Vector Database | Mem0 默认使用 SQLite 进行快速测试,但生产系统通常需要 vector database。 | 确保数据库在 user_id 上有索引。托管选项如 Mem0 Cloud 可以处理此问题,自托管也是一种选择。数据库选择(如 Qdrant 或 Pinecone)会影响成本、速度和可用功能。 |
| Data Privacy & Retention | 内存系统会存储用户数据,因此隐私和保留必须小心处理。 | 必要时加密敏感字段,在定义期限后删除记忆,并在存储个人数据前获得用户同意。Mem0 APIs 可以帮助删除或导出数据。VPC 可以提升 vector store 的保护。 |
| Cost & Performance | 添加内存可以降低 LLM token 使用量,因为 prompt 保持较小,但会引入数据库查询。 | 语义搜索通常非常快,并且可以批量处理。Mem0 报告称 token 节省约 90%,p95 延迟比全上下文方法低 91%。请基准测试您自己的 LLM 配置以确认延迟。 |
| Reliability | 内存数据库和 LangGraph state 应设计为容错。 | 使用 LangGraph checkpoints 从崩溃中恢复,并为内存存储维护备份。随着 vector database 增长,监控使用情况并规划扩展。 |
| Security | Mem0 API key 和数据库必须受到保护。 | 限制写访问权限,使只有 agent 才能修改内存。在多 agent 或多租户系统中,隔离 namespaces 以提升安全性和分离性。 |
常见问题解答
- AI agent 中的长期记忆是什么? 长期记忆是 agent 存储从交互中提取的重要事实的地方。虽然短期记忆限于上下文窗口(通常在几条消息后重置),但长期记忆可以跨会话持久化。
- Mem0 与 RAG 有何不同? Retrieval-Augmented Generation 使用外部文档来增强 LLM 中的知识。Mem0 只存储您的对话历史。它从与用户的对话中提取事实,允许 agent 存储关于您的信息并提供个性化响应。使用 RAG,您可能询问“法国的首都是什么?”使用 Mem0,agent 可以记住您上个月订购了一台笔记本电脑。
- LangGraph agent 可以记住过去的对话吗? 可以。使用 LangGraph 结合 Mem0 的 agent 可以记住过去的对话。在每次对话轮次中,LLM 响应后存储新的片段,然后在后续轮次中检索。中介件和搜索函数将适用的记忆推入 system prompt。
- Mem0 需要 vector database 吗? Mem0 需要 vector store 来对 embeddings 进行相似性搜索。虽然参考实现使用 pgvector,但您可以配置托管服务。对于大多数小型项目,pgvector 很可能工作良好,但对于大型部署,您可能更喜欢 Pinecone 或 Weaviate。
- agent 中长期记忆的常见用例是什么? 长期记忆的用例包括个人助手、客户支持 agent、辅导系统和内部帮助台。只要 agent 反复与同一用户交互,就可以用于定制回复、避免重复并与用户建立联系。长期记忆还支持对用户行为和偏好的分析。
结论
将 LangGraph 与 Mem0 结合是实现从基于会话的代理向具有持久、长期记忆且针对单个用户的代理过渡的一种潜在路径。LangGraph 提供结构化的编排和短期对话状态管理,而 Mem0 则启用持久的语义记忆,这些记忆可以在会话间检索,以提高连续性、个性化和相关性。通过精心设计(例如,选择性提取和保留、隐私控制、检索设置等),这种组合方法使开发者能够创建更强大的代理,同时在规模化时保持高效,而无需依赖膨胀的聊天历史或通用的文档检索。
除了本地示例外,生产就绪的记忆架构还需要部署基础设施。Langchain 的 Gradient 集成允许将 LangChain 驱动的工作流连接到 Gradient AI 平台。这为开发者提供了使用 GPU 加速的无服务器推理访问各种模型的途径,并为将 AI 应用扩展到原型阶段之外提供了路径。
参考资料
- LangGraph
- LangGraph 概述
- Graph API 概述
- 自定义事实提取提示
- Mem0:使用可扩展长期记忆构建生产就绪的 AI 代理