给 AI 装上长期记忆:Zep Cloud 初探与上手教程

在构建智能对话系统时,记忆 是一个至关重要的能力。一个 AI 助手如果每次都从零开始对话,而无法记住用户的历史偏好、兴趣和上下文,就很难被认为是「智能」的。
Zep 正是为了解决这一问题的工具,它提供了长期记忆(long-term memory) 的能力,让 AI 可以像人类一样,在多轮交互中逐渐形成对用户的理解。

这篇文章会结合一些示例代码,带大家对 Zep 的长期记忆 有一个初步的认识。

1. 环境准备

使用 Zep 之前,需要先获取 API Key,Zep - AI Memory for Applications

并通过环境变量配置:

from dotenv import load_dotenv import os # 加载 .env 文件 load_dotenv(override=True) # 获取 ZEP API Key ZEP_API_KEY = os.getenv("ZEP_API_KEY") 

安装依赖:

pip install python-dotenv zep-cloud 

然后通过 Zep 客户端与 Zep 服务交互:

from zep_cloud.client import Zep client = Zep(api_key=ZEP_API_KEY) 

2. 用户的管理

在长期记忆中,用户(User) 是最核心的对象。Zep 提供了用户的增删改查功能,比如:

  • 添加用户:
def add_user(user_id, email, first_name, last_name): """添加一个新用户""" user = client.user.add( user_id=user_id, email=email, first_name=first_name, last_name=last_name, ) print(f"✅ 用户 {user_id} 已创建:", user) return user
  • 获取用户信息:
def get_user(user_id): """获取用户信息""" user = client.user.get(user_id) print("ℹ️ 用户信息:", user) return user 

通过这些接口,Zep 可以为每个用户维护独立的记忆空间,避免不同用户之间的干扰。

3. 会话与线程(Thread)

Thread 可以理解为某个用户与 AI 的对话会话,它是记忆的载体。
我们可以为用户创建一个新的对话线程:

import uuid def create_thread(user_id): """为用户创建新的对话线程""" thread_id = uuid.uuid4().hex client.thread.create(thread_id=thread_id, user_id=user_id) print("🆕 新建线程:", thread_id) return thread_id

在这个会话中,用户和 AI 的消息都会被存储,逐渐形成长期记忆。

4. 向 Zep 添加记忆

当用户和 AI 进行对话时,我们可以把消息存储到 Zep 中。例如:

def add_memory(user_id, bot_id, thread_id, user_message, bot_message): """将用户和 AI 的对话存入记忆""" messages = [ Message(name=user_id, role="user", content=user_message), Message(name=bot_id, role="assistant", content=bot_message), ] client.thread.add_messages(thread_id, messages=messages) print(f"💾 已存入记忆: {user_message} -> {bot_message}")

比如,用户说「我想学习 Python」,AI 回复「好的,我来教你一些基础代码」,这段信息就会被 Zep 存储起来。

5. 从 Zep 中检索记忆

Zep 的强大之处在于,它不只是单纯的对话存档,而是提供了结构化的长期记忆检索能力

例如,我们可以通过以下方式获取某个对话线程的上下文摘要:

def get_user_context(thread_id, mode="summary"): """获取用户上下文(支持 summary/basic 两种模式)""" memory = client.thread.get_user_context(thread_id=thread_id, mode=mode) print(f"📌 用户上下文({mode}):\n", memory.context) return memory.context

Zep 会自动对历史对话进行摘要,提取用户的偏好和事实,从而在后续对话中帮助 AI 更好地理解用户。

同时,Zep 还支持基于 知识图谱(graph) 的检索,可以通过 search_in_graphget_relevant_fact 找到和用户相关的事实和关系。这使得 AI 不仅能记住对话,还能推理出用户的兴趣、习惯和事实网络

6. 一个简单的完整的例子

