乐于分享
好东西不私藏

记忆系统架构文档

记忆系统架构文档

记忆系统架构文档

1. 系统概览

记忆系统是一个多层文件持久化框架,以腾讯云 COS(对象存储)为唯一后端,无本地磁盘回退。

┌──────────────────────────────────────────────────────────────┐
│                       记忆系统 (Memory System)                 │
├──────────┬──────────┬──────────┬──────────┬──────────────────┤
│Agent     │Auto      │Session   │Snapshot  │Relevant Recall   │
│Memory    │Memory    │Memory [OK] │          │                  │
│持久记忆   │自动提取   │会话摘要   │可分发型   │智能回忆           │
│绑定Agent  │后台任务   │长对话压缩  │记忆资产   │最多5个文件         │
├──────────┴──────────┴──────────┴──────────┴──────────────────┤
│                    memdir (MEMORY.md 索引 + 提示词构建)         │
├──────────────────────────────────────────────────────────────┤
│               MemoryTools (COS-backed 文件工具)                │
│         save_file | read_file | list_files | delete_file     │
│                       replace_file_chunk                     │
├───────────────────────────┬──────────────────────────────────┤
│       COSStorage (COS)    │    Redis (Session Memory 热数据)    │
│   记忆文件持久化 (所有层)    │   消息累积 + 提取状态 (多 Pod 共享)  │
│   摘要持久化 (Session)     │   分布式锁 (防并发提取)              │
└───────────────────────────┴──────────────────────────────────┘

2. 功能模块

2.1 Agent Memory (agent_memory.py)

核心层,负责将持久记忆注入 Agent 运行时。

功能 说明
提示词注入 load_agent_memory_prompt() 将记忆目录结构、MEMORY.md 索引、使用指令注入 system prompt
工具注入 inject_memory_tools() 将 COS-backed MemoryTools 挂载到 Agent
目录管理 ensure_memory_dir() 确保记忆目录在 COS 上存在(异步、不阻塞)
作用域 USER(跨项目用户级)/ PROJECT(项目级)/ LOCAL(本机级)

指令结构(注入到 Agent system prompt 的 additional_context):

# Persistent Agent Memory
├── 记忆目录路径
├── ## Types of memory (user/feedback/project/reference)
├── ## What NOT to save (排除项)
├── ## How to save memories (save_file 用法 + frontmatter 格式)
├── ## When to save memories (何时主动保存)
├── Scope-specific guidance (USER/PROJECT/LOCAL 作用域指引)
├── ## When to access memories (何时读取 + read_file 指引)
└── ## MEMORY.md (当前索引内容)

2.2 Auto Memory (auto_memory.py)

后台自动提取层,从对话记录中异步提取持久记忆。

功能 说明
extract_memories() 使用独立模型扫描对话,提取值得持久化的信息
extract_memories_background() fire-and-forget 封装,不阻塞主流程
提取类型 user / feedback / project / reference
解析格式 TYPE|NAME|DESCRIPTION|CONTENT--- 分隔多条目

当前状态:模块已定义,尚未集成到对话 Pipeline 中。

2.3 Session Memory (session_memory.py + session_manager.py)

长对话压缩层,防止上下文窗口溢出。支持多 Pod 部署。

文件 职责
session_memory.py 纯逻辑:token 估算、阈值判断、自然断点检测
session_manager.py 运行时管理器:消息累积、摘要提取、COS 持久化、Redis 共享状态

存储分层

热数据 (Redis)              温/冷数据 (COS)             本地 (内存)
┌─────────────────┐    ┌──────────────────────┐    ┌──────────────┐
│ messages (List)  │    │ session-{id}.md      │    │ 摘要 LRU 缓存 │
│ state (Hash)     │    │ (摘要 Markdown 文件)   │    │ (命中直接返回) │
│ lock (String)    │    │                      │    │              │
│ TTL 3600s       │    │ 持久化,不自动过期     │    │ Pod 重启即丢   │
└─────────────────┘    └──────────────────────┘    └──────────────┘
  多 Pod 共享               多 Pod 共享              单 Pod 可见
  • 消息和提取状态 -> Redis(需跨 Pod 共享,控制累积一致性)
  • 摘要 -> COS 持久化 + 内存 LRU(不再存 Redis,减少内存占用)
  • 跨 Pod 摘要可见性:Pod A 提取 -> 写 COS -> Pod B 下次请求 -> 读 COS -> 缓存到内存

Redis Key 设计

Key 类型 内容 限制
wclaw:session_memory:{session_id}:messages List JSON 消息对象 LTRIM 最多 200 条 (~50KB)
wclaw:session_memory:{session_id}:state Hash initialized, last_uuid, token_count
wclaw:session_memory:{session_id}:lock String 提取分布式锁 (SETNX) TTL 60s

全局 TTL 3600s,每次 collect_messages 续期。用户停止对话 1 小时后自动过期清理。

双模式运行

启动时自动 PING Redis 探测可达性:

模式 条件 消息/状态存储 多 Pod 安全
Redis 模式 REDIS_URL 配置 + 可达 Redis [OK]
内存模式 Redis 未配置或不可达 进程内 dict [X] (开发/测试用)

阈值配置

参数 默认值 环境变量
初始化阈值 10,000 tokens SESSION_MEMORY_MIN_TOKENS_TO_INIT
更新阈值 5,000 tokens SESSION_MEMORY_MIN_TOKENS_BETWEEN_UPDATE
工具调用阈值 3 次 SESSION_MEMORY_TOOL_CALLS_BETWEEN_UPDATE

核心方法

方法 说明
collect_messages(session_id, messages) 追加消息到 Redis List(去重 + LTRIM 截断)
should_extract(session_id) 检查阈值 + 自然断点
maybe_extract(session_id, model, force=False) 获取分布式锁 -> LLM 提取摘要 -> 写 COS -> 重置消息缓冲
get_summary(session_id) 内存缓存 -> COS 回退读取
clear_session(session_id) 删除 Redis key + 内存缓存
stats(session_id) 调试信息(消息数、tokens、后端模式等)

内存控制策略

策略 说明
摘要不存 Redis 摘要已在 COS 持久化,Redis 不再冗余存储;跨 Pod 通过 COS 读取
LTRIM 截断 collect_messages 时自动截断到 200 条,防止单会话消息无限增长
提取后重置 提取成功后消息缓冲重置为最后 5 条(保留上下文衔接)
TTL 自动过期 非活跃会话 1 小时后所有 Redis key 自动删除
分布式锁 SETNX 60s TTL,防止多 Pod 同时提取同一会话

当前状态:[OK] 已集成,支持多 Pod Redis 共享。详见 5.4 Session Memory 集成。

2.4 Snapshot (snapshot.py)

可分发的记忆资产,让项目附带 Agent 的初始记忆结构。

功能 说明
check_agent_memory_snapshot() 检查快照状态:none / initialize / prompt-update
initialize_from_snapshot() 从快照目录复制文件到 Agent 记忆目录
replace_from_snapshot() 强制替换(删除本地 .md 后全量复制)
create_snapshot() 从当前记忆反向生成快照
mark_snapshot_synced() 记录已同步,不覆盖本地记忆

状态转换

    snapshot不存在 ──-> none
    记忆目录为空 ──-> initialize (复制快照作为初始状态)
    有新版快照 ──-> prompt-update (通知用户同步)
    已同步 ──-> none

2.5 Relevant Recall (find_relevant.py)

智能回忆,用轻量模型从记忆目录中选取最多 5 个最相关文件。

功能 说明
scan_memory_files() 扫描所有 .md 文件的 frontmatter,提取 name/description/type
format_memory_manifest() 构建紧凑文件清单(仅文件名+描述,不含正文)
find_relevant_memories() 用轻量模型选择相关文件,或 keyword fallback
最大数量 5 个文件
去重 过滤已在最近轮次中 surfaced 的文件

3. COS 存储路径映射

3.1 目录布局

<memory-base>/
├── users/<user_id>/agent-memory/<agent_type>/   <- Agent Memory (用户隔离)
│   ├── MEMORY.md                                 <- 索引文件
│   ├── *.md                                      <- 记忆文件
│   └── .snapshot-synced.json                     <- 快照同步状态
├── agent-memory/<agent_type>/                    <- Agent Memory (共享)
├── users/<user_id>/projects/<cwd>/memory/        <- Auto Memory (用户)
├── projects/<cwd>/memory/                        <- Auto Memory (共享)
└── sessions/                                     <- Session Memory

3.2 COS Key 生成

# local path -> COS key
/Users/mac/.harness/users/100/agent-memory/default/user_role.md
        v 以 /.harness/ 为分界截断
memory/users/100/agent-memory/default/user_role.md

3.3 记忆文件格式

---
name: memory_name
description: 一行描述,用于判断相关性
type: user|feedback|project|reference
---

正文内容。Markdown 格式。

4. 核心流程

4.1 Agent 创建时记忆注入

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.2 主动保存记忆(save_file)

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.3 跨会话读取记忆

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.4 纠正/更新记忆

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.5 删除记忆文件

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.6 列出记忆文件

流程图(原文包含 Mermaid 流程图,请在原文中查看)

4.7 Session Memory 运行时流程(多 Pod Redis 模式)

流程图(原文包含 Mermaid 流程图,请在原文中查看)

5. 集成点

5.1 Agent 创建 (blaze_agent.py)

_build_agent()
  ├── 过滤 agno 内置工具 (FileTools, update_user_memory, update_profile)
  ├── load_agent_memory_prompt() -> additional_context
  ├── Agent.__init__(tools=filtered, additional_context=prompt)
  └── inject_memory_tools() -> MemoryTools 追加到 agent.tools

5.2 请求入口 (routes.py)

sandbox_agent_runs
  ├── 提取 user_id (header wid 或 body)
  ├── 创建 session
  └── get_blaze_executor(user_id, ...)
       └── _build_agent(user_id) -> 触发记忆注入

5.3 学习模块 (learning_manager.py)

get_learning_machine()
  ├── user_profile=False  <- 由 COS MemoryTools 接管
  ├── user_memory=False   <- 由 COS MemoryTools 接管
  └── learned_knowledge (可选)

5.4 Session Memory 集成

两个注入点

请求入口 (routes.py)
  ├── get_session_memory_manager().get_summary(session_id)  <- async
  │   ├── 内存缓存命中 -> 直接返回
  │   ├── 内存缓存未命中 -> COS 读取 -> 缓存到内存 -> 返回
  │   └── 如果有摘要 -> 注入到 message 前面
  │       格式: "[会话历史摘要]\n{summary}\n\n---\n用户最新消息:{message}"
  └── agent.run(injected_message)

Agent 创建 (blaze_agent.py)
  └── post_hooks: _build_session_memory_post_hook()
       └── 每轮对话结束后 (async):
            ├── await mgr.collect_messages(session_id, messages)
            │   └── Redis: RPUSH + LTRIM + EXPIRE (或内存 dict)
            └── if await mgr.should_extract(session_id):
                 └── asyncio.create_task(mgr.maybe_extract(session_id, model))
                      ├── Redis SETNX lock (防并发)
                      ├── LLM 提取摘要
                      ├── COS write_memory (持久化)
                      ├── 内存缓存摘要 (当前 Pod)
                      ├── Redis: 重置消息缓冲为最后 5 条
                      └── Redis DEL lock

启动时自动探测

SessionMemoryManager.__init__()
  └── (lazy) _ensure_redis()
       ├── REDIS_URL 未配置 -> 内存模式 (单 Pod)
       ├── Redis PING 成功 -> Redis 模式 (多 Pod 安全)
       └── Redis PING 失败 -> 内存模式 + 警告日志

调试端点 (routes.py):

端点 方法 说明
/wclaw/agents/session-memory/stats?session_id=xxx GET 查询消息数、tokens、摘要状态、后端模式 (redis/memory)
/wclaw/agents/session-memory/force-extract?session_id=xxx POST 手动触发提取(绕过阈值检查)

6. 关键设计决策

决策 原因
COS 唯一后端,无本地回退 多实例部署时保证记忆一致;本地文件系统不可靠
MEMORY.md 自动维护 Agent 只需调 save_file,索引自动同步,避免手动两步操作
/.harness/ 作为 COS Key 分界 消除本地家目录路径污染,保持 COS Key 简洁
过滤 agno 内置记忆工具 update_user_memory 走 PostgreSQL,与 COS 路径冲突
过滤 agno FileTools 方法名重叠(save_file 等),且 FileTools 写本地磁盘
提示词注入而非 system_message 追加到 additional_context,不影响 Agent 核心角色定义
Session Memory 消息/状态走 Redis 多 Pod 共享消息累积和提取状态,避免 Pod 间消息碎片化导致阈值永远达不到
Session Memory 摘要走 COS 不存 Redis 摘要已在 COS 持久化,Redis 冗余浪费内存;跨 Pod 通过 COS 读取,首次后内存缓存
Redis 不可达自动降级为内存模式 开发/测试环境无 Redis 时也能正常运行,生产环境确保配置 REDIS_URL
分布式锁防并发提取 SETNX 60s TTL,防止多 Pod 同时检测到阈值触发、重复调用 LLM 提取
LTRIM 200 条 + TTL 3600s 控制单会话 Redis 内存上限 (~50KB);非活跃会话 1 小时自动过期
提取后消息重置为 5 条 既保留上下文衔接,又避免同一会话反复提取