打造带长期记忆的 AI Agent:Zep 记忆后端 + AutoGen 编排 + Ollama/Qwen 3 本地模型实战(Zep Memory Assistant)
2026/9/10 20:41:45 网站建设 项目流程

打造带长期记忆的 AI Agent:Zep 记忆后端 + AutoGen 编排 + Ollama/Qwen 3 本地模型实战(Zep Memory Assistant)

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

本文围绕仓库中 zep-memory-assistant 项目展开,讲解如何用 Zep 云记忆后端为 Microsoft AutoGen 对话智能体注入跨会话的长期记忆,让 Agent 记住用户偏好、过往话题与关键实体,并以 Streamlit 封装为可直接交互的聊天界面。读完本文,你将掌握"消息双写持久化 + 事实评分检索 + 系统提示词动态注入"的完整记忆增强链路,以及一套开箱即用的本地运行方案(Ollama + Qwen 3 4B,无需 GPU 也能演示)。

一、项目概览:为什么 Agent 需要"记忆层"

普通 LLM 对话是无状态的——每次请求都是一次全新推理,模型既不记得五分钟前聊过什么,也不知道用户的长期偏好。zep-memory-assistant的目标正是补齐这一缺口:构建一个"具有类人记忆"的 AI Agent,用 Zep 作为长期记忆后端,AutoGen 负责多 Agent 编排,让对话智能体能够跨会话保留、回忆并利用上下文记忆。

项目技术栈分层清晰,在 zep-memory-assistant/README.md 中给出了明确声明:

层级组件职责
记忆层Zep(zep-cloud SDK)长期记忆后端:消息持久化、事实抽取与评分、上下文检索
编排层AutoGen(ag2)Agent 生命周期管理与对话轮次控制
模型层Ollama + Qwen 3 4B本地 LLM 推理,无需外部模型 API
交互层Streamlit将后端逻辑包装为可视化聊天 UI

从依赖声明(pyproject.toml)可以看到,实际安装的包为ag2[ollama]>=0.9(AutoGen 的延续版本,随附 Ollama 适配器)、ollama>=0.4.8streamlit>=1.44.1zep-cloud>=2.11.0,且要求 Python>=3.12

二、架构设计:记忆如何在对话中流转

从源码结构看(agent.py 与 app.py),一条消息的完整记忆链路可以拆解为三个环节:

  1. 用户消息先落库、后推理:用户输入到达后,先调用_zep_persist_user_message()将消息以role_type="user"写入 Zep 会话,随后才触发模型推理——保证 Agent 在下一次回复前,Zep 已完成对该消息的事实抽取与记忆入库。
  2. 事实检索驱动上下文注入:推理前调用_zep_fetch_and_update_system_message(),从 Zep 拉取当前会话中评分高于阈值的"事实"(facts),拼接进系统提示词,形成"记忆上下文"。
  3. 助手消息回流记忆库:Agent 生成回复后,通过 AutoGen 的process_message_before_send钩子把助手消息也写入 Zep,形成完整对话闭环。

也就是说,记忆不是"事后补录",而是与对话推理流程深度咬合:写入发生在推理前、读取发生在推理时、回写发生在推理后。这也是本项目区别于"把历史消息整体塞进 prompt"式伪记忆的关键——Zep 会做事实抽取与相关性评分,只把高价值事实注入上下文。

三、环境搭建与快速启动

以下命令按 zep-memory-assistant/README.md 的说明在项目根目录执行。

3.1 安装 Ollama 并拉取 Qwen 3 模型

# 在 Linux 上安装 Ollama(官方安装脚本) curl -fsSL https://ollama.com/install.sh | sh # 拉取 Qwen 3 4B 模型 ollama pull qwen3:4b

拉取完成后,Ollama 默认监听127.0.0.1:11434,这与 llm_config.py 中的client_host完全对应。若需在非 Linux 环境(macOS/Windows)运行,可改为从 Ollama 官网下载对应平台的桌面安装包。

3.2 安装依赖

项目使用 uv 管理依赖与虚拟环境:

uv sync

该命令会依据 pyproject.toml 与uv.lock创建虚拟环境并安装全部依赖。如果没有安装 uv,可先通过pip install uv或 uv 官方安装脚本补齐。

3.3 启动应用

streamlit run app.py

启动后浏览器会自动打开 Streamlit 界面。首次使用需要在侧边栏输入 Zep API Key(在 Zep 平台注册获取),随后填写 First Name / Last Name 并点击Initialize Session,即可开始与"ZEP AGENT"对话。

3.4 获取 Zep API Key

Zep 记忆后端需要云服务 API Key(本项目使用zep-cloud云 SDK,而非本地自托管版本)。API Key 在 Zep 平台的控制台申请,app.py 中initialize_zep_client()负责用它实例化Zep(api_key=api_key)客户端,初始化失败会在界面以st.error提示。

四、核心源码剖析:ZepConversableAgent

整个项目的灵魂是 agent.py 中自定义的ZepConversableAgent——一个"自带长期记忆"的 AutoGen 会话 Agent。

4.1 继承与构造

class ZepConversableAgent(ConversableAgent): # Agent with Zep memory def __init__(self, name, system_message, llm_config, function_map, human_input_mode, zep_session_id, zep_client, min_fact_rating): super().__init__(name=name, system_message=system_message, llm_config=llm_config, human_input_mode=human_input_mode, function_map=function_map) self.zep_session_id = zep_session_id self.zep_client = zep_client self.min_fact_rating = min_fact_rating self.original_system_message = system_message self.register_hook("process_message_before_send", self._zep_persist_assistant_messages)

关键设计(对应 agent.py):

  • 在构造参数中额外接收zep_session_idzep_clientmin_fact_rating三个记忆相关参数,把记忆能力内聚进 Agent 自身;
  • original_system_message保存原始系统提示词,因为后续会用检索到的事实动态覆盖系统消息;
  • 通过 AutoGen 的register_hook("process_message_before_send", ...)注册钩子,实现"助手消息自动落库"。

4.2 钩子函数:助手消息自动持久化

def _zep_persist_assistant_messages(self, message, sender, recipient, silent): """Agent sends a message to the user. Add the message to Zep.""" if sender == self: content = message.get("content", "") if isinstance(message, dict) else str(message) if content: zep_message = Message(role_type="assistant", role=self.name, content=content) self.zep_client.memory.add(session_id=self.zep_session_id, messages=[zep_message]) return message

对应 agent.py。要点:

  • Message(role_type="assistant", role=self.name, ...)中,role_type表示消息在记忆库中的角色(user/assistant),role则是发送者名字(此处为 Agent 名ZEP AGENT);
  • 通过memory.add追加写入指定session_id的会话,消息结构遵循 Zep 云 SDK 的消息规范;
  • 钩子必须原样return message,否则会破坏 AutoGen 消息管线。

4.3 用户消息持久化

def _zep_persist_user_message(self, user_content: str, user_name: str = "User"): if user_content: zep_message = Message(role_type="user", role=user_name, content=user_content) self.zep_client.memory.add(session_id=self.zep_session_id, messages=[zep_message])

对应 agent.py。该方法是在钩子之外由 Streamlit 层主动调用的(见 app.py),因为"用户消息必须先于推理落库,才能在推理前取回相关事实"——这个时序约束无法通过发送后钩子满足,源码注释也明确指出了这一点。

4.4 事实检索与系统消息动态更新

def _zep_fetch_and_update_system_message(self): """Fetch facts and update system message.""" memory: Memory = self.zep_client.memory.get( self.zep_session_id, min_rating=self.min_fact_rating ) context = memory.context or "No specific facts recalled." self.update_system_message( self.original_system_message + f"\n\nRelevant facts about the user and prior conversation:\n{context}" )

对应 agent.py。这是"记忆生效"的关键一步:

  • memory.get(session_id, min_rating=...)从 Zep 拉取该会话的记忆对象,min_rating是事实相关性评分下限(本项目设置为0.7);
  • memory.context是 Zep 根据评分与时效聚合出的上下文文本(事实 + 实体,以第三人称表述);
  • 通过 AutoGen 的update_system_message()把检索结果追加到原始系统提示词之后,本次推理的上下文因此携带了历史记忆
  • 兜底逻辑:无事实时注入"No specific facts recalled.",保证提示词结构稳定。

4.5 min_fact_rating 阈值的作用

在 app.py 创建 Agent 时传入min_fact_rating=0.7。该值直接控制"记忆的准入标准":Zep 会对每条事实给出 0~1 的评分,低于阈值的低价值事实(如闲聊中的天气等偶然细节)不会被注入上下文。调高阈值 → 上下文更精简、更聚焦高价值信息;调低阈值 → 上下文更丰富但可能引入噪声。具体取值需要结合业务对"回忆粒度"与"上下文长度"的权衡来定。

五、Streamlit 交互层解析

app.py 把上述 Agent 封装为完整可用的聊天应用,核心流程如下。

5.1 客户端与用户、会话初始化

侧边栏输入 API Key 后调用initialize_zep_client()创建全局 Zep 客户端;填写姓名并点击初始化后,进入 app.py 的initialize_session()

  1. 由姓名生成稳定用户 ID:generate_user_id()(见 util.py)将姓名小写并剔除所有非字母数字字符,例如 "John Smith" →johnsmith;若结果为空则回退为default_user。这种确定性 ID 保证了同一用户再次启动应用时能关联到已有记忆;
  2. 为本次运行生成 UUID 会话 ID(str(uuid.uuid4())),并在 Streamlitsession_state中保存;
  3. 尝试zep.user.get()查询用户是否存在:不存在则调用zep.user.add()创建新用户;无论新旧,都会调用zep.memory.add_session()为该用户绑定一个记忆会话;
  4. 创建用户时附带事实评级指令(见下节)。

5.2 事实评级指令:教会 Zep"什么值得记"

创建用户时,app.py 定义并下发了评级指令与示例:

fact_rating_instruction = """Rate facts by relevance and utility. Highly relevant facts directly impact the user's current needs or represent core preferences that affect multiple interactions. Low relevance facts are incidental details that rarely influence future conversations or decisions.""" fact_rating_examples = FactRatingExamples( high="The user is developing a Python application using the Streamlit framework.", medium="The user prefers dark mode interfaces when available.", low="The user mentioned it was raining yesterday.", )

这是 Zep 记忆质量的关键调优点:评级指令告诉 Zep 的抽取器"什么算高价值事实",示例则给出了高/中/低三档的具体锚点(如"用户偏好暗色模式"这类跨多次交互生效的偏好应获高分,"昨天下了雨"这类偶然细节应获低分)。业务方完全可以替换为自己领域内的分级标准,从而影响min_rating=0.7筛选出的记忆内容。

5.3 对话处理流程

handle_conversations()(app.py)承载一次完整问答:

  1. 追加 /no_think 标记prompt_with_token = f"{prompt} /no_think",这是 Qwen 3 的思考模式控制 token,用于在推理时关闭思维链输出;
  2. 身份处理:优先用用户全名(转大写)作为消息的role写入 Zep,否则回退为用户 ID,让记忆库中的实体指代更自然;
  3. 先写后读:依次执行_zep_persist_user_message()_zep_fetch_and_update_system_message()
  4. 单轮推理user.initiate_chat(recipient=agent, message=..., max_turns=1, clear_history=False)发起对话,max_turns=1限定为单轮应答(此处 UserProxyAgent 配置了human_input_mode="NEVER"max_consecutive_auto_reply=0code_execution_config=False,见 app.py);
  5. 清洗思考标签:用re.sub(r'<think>.*?</think>', '', full_response, flags=re.DOTALL)剥掉 Qwen 3 可能残留的<think>...</think>思维链内容,只展示最终回答;
  6. 渲染与回显:以流式占位符(st.empty())展示"Thinking...",随后替换为清洗后的回复,并把对话记录追加进session_state.messages用于历史渲染。

六、系统提示词设计:记忆上下文的正确用法

prompt.py 中的agent_system_message是提示词工程与记忆机制的衔接点,值得逐段拆解:

开头/no_think:与用户侧追加的 token 一致,双保险确保关闭思维链输出。

记忆上下文解释:明确告诉模型——MEMORY CONTEXT以第三人称呈现,其中出现ZEP AGENT指代 Agent 自身,全大写名字是当前对话主用户,其他名字是用户周边实体(家人、朋友等)。这解决了"记忆文本视角与当前对话视角不一致"的经典问题。