import os import uuid from dotenv import load_dotenv from zep_cloud.client import Zep from zep_cloud import Message # ====================== # 1. 初始化 Zep 客户端 # ====================== load_dotenv(override=True) ZEP_API_KEY = os.getenv("ZEP_API_KEY") client = Zep(api_key=ZEP_API_KEY) # ====================== # 2. 用户管理 # ====================== def add_user(user_id, email, first_name, last_name): """添加一个新用户""" user = client.user.add( user_id=user_id, email=email, first_name=first_name, last_name=last_name, ) print(f"✅ 用户 {user_id} 已创建:", user) return user def get_user(user_id): """获取用户信息""" user = client.user.get(user_id) print("ℹ️ 用户信息:", user) return user # ====================== # 3. 会话管理(Thread) # ====================== def create_thread(user_id): """为用户创建新的对话线程""" thread_id = uuid.uuid4().hex client.thread.create(thread_id=thread_id, user_id=user_id) print("🆕 新建线程:", thread_id) return thread_id # ====================== # 4. 添加记忆 # ====================== def add_memory(user_id, bot_id, thread_id, user_message, bot_message): """将用户和 AI 的对话存入记忆""" messages = [ Message(name=user_id, role="user", content=user_message), Message(name=bot_id, role="assistant", content=bot_message), ] client.thread.add_messages(thread_id, messages=messages) print(f"💾 已存入记忆: {user_message} -> {bot_message}") # ====================== # 5. 获取长期记忆摘要 # ====================== def get_user_context(thread_id, mode="summary"): """获取用户上下文(支持 summary/basic 两种模式)""" memory = client.thread.get_user_context(thread_id=thread_id, mode=mode) print(f"📌 用户上下文({mode}):\n", memory.context) return memory.context # ====================== # 6. 演示流程 # ====================== if __name__ == "__main__": # 定义两个用户:human user 和 bot user_id = "harry_user" bot_id = "ai_bot" # 创建用户 add_user(user_id, "[email protected]", "Harry", "Liu") add_user(bot_id, "[email protected]", "AI", "Assistant") get_user(user_id) get_user(bot_id) # 创建对话线程(以 human user 为主) thread_id = create_thread(user_id) # 模拟一次对话 user_msg = "Hi, my name is Harry. I love watching movies and learning Python." bot_msg = "Nice to meet you Harry! 🎬🐍 Movies and Python are both great choices!" add_memory(user_id, bot_id, thread_id, user_msg, bot_msg) # 再来一次对话 user_msg2 = "I want to learn Python basics, please teach me." bot_msg2 = "Sure! Let's start with printing text:\n```python\nprint('Hello, Harry!')\n```" add_memory(user_id, bot_id, thread_id, user_msg2, bot_msg2) # 获取用户记忆摘要 get_user_context(thread_id, "summary") get_user_context(thread_id, "basic") 

执行结果

✅ 用户 harry_user 已创建: created_at='2025-08-23T03:25:14.843616Z' deleted_at=None email='[email protected]' fact_rating_instruction=None first_name='Harry' id=35 last_name='Liu' metadata=None project_uuid='ff41087d-e0f6-496d-8cea-e2e05be96d20' session_count=None updated_at='2025-08-23T03:25:14.843616Z' user_id='harry_user' uuid_='19a1bc52-102c-4610-8941-63bda6979204' ✅ 用户 ai_bot 已创建: created_at='2025-08-23T03:25:15.208405Z' deleted_at=None email='[email protected]' fact_rating_instruction=None first_name='AI' id=36 last_name='Assistant' metadata=None project_uuid='ff41087d-e0f6-496d-8cea-e2e05be96d20' session_count=None updated_at='2025-08-23T03:25:15.208405Z' user_id='ai_bot' uuid_='9d915a28-0b54-4b09-b6f6-eebd1c5fc3d7' ℹ️ 用户信息: created_at='2025-08-23T03:25:14.843616Z' deleted_at=None email='[email protected]' fact_rating_instruction=None first_name='Harry' id=35 last_name='Liu' metadata=None project_uuid='ff41087d-e0f6-496d-8cea-e2e05be96d20' session_count=None updated_at='2025-08-23T03:25:14.843616Z' user_id='harry_user' uuid_='19a1bc52-102c-4610-8941-63bda6979204' ℹ️ 用户信息: created_at='2025-08-23T03:25:15.208405Z' deleted_at=None email='[email protected]' fact_rating_instruction=None first_name='AI' id=36 last_name='Assistant' metadata=None project_uuid='ff41087d-e0f6-496d-8cea-e2e05be96d20' session_count=None updated_at='2025-08-23T03:25:15.208405Z' user_id='ai_bot' uuid_='9d915a28-0b54-4b09-b6f6-eebd1c5fc3d7' 🆕 新建线程: b4cfdfa942f34c768e2b4348c31d32d9 💾 已存入记忆: Hi, my name is Harry. I love watching movies and learning Python. -> Nice to meet you Harry! 🎬🐍 Movies and Python are both great choices! 💾 已存入记忆: I want to learn Python basics, please teach me. -> Sure! Let's start with printing text: ```python print('Hello, Harry!') ``` 📌 用户上下文(summary): • Harry Liu introduced himself as someone who loves watching movies and learning Python (2024-12-19 - 2024-12-19) • Harry Liu requested to learn Python basics (2024-12-19 - 2024-12-19) • AI bot provided first Python instruction: print('Hello, Harry!') (2024-12-19 - 2024-12-19) • Harry Liu's user profile includes email [email protected] and user_id harry_user (2024-12-19 - 2024-12-19) 📌 用户上下文(basic): FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) <FACTS> - ai_bot is teaching Harry Python basics. (2025-08-23 03:25:17 - present) - Harry wants to learn Python basics. (2025-08-23 03:25:17 - present) - Harry Liu loves learning Python (2025-08-23 03:25:17 - present) - ai_bot thinks Python are great choices (2025-08-23 03:25:17 - present) - Harry Liu loves watching movies (2025-08-23 03:25:17 - present) </FACTS> # These are the most relevant entities # Name: ENTITY_NAME # Label: entity_label (if present) # Attributes: (if present) # attr_name: attr_value # Summary: entity summary <ENTITIES> - Name: Python basics Label: Topic Attributes: domain: Python expertise_level: basics Summary: Harry wants to learn Python basics. </ENTITIES>

7. 知识图谱搜索(Graph Search)

在前面的例子里,我们通过 user_context 可以快速拿到用户的摘要信息。但在更复杂的 RAG 问答 场景下,仅靠摘要可能不够精确。这时候,Zep 提供的 知识图谱搜索(Graph Search)就派上用场了。

为什么需要知识图谱?

  • 精确检索用户事实:比如用户喜欢的编程语言、职业、同事关系等。
  • 关系推理:例如“Harry 和谁是同事?”、“他在哪家公司工作?”。
  • 复杂问题处理:多个实体、多关系组合的问题。

图搜索代码示例

def search_in_graph(user_id, query_text, center_node_uuid=None): """ 在 Zep 知识图谱中搜索与 query_text 相关的节点或事实 """ client = Zep(api_key=ZEP_API_KEY) if center_node_uuid: results = client.graph.search( user_id=user_id, query=query_text, reranker="node_distance", center_node_uuid=center_node_uuid # 可选,指定搜索中心 ) else: results = client.graph.search( user_id=user_id, query=query_text ) relevant_nodes = results.nodes relevant_edges = results.edges print("=== 节点 ===") if relevant_nodes: for node in relevant_nodes: print(node) print("=== 相关事实 ===") if relevant_edges: for edge in relevant_edges: print(edge.fact) if __name__ == "__main__": search_in_graph(user_id, "what does harry like?")

执行结果

=== 节点 === === 相关事实 === Harry Liu loves watching movies Harry Liu loves learning Python Harry wants to learn Python basics. ai_bot is teaching Harry Python basics. Harry Liu wants to learn Python basics. ai_bot thinks movies are great choices ai_bot thinks Python are great choices

随机问题时怎么办?

在实际 RAG 场景里,用户的问题往往是随机的,我们并不能提前知道要以哪个节点作为中心。这里有两种策略:

1. 全局搜索(不指定中心节点)

search_in_graph(user_id, query_text) 

Zep 会在整个知识图谱里检索与问题相关的节点和事实。
适合范围比较宽泛、问题不确定的场景。

2. 自动推断中心节点

我们可以先对用户问题做 关键词/实体抽取,再去匹配知识图谱节点。如果找到对应节点,就用它作为搜索中心;找不到,则 fallback 到全局搜索。

示例代码:

def auto_graph_search(user_id, query_text): client = Zep(api_key=ZEP_API_KEY) # 先尝试列出用户所有节点 nodes = client.graph.node.get_by_user_id(user_id=user_id) # 简单关键词匹配(可以换成更智能的 NER 模型) center_node_uuid = None for node in nodes: if node.label.lower() in query_text.lower(): center_node_uuid = node.uuid break # 如果找到中心节点,就指定搜索,否则全局搜索 return search_in_graph(user_id, query_text, center_node_uuid) 

3. 搜索图的范围有三种 (edges, nodes , episodes)

query = "What projects is Jane working on?" # Search for edges in a graph edge_results = client.graph.search( graph_id=graph_id, query=query, scope="edges", # Default is "edges" limit=5 ) # Search for nodes in a graph node_results = client.graph.search( graph_id=graph_id, query=query, scope="nodes", limit=5 ) # Search for episodes in a graph episode_results = client.graph.search( graph_id=graph_id, query=query, scope="episodes", limit=5 ) # search for perferences search_results = client.graph.search( user_id=user_id, query="the user's music preferences", scope="nodes", search_filters={ "node_labels": ["Preference"] } ) for i, node in enumerate(search_results.nodes): preference = node.attributes print(f"Preference {i+1}:{preference}")

8. 初步认识与思考

从上面的例子可以看到,Zep 提供了以下几个层次的记忆能力:

  1. 对话存储:保留用户与 AI 的消息。
  2. 上下文总结:自动生成用户画像和对话摘要。
  3. 图谱搜索:以结构化的方式组织知识,方便 AI 检索和推理。

这让 AI 不仅能「记住你说过的话」,还可以「理解你是谁」、「你关心什么」、「你曾经提过的事实」——这就是长期记忆的价值。

总结

传统的聊天机器人往往是「短期记忆」:只记住本轮对话内容。而 Zep 则进一步赋予 AI 「长期记忆」:它能管理用户信息、保存对话线程、抽取知识图谱,并支持高效的检索和推理。

对于想要打造真正个性化 AI 助手的开发者来说,Zep 提供了一套非常实用的工具。未来我们还可以基于这些记忆能力,构建更加智能、持久且个性化的 AI 应用。

参考资料

https://github.com/getzep/zep

https://github.com/getzep/graphiti

Context Engineering Platform for AI Agents - Zep

其它

Zep 知识图谱结构

Zep 的知识图谱是围绕 用户个性化事实 自动构建的。
当用户和 bot 的对话中出现了新的事实(比如职业、爱好、关系等),Zep 会把这些事实提取出来,构造成 节点(Node)边(Edge),存放到图数据库里。

1. 节点(Node)

节点通常表示 实体,比如:

  • 人物:Harry小明AI bot
  • 组织:百度OpenAI
  • 事物:Python篮球纽约
  • 概念:爱好职业

每个节点包含信息:

  • uuid:节点唯一 ID
  • labels:标签名称,比如 "User", "Entity"
  • summary:关于这个实体的总结描述(可能是从多条对话中生成的)
2. 边(Edge)

边表示 事实或关系,连接两个节点。

  • uuid:节点唯一 ID
  • fact:这条边表达的事实,例如:
    • "Harry 在百度工作"
    • "Harry 的同事是小明"
    • "Harry 喜欢 Python"

边不仅仅是“连接”,它们包含了 关系语义,是知识图谱的核心价值。

3. 图的构建方式

Zep 会自动从对话中抽取事实,比如:

用户说:

我在百度工作,我的同事是小明。我喜欢 Python。 

知识图谱中会自动生成:

  • 节点:
    • Harry
    • 百度
    • 小明
    • Python
  • 边:
    • (Harry) —— [职业] ——> (百度)
    • (Harry) —— [同事] ——> (小明)
    • (Harry) —— [爱好] ——> (Python)
4. 知识图谱与 user_context 的区别
  • user_context:是 Zep 给出的一个 文本总结/提取块,方便直接放进 prompt,让 LLM 拿到用户背景。
    • 比如 Harry 是 25 岁的程序员,在百度工作,喜欢 Python 和篮球
  • knowledge graph:是一个结构化的 实体-关系图,方便做事实检索和推理。
    • 比如能回答:
      • Harry 的同事是谁?
      • Harry 的爱好和职业之间有没有联系?
      • 和 Harry 相关的所有实体节点有哪些?

小结:

  • 节点(Node) 存放用户相关的实体。
  • 边(Edge) 存放事实和关系,带有自然语言描述。
  • 知识图谱 适合做结构化检索和推理(特别是关系类问题)。
  • user_context 更适合当作 RAG 的输入上下文,直接提供背景信息给 LLM。

Read more

前端安全:别让你的应用变成黑客的游乐场

前端安全:别让你的应用变成黑客的游乐场 毒舌时刻 这代码写得跟网红滤镜似的——仅供参考。 各位前端同行,咱们今天聊聊前端安全。别告诉我你还在写明文存储密码,那感觉就像把家门钥匙挂在门口——方便,但不安全。 为什么你需要前端安全 最近看到一个项目,登录表单直接把密码发送到服务器,没有任何加密。我就想问:你是在做应用还是在给黑客送大礼? 反面教材 // 反面教材:不安全的登录 // components/LoginForm.jsx export default function LoginForm() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); // 直接发送明文密码 const response = await

五种常用的web加密算法

五种常用的web加密算法

文章目录 * 五种常用Web加密算法实战及原理详解 * 1. AES (高级加密标准) * 原理详解 * 应用场景 * 实战代码(Node.js) * 2. RSA (非对称加密) * 原理详解 * 应用场景 * 实战代码(Node.js) * 3. SHA-256 (安全哈希算法) * 原理详解 * 应用场景 * 实战代码(浏览器环境) * 4. HMAC (基于哈希的消息认证码) * 原理详解 * 应用场景 * 实战代码(Node.js) * 5. PBKDF2 (基于密码的密钥派生函数) * 原理详解 * 应用场景 * 实战代码(Node.js) * 加密算法对比表 * 安全最佳实践 * 进阶主题 五种常用Web加密算法实战及原理详解 在现代Web开发中,数据安全至关重要。以下是五种最常用的Web加密算法,包括它们的原理、应用场景和实战代码示例。

开源视觉模型部署教程:GLM-4.6V-Flash-WEB一键启动实践

开源视觉模型部署教程:GLM-4.6V-Flash-WEB一键启动实践 想快速体验一个能看懂图片、还能跟你聊天的AI助手吗?智谱最新开源的GLM-4.6V-Flash-WEB模型,就是一个功能强大且部署简单的选择。它不仅能通过网页界面直接对话,还提供了API接口,方便开发者集成到自己的应用里。 今天,我就带你从零开始,手把手完成这个视觉大模型的部署和启动。整个过程非常简单,只需要三步,哪怕你是刚接触AI的新手,也能在10分钟内搞定。我们主要的目标就是:快速部署,立即体验。 1. 环境准备与镜像部署 万事开头难,但这次开头很简单。部署GLM-4.6V-Flash-WEB,你只需要一个能运行Docker的环境。这里我们以常见的云服务器或本地支持Docker的Linux环境为例。 1.1 获取部署镜像 首先,你需要找到模型的部署镜像。根据提供的资料,我们可以从相关的镜像仓库获取。这里假设你已经有一个可用的环境,并且安装了Docker。 打开你的终端,执行以下命令来拉取镜像。这个镜像已经包含了运行模型所需的所有依赖,省去了你手动安装Python、PyTorch等一堆库的麻烦。

SenseVoice-Small语音识别模型Gradio前端定制化开发:UI修改与API扩展教程

SenseVoice-Small语音识别模型Gradio前端定制化开发:UI修改与API扩展教程 1. 环境准备与快速部署 在开始定制化开发之前,我们需要先准备好基础环境。SenseVoice-Small语音识别模型基于ONNX格式并带有量化处理,这使得模型在保持高精度的同时具有更快的推理速度。 首先确保你的系统满足以下要求: * Python 3.8或更高版本 * 至少4GB可用内存 * 支持ONNX Runtime的硬件环境 安装必要的依赖包: pip install modelscope gradio onnxruntime numpy librosa soundfile 如果你需要录音功能,还需要安装额外的音频处理库: pip install pydub webrtcvad 完成环境配置后,我们可以开始模型的加载和测试。ModelScope提供了便捷的模型管理方式,让我们能够快速获取和部署预训练模型。 2. 基础模型加载与测试 2.1 使用ModelScope加载模型 ModelScope简化了模型的加载过程,下面是基本的模型加载代码: