Skip to content

Day 7 — Memory 设计文档

设计目标:构建分层记忆系统——短期记忆管理对话窗口、长期记忆持久化跨对话知识、SystemPromptBuilder 在 Token 预算内组装最优上下文。


一、核心接口设计

1.1 ShortTermMemory

方法签名说明
get_messagesget_messages(session) -> List[ChatMessage]获取裁剪后的消息列表
trimtrim(messages, max_messages) -> List[ChatMessage]按窗口大小裁剪

配置参数

参数默认值说明
max_messages20最多保留的消息条数

1.2 LongTermMemory

方法签名说明
storeasync store(user_id, content, category)存入一条记忆
recallasync recall(user_id, query, top_k) -> List[str]按关键词召回记忆
clearasync clear(user_id)清除用户所有记忆

存储格式(Markdown 文件):

markdown
## 2025-01-15 14:30:00 | 用户偏好
用户喜欢简洁的回答风格

## 2025-01-15 15:00:00 | 项目信息  
用户在做 Python 电商项目

1.3 SystemPromptBuilder

方法签名说明
set_base_promptset_base_prompt(prompt: str)设置基础提示词
add_skills_layeradd_skills_layer(prompts: List[str])添加技能层
add_tools_layeradd_tools_layer(tools_desc: str)添加工具描述层
add_dynamic_contextadd_dynamic_context(context: str)添加动态上下文
add_memory_layeradd_memory_layer(memories: List[str])添加长期记忆层
buildbuild(token_budget: int) -> str在预算内构建最终 prompt

二、关键流程图

SystemPromptBuilder 组装流程

短期记忆裁剪流程


三、设计决策与权衡

决策 1:短期记忆用消息条数 vs Token 数量裁剪

方案优点缺点
消息条数(选择)简单直观,O(1) 操作不同消息长度差异大,实际 Token 用量不稳定
Token 数量精确控制需要逐条计算 Token,复杂
消息摘要保留更多上下文需要额外 LLM 调用,成本高

选择理由:教学阶段用条数裁剪最直观。理解了概念后,改为 Token 裁剪只需修改 trim() 方法。

决策 2:长期记忆用 Markdown 文件

方案优点缺点
Markdown 文件(选择)零依赖、可读性好、Git 友好搜索效率低(O(n) 遍历)
SQLite本地零配置、结构化查询需要 SQL 知识
向量数据库语义搜索、最准确需要安装配置、向量化模型

选择理由:教学目标是理解"长期记忆的概念和流程",而非实现高效的存储引擎。Markdown 存储让学习者可以直接打开文件查看记忆内容,降低学习门槛。

决策 3:Token 计算的降级策略

python
try:
    import tiktoken
    encoding = tiktoken.encoding_for_model(model)
    token_count = len(encoding.encode(text))
except ImportError:
    token_count = len(text)  # 1 字符 ≈ 1 token 的粗略估算
方案优点缺点
tiktoken 优先 + 字符数降级(选择)有就精确、没有也不报错降级后不够准确
强制依赖 tiktoken始终精确增加安装门槛

决策 4:Builder 分层优先级

高优先级的层保证保留,低优先级的层预算不够时裁减

  1. 基础 prompt(永远保留)
  2. 技能 prompt(通常很短,保留)
  3. 工具描述(影响工具使用能力,优先保留)
  4. 动态上下文(有用但非必须)
  5. 长期记忆(最低优先级,可以不带)

理由:没有基础 prompt,Agent 不知道自己是谁;没有工具描述,Agent 无法调用工具。长期记忆是"锦上添花",缺了不影响基本功能。


四、与前序章节的集成点

  • 依赖 Day 3:ShortTermMemory 操作 Session.messages
  • 依赖 Day 5:Builder 的工具描述层来自 ToolRegistry
  • 依赖 Day 6:Builder 的技能层来自 SkillManager.get_active_prompts()
  • 被 Day 4 依赖:Builder.build() 替代简单的 system_prompt 字符串传给 AgentRuntime

五、与真实生产系统的对比

维度miniOpenClaw生产级实现
短期记忆滑动窗口(条数)Token 精确裁剪 + 消息摘要
长期记忆Markdown 关键词搜索向量数据库 + 语义检索
记忆写入显式调用Agent 自动判断 + 结构化提取
Token 计算tiktoken / 字符数tiktoken 精确计算
上下文窗口固定预算动态分配(根据任务复杂度调整)
多用户隔离文件名区分数据库行级隔离 + 加密