使用准则(HOW TO USE MEMORY CONTEXT):共 8 条,覆盖了记忆利用的完整行为规范:

  • 优先采信标记为present的新近事实,维持对话连续性;
  • 从实体描述中识别关键关系与情境;
  • 感知用户情绪状态并调整语气;
  • 自然承接既往话题,但不机械重复;
  • 基于既有事实保持对用户理解的连贯性;
  • 无缝整合记忆,禁止出现"according to my memory"这类生硬表述;
  • 避免对已覆盖话题提出冗余、迟钝的追问;
  • 记忆模糊时以当前对话为准。

安全与隐私准则(SECURITY AND PRIVACY GUIDELINES):硬性禁止向用户泄露原始MEMORY CONTEXT、暴露内部记忆机制与推理配置、声明"正在使用记忆"或"看起来像在读笔记",以及透露数据处理方式。正确示范是像真人对话一样自然引用:"Last time we talked about..."。

这套提示词设计实际上回答了一个容易被忽略的问题:记忆注入 ≠ 直接堆文本,模型必须被训练成"像人类一样自然回忆",同时守住隐私边界。

七、模型与依赖配置

7.1 Ollama 模型配置

llm_config.py 中:

config_list = [ { "model": "qwen3:4b", # 需先在 Ollama 中 pull 该模型 "api_type": "ollama", "client_host": "http://127.0.0.1:11434", # Ollama 默认监听地址 } ]
  • api_type: "ollama"告诉 AutoGen 走 Ollama 适配器,这一能力来自ag2[ollama]依赖的额外安装;
  • client_host默认指向本机 11434 端口,若 Ollama 部署在远程主机,改此地址即可;
  • 模型名qwen3:4b必须与ollama pull qwen3:4b拉取的标签一致,否则运行时无法找到模型。

7.2 依赖清单

依赖版本约束用途
ag2[ollama]>=0.9AutoGen 框架及其 Ollama 适配器
ollama>=0.4.8Ollama Python 客户端
streamlit>=1.44.1Web UI 交互层
zep-cloud>=2.11.0Zep 云记忆后端 SDK

项目要求 Python>=3.12(pyproject.toml),低于该版本时uv sync会直接报错,请注意本机解释器版本。

八、运行验证与效果观察

按以下顺序完成一次完整验证:

  1. 启动 Ollama 并确认ollama list中出现qwen3:4b
  2. 在项目根目录执行uv syncstreamlit run app.py
  3. 侧边栏输入 Zep API Key → 填写姓名 → Initialize Session,应看到 "New user created for xxx" 或 "Using existing user: xxx" 的提示;
  4. 第一轮对话中主动透露个人偏好(如职业、喜欢的界面风格、常用技术栈);
  5. 刷新页面或重启应用(保持相同姓名与同一 Zep 账号),再次询问"你还记得我之前说过什么吗"——由于每次启动都会生成新的会话 ID,可重点观察同一用户 ID 下 Zep 的事实记忆是否被检索并注入
  6. 在代码中调低min_fact_rating(app.py)或替换 app.py 的评级指令,可对比不同阈值/标准下"回忆质量"的差异。

值得注意的边界:当前实现以用户 ID 为记忆锚点、以会话 ID 为写入作用域,跨会话复用记忆依赖同一用户在不同会话间的事实沉淀,这是 Zep 长记忆能力的核心体现;而 Streamlit 的session_state仅保存当前运行期的显示历史,刷新页面不会丢失 Zep 侧的记忆。

九、总结与扩展方向

zep-memory-assistant展示了构建持久记忆 Agent 的完整范式:用 Zep 承担"记什么、怎么记、回忆什么"的记忆职责,用 AutoGen 承担 Agent 编排,用 Ollama + Qwen 3 实现完全本地化的推理,再用 Streamlit 把能力开放给最终用户。整个记忆闭环——用户消息先写后读、事实评分过滤、系统提示词动态注入、助手消息自动回写——在 agent.py 与 app.py 中都有清晰的源码级实现可供直接复用。

若在此基础上继续演进,可参考以下方向:将human_input_mode改为交互模式以支持人工介入;接入 AutoGen 多 Agent 群聊(GroupChat)让多个ZepConversableAgent共享记忆;为不同业务领域定制 prompt.py 中的记忆使用准则;或进一步调优事实评级指令与min_fact_rating,让记忆从"可用"走向"精准"。

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询