首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Nanobot 记忆系统深度解析

Nanobot 记忆系统深度解析

作者头像
naget
发布2026-03-13 15:05:15
发布2026-03-13 15:05:15
2320
举报
文章被收录于专栏:VegoutVegout

📑 本文目录

1. 核心问题:记忆膨胀如何解决

2. 三层记忆架构

3. 分层记忆加载详解

4. Tier 3 记忆的唤醒机制

5. 什么样的记忆会进入长期记忆

6. 📝 总结

核心问题:记忆膨胀如何解决

问题背景

随着使用时间越长,nanobot 积累的记忆会越来越多。如果不加控制,每次对话的上下文会越来越长,最终导致:

  • Token 消耗爆炸 💸
  • 超出模型上下文限制 📏
  • 响应变慢 🐌

解决方案:分层截断

代码语言:javascript
复制
┌─────────────────────────────────────────────────────────────┐
│  Layer 1: System Prompt (每次请求都包含)                      │
│  ├── 核心身份 (identity)                                     │
│  ├── Bootstrap 文件 (AGENTS.md, SOUL.md, USER.md 等)        │
│  ├── 长期记忆 MEMORY.md (完整内容)                           │
│  └── 今日笔记 (当天记忆,完整内容)                            │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│  Layer 2: Conversation History (限制数量)                    │
│  └── 最近 max_messages=50 条对话历史                        │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│  Layer 3: Persistent Storage (不直接送入 LLM)                │
│  ├── 历史日期记忆文件 (memory/2024-01-15.md...)             │
│  └── 历史对话记录 (sessions/*.jsonl)                        │
└─────────────────────────────────────────────────────────────┘

关键代码

历史截断机制 (session/manager.py):

代码语言:javascript
复制
def get_history(self, max_messages: int = 50) -> list[dict[str, Any]]:
# 只取最近 50 条消息
recent = self.messages[-max_messages:] if len(self.messages) > max_messages else self.messages
return [{"role": m["role"], "content": m["content"]} for m in recent]

三层记忆架构

Tier 1: 关键记忆 (Always Loaded)

代码语言:javascript
复制
完整加载

特点:直接嵌入 System Prompt,LLM 立即可见

Tier 2: 近期历史 (Truncated)

内容

加载方式

对话历史

最多 50 条

特点:作为 messages 传入,旧消息自动丢弃

Tier 3: 归档记忆 (On-Demand)

内容

加载方式

历史日期记忆文件

不自动加载

历史对话记录

不自动加载

特点:需要时通过 read_file 工具按需读取


分层记忆加载详解

什么是分层记忆加载?

分层记忆加载是指 nanobot 根据记忆的重要性时效性,采用不同的加载策略,而不是把所有记忆都塞进 LLM 的上下文。

实际工作流程

代码语言:javascript
复制
用户提问: "上周我让你记了什么?"┌────────────────────────────────────────────────────────────┐
│ Step 1: 构建上下文                                          │
│ System Prompt: 包含 MEMORY.md + 今日笔记                    │
│ History: 最近 50 条对话                                      │
│                                                            │
│ → 此时**不包含**上周的记忆文件                               │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ Step 2: LLM 决定需要读取历史记忆                             │
│ LLM 调用: read_file(path="memory/2024-01-15.md")            │
│                                                            │
│ → 通过工具**按需加载**特定日期的记忆                         │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ Step 3: 记忆内容加入上下文                                   │
│ Tool Result: 上周记忆的内容                                  │
│ LLM 基于读取的内容回答用户                                   │
└────────────────────────────────────────────────────────────┘

设计对比

层级

类比人类大脑

设计原因

Tier 1

工作记忆

关键信息需要 LLM 随时知道

Tier 2

短期记忆

对话连续性需要,但旧对话相关性递减

Tier 3

长期存储

历史信息可能有用也可能没用,让 LLM 自己判断


Tier 3 记忆的唤醒机制

核心特点

Tier 3 记忆是"被动唤醒"的 —— 它静静地躺在文件系统里,只有当 LLM 通过推理认为"我需要这个信息"时,才会通过 read_file 工具被唤醒。

三种唤醒触发方式

触发方式 1: 用户显式要求
代码语言:javascript
复制
用户: "帮我查一下上周三我记了什么"
↓
LLM 推理: 用户询问历史记忆 → 需要读取特定日期文件
↓
调用: read_file(path="memory/2024-01-10.md")
触发方式 2: LLM 主动推理
代码语言:javascript
复制
用户: "根据之前的项目计划,接下来该做什么?"
↓
LLM 推理: 当前上下文没有项目计划 → 需要查找 MEMORY.md 或历史笔记
↓
调用: read_file(path="memory/MEMORY.md")
或: list_dir(path="memory") → 查看有哪些历史文件
触发方式 3: 长期记忆指引
代码语言:javascript
复制
场景: MEMORY.md 中有一条记录:
"重要: 所有 API 密钥都保存在 ~/secrets.json"
↓
用户: "我需要更新 API 密钥"
↓
LLM 看到 MEMORY.md 中的指引 → 知道要去读取 ~/secrets.json
↓
调用: read_file(path="~/secrets.json")

为什么 Tier 3 不会自动唤醒?

方案

优点

缺点

❌ 自动检索相关记忆

无需 LLM 推理

增加复杂性,可能召回不相关内容

✅ LLM 自主决定 (nanobot)

简单可靠,精准召回

需要 LLM 有推理能力

局限性

  • 依赖 LLM 推理:如果 LLM 没意识到需要查历史,就不会读取
  • 无自动检索:不会自动搜索"相关"的历史记忆
  • 需要明确日期:用户说"上周"LLM 需要转换成具体日期

什么样的记忆会进入长期记忆

进入机制

nanobot 的长期记忆 (MEMORY.md) 采用开放式设计,通过 System Prompt 引导 + LLM 自主判断 来决定什么该记住。

System Prompt 引导

代码语言:javascript
复制
# context.py
"When remembering something, write to {workspace_path}/memory/MEMORY.md"

长期记忆的典型内容

类别

示例

为什么进长期记忆

用户身份信息

"用户叫张三,是软件工程师"

跨会话都需要知道

个人偏好

"用户喜欢用 Python,不喜欢 Java"

影响后续回答风格

重要事实

"用户的 OpenAI API key 在 ~/.key"

需要持久保存

项目背景

"正在开发一个电商网站"

多轮对话的上下文基础

关键决策

"决定使用 PostgreSQL 而不是 MySQL"

避免重复讨论

约束条件

"代码必须兼容 Python 3.9"

影响所有后续代码生成

长期记忆 vs 每日笔记

代码语言:javascript
复制
┌─────────────────────────────────────────────────────────────────┐
│  长期记忆 (MEMORY.md)              每日笔记 (YYYY-MM-DD.md)      │
├─────────────────────────────────────────────────────────────────┤
│  • 跨会话持久                      • 当天有效                    │
│  • 需要显式决定写入                  • 自动追加                   │
│  • 结构化组织 (User/Preferences)    • 时间线式记录                │
│  • 每次对话都加载                    • 只加载当天                 │
│  • 适合: 事实、偏好、配置            • 适合: 临时想法、当日待办     │
└─────────────────────────────────────────────────────────────────┘

进入长期记忆的三种方式

代码语言:javascript
复制
┌─────────────────────────────────────────────────────────────────┐
│ 方式 1: LLM 自主决定写入                                         │
├─────────────────────────────────────────────────────────────────┤
│ 用户: "我叫李四,以后就这么叫我吧"                               │
│       ↓                                                         │
│ LLM 推理: 这是重要身份信息 → 应该写入长期记忆                     │
│       ↓                                                         │
│ 调用: write_file(path="memory/MEMORY.md", content="...")        │
└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐
│ 方式 2: 用户显式要求                                             │
├─────────────────────────────────────────────────────────────────┤
│ 用户: "记住我的邮箱是 li@example.com"                            │
│       ↓                                                         │
│ LLM 推理: 用户要求记住 → 写入 MEMORY.md                         │
│       ↓                                                         │
│ 调用: edit_file 或 write_file 更新 MEMORY.md                    │
└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐
│ 方式 3: 从每日笔记提炼                                           │
├─────────────────────────────────────────────────────────────────┤
│ 场景: 今天讨论了一整天的技术方案                                 │
│       ↓                                                         │
│ LLM 推理: 今日笔记中有重要结论 → 提炼到长期记忆                   │
│       ↓                                                         │
│ 读取今天的笔记 → 总结关键点 → 追加到 MEMORY.md                  │
└─────────────────────────────────────────────────────────────────┘

设计哲学

"长期记忆是用户的第二大脑,不是日志"

  • ❌ 不会自动把所有对话都塞进去
  • ❌ 没有复杂的自动摘要算法
  • ✅ 依赖 LLM 的推理能力判断"什么值得记住"
  • ✅ 保持简洁,只存真正重要的信息

📝 总结

nanobot 的记忆系统通过分层设计解决了记忆膨胀问题:

  1. Tier 1 (关键记忆): 始终加载,保证核心信息可用
  2. Tier 2 (近期历史): 硬性截断,保持上下文可控
  3. Tier 3 (归档记忆): 按需唤醒,避免无关信息干扰

这种设计让 nanobot 可以积累无限多的历史记忆,而每次请求的 token 消耗始终保持在可控范围内。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Vegout 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 核心问题:记忆膨胀如何解决
    • 问题背景
    • 解决方案:分层截断
    • 关键代码
  • 三层记忆架构
    • Tier 1: 关键记忆 (Always Loaded)
    • Tier 2: 近期历史 (Truncated)
    • Tier 3: 归档记忆 (On-Demand)
  • 分层记忆加载详解
    • 什么是分层记忆加载?
    • 实际工作流程
    • 设计对比
  • Tier 3 记忆的唤醒机制
    • 核心特点
    • 三种唤醒触发方式
      • 触发方式 1: 用户显式要求
      • 触发方式 2: LLM 主动推理
      • 触发方式 3: 长期记忆指引
    • 为什么 Tier 3 不会自动唤醒?
    • 局限性
  • 什么样的记忆会进入长期记忆
    • 进入机制
    • System Prompt 引导
    • 长期记忆的典型内容
    • 长期记忆 vs 每日笔记
    • 进入长期记忆的三种方式
    • 设计哲学
  • 📝 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档