OpenClaw 的长短期记忆体系概览

一句话总览:

OpenClaw 把"记忆"拆成两层:

  • 短期记忆:当前会话里、这次请求要发给模型的那一小段上下文(会被裁剪/压缩)。
  • 长期记忆:落在磁盘上的 Markdown 文件 + 向量/全文索引,用来跨会话、跨时间"回想"信息。

下面分块讲清楚这两层各自是什么、怎么实现、怎么协同。


一、短期记忆:会话上下文(Session Context)

1. 会话是怎么管理的?

文档:docs/concepts/session.md

  • 每个 Agent 有一套会话系统:
  • 主私聊:agent:<agentId>:<mainKey>(默认 main)。
  • 不同频道/群聊有独立 session key。
  • 状态保存在网关机器上:
  • 元数据:~/.openclaw/agents/<agentId>/sessions/sessions.json
  • 聊天记录(转录):~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl

JSONL 每一行是一条记录(用户/助手消息、工具调用等)。

2. "短期记忆"具体是什么?

一轮请求时,OpenClaw 会:

  1. 找到对应的 sessionId。
  1. 读取该 session 最近的一段聊天(从 JSONL 或内存缓存)。
  1. 加上:
  • 系统提示(system prompt)
  • 工具调用结果(如 memory_search、浏览器结果等)
  • 运行时元信息 / 控制开关
  1. 拼成一个要发给模型的大 prompt。

这个 prompt + 最近几轮对话,就可以视为"短期记忆":

  • 它是这次 LLM 调用真实看到的上下文。
  • 大小受模型 contextWindow 限制(上下文窗口)。
  • 当太长时,会触发:
  • Session pruning:优先删掉老旧/低价值内容(如旧工具结果)。
  • Compaction:把较早部分对话"压缩成摘要"。

这些裁剪/压缩只影响"送进模型的上下文",

不会立刻改写 JSONL 文件(JSONL 是原始历史)。


二、长期记忆:Markdown + 向量/全文索引

文档:docs/concepts/memory.md

核心代码:src/memory/*

1. 长期记忆的"源数据":两类 Markdown

默认工作区下有两类记忆文件(L18--L25):

  • memory/YYYY-MM-DD.md
  • 每日"流水账",追加型。
  • Session 启动时会读取"今天 + 昨天"的内容。
  • 手工/半自动"长期记忆总结":
  • 稳定偏好(比如"这个用户喜欢中文 + TypeScript")
  • 长期存在的事实、约定。
  • 只在 主私聊 session 中加载,避免在群里泄露。

写入建议:

  • "决定、偏好、长期事实" → MEMORY.md
  • "日常运行笔记、当天情况" → memory/当天日期.md
  • 用户说"记住这个"时:应该显式写盘,而不是只让它停留在上下文里。

可以把这两类文件直接当作"人类可读的知识库笔记本"。

2. 向量/全文索引:怎么让机器"用起来"

Markdown 是本体,但要自动检索,需要一个索引引擎。

默认使用 SQLite 嵌入式数据库 构建索引,路径类似:

  • ~/.openclaw/memory/<agentId>.sqlite

建表逻辑在 src/memory/memory-schema.ts,主要表:

  • files
  • 每行代表一个被索引的文件(比如 MEMORY.md、memory/2026-02-04.md)。
  • 保存 path、source(memory / sessions)、hash、mtime、size。
  • chunks
  • 核心向量索引表:
  • 一行 = 一个小片段(chunk):
  • 来源路径 + 起止行号:path / source / start_line / end_line
  • 文本内容:text
  • 向量:embedding(JSON 字符串、内部是 [0.01, -0.03, ...])
  • 使用的 embedding 模型名:model
  • hash:chunk 内容的 hash
  • embedding_cache
  • 相同内容的 chunk 只算一次 embedding,用 hash 做 key 缓存。
  • meta
  • 保存当前索引用的模型、provider、chunk 大小等,便于判断是否要全量重建。

此外还有:

  • chunks_vec:sqlite-vec 的虚拟向量表(FLOAT[N] 数组),用于在 SQLite 内部直接做向量距离搜索。
  • chunks_fts:FTS5 全文检索表,用于关键词/BM25 搜索。

3. 向量是怎么算出来的?(Embedding Provider)

统一封装在 src/memory/embeddings.ts:

embeddings.tsLines 21-26

export type EmbeddingProvider = {

id: string; // "openai" | "gemini" | "local"

model: string; // 模型名或本地模型路径

embedQuery: (text: string) => Promise<number[]>;

embedBatch: (texts: string[]) => Promise<number[][]>;

};

支持三种后端:

  • OpenAI 远程 embedding
  • 默认模型:text-embedding-3-small。
  • Gemini 远程 embedding
  • 默认模型:gemini-embedding-001。
  • 本地 embedding(node-llama-cpp)
  • 默认模型:hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf。
  • 会自动下载 GGUF 模型,使用 node-llama-cpp 在本机计算向量。

所有向量计算后会做标准化(单位向量):

embeddings.tsLines 9-15

// 非数值改成 0,然后进行 L2 归一化

4. 文本是如何切片(chunking 策略)的?

配置结构在 ResolvedMemorySearchConfig.chunking:

  • 默认参数:
  • tokens = 400:每个 chunk 目标 token 数。
  • overlap = 80:相邻 chunk 重叠 token 数。

大致做法:

  • 按顺序遍历 Markdown / 会话文本:
  • 每 400 token 切成一段;
  • 段与段之间重叠 80 token;
  • 这样:
  • 既不会把整篇长文塞进一个向量(太粗糙),
  • 又能保证相邻语义关联内容有交叠,不容易被切断。

5. 检索策略:向量 + 全文混合

用户/Agent 通过工具 memory_search 调用索引时,核心流程(MemoryIndexManager.search):

  1. 对查询文本做一次 embedding(embedQuery),得到 query 向量。
  1. 向量检索(semantic):
  • 在 chunks_vec / chunks 里找距离最近的一批 chunk(最多 N * candidateMultiplier)。
  1. 全文检索(keyword / BM25):
  • 在 chunks_fts 里用 FTS5 做 MATCH,算 BM25 分数。
  1. 混合(hybrid):
  • 参数:
  • vectorWeight(默认 0.7)
  • textWeight(默认 0.3)
  • 将两个分数线性加权合并,得到最终得分。
  1. 按分数排序,取前 maxResults 个 snippet 返回(每段 ~700 字符)。

返回内容包括:

  • snippet:一小段原文。
  • path / startLine / endLine:可以精确回到原 Markdown 文件。
  • source:"memory" 或 "sessions"(如果开启了 sessionMemory)。

Agent 会把这些 snippet 继续注入当次 LLM 调用的 prompt 中。


三、"短期 → 长期"的桥梁:自动 memory flush & sessionMemory

1. 自动 memory flush:上下文要满了,先"记个笔记"

当某个 session 的上下文 token 数接近模型窗口上限(考虑 reserveTokensFloor 和 softThreshold),

OpenClaw 会触发一次隐藏的提醒回合:

  • system 提示类似:
  • "Session nearing compaction. Store durable memories now."
  • user 提示类似:
  • "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store."

模型这时会:

  • 把这次长对话中"值得长期记住的事实、偏好、结论"写入 Markdown(MEMORY.md / memory/当天.md)。
  • 如果没有,就回复 NO_REPLY(这个回合对用户是不可见的)。

这相当于在"短期记忆即将被裁剪/摘要之前",

让模型主动把长远重要的信息搬运到长期记忆本子里。

2. sessionMemory:可选的"会话历史索引"

除了 Markdown,OpenClaw 还能选择性地把 会话转录 JSONL 自己也做成索引源(实验特性):

  • 配置示例:

agents: {

defaults: {

memorySearch: {

experimental: { sessionMemory: true },

sources: ["memory", "sessions"]

}

}

}

开启后:

  • MemoryIndexManager 会监听 ~/.openclaw/agents/<agentId>/sessions/*.jsonl:
  • 定期读取新追加的内容;
  • 把 User/Assistant 的文本内容提取出来,做 chunk + embedding;
  • 以 source="sessions" 的形式存入同一个 SQLite 索引。
  • 搜索时,可以同时在:
  • source="memory"(Markdown 记忆)
  • source="sessions"(会话记录)

两者上进行混合查询。

这样,近期的对话记录本身也可以被语义检索,但和 Markdown 的长期记忆仍然有清晰区分。


四、索引何时更新?(用户手动改 Markdown 的情况)

当用户自己编辑 MEMORY.md 或 memory/*.md 时,更新流程大致是:

  1. 文件写入磁盘后,chokidar 监听到变更:
  • 把 dirty = true,并启动一个防抖计时器。
  1. 防抖延迟结束后(默认 ~1.5 秒):
  • 后台调用 MemoryIndexManager.sync({ reason: "watch" })。
  • 对比每个文件的 hash:
  • hash 没变 → 跳过。
  • hash 变了 → 重切 chunk、重算 embeddings,更新 chunks / chunks_vec / chunks_fts。
  1. 完成后清理 stale 记录、更新 files 表,让索引与磁盘内容保持一致。

此外还有三种"顺带触发"的机会:

  • 新会话开始时(onSessionStart)。
  • 搜索前/后(onSearch)。
  • 定时后台任务(intervalMinutes)。

你无需手动操作任何按钮:只要保存 Markdown,索引会在短时间内自动同步。


五、SQLite 与"嵌入式数据库"的理解

1. SQLite 文件是什么?

  • 是一个普通的单文件,比如:~/.openclaw/memory/main.sqlite。
  • 内部是 SQLite 规定的二进制数据库格式:
  • 有表结构、索引、页、事务等。
  • 通过 SQLite 库可以用 SQL 语句 SELECT/INSERT/UPDATE 操作。

2. "嵌入式数据库"是什么意思?

  • 嵌入式数据库(如 SQLite)的特点:
  • 没有单独的数据库服务进程:
  • 没有 mysqld、postgres 那样的 daemon。
  • 程序直接在进程里 import sqlite,然后 open("xxx.sqlite") 就能用。
  • 执行 SQL 时,所有逻辑在当前进程内完成,直接读写这个文件。
  • 与 MySQL / PostgreSQL 这种"服务器型数据库"相对:
  • 那些需要先启动一个服务器进程:
  • 程序再通过 TCP / Unix socket 连接。
  • 数据文件的格式和管理主要由服务器自己负责,应用一般不直接操作文件。

在 OpenClaw 里:

选择 SQLite 做记忆索引,是因为它:

  • 部署简单:不需要额外跑数据库服务。
  • 跨平台:macOS / Linux 下都很好用。
  • 单文件易管理:备份、移动、清理都方便。

六、整体串起来的一句话总结

  • 短期记忆:
  • 当前这次请求要发给模型的 prompt + 最近几轮对话。
  • 存在内存 + JSONL 转录,受上下文窗口约束,会被裁剪/压缩。
  • 长期记忆:
  • MEMORY.md + memory/YYYY-MM-DD.md(以及可选的会话 JSONL)作为"记事本本体";
  • SQLite / QMD 上的向量 + 全文索引,让这些记事本可以被语义+关键词混合检索;
  • 通过 memory_search / memory_get 把相关片段再注入短期上下文,
  • 再配合自动 memory flush 把快被遗忘的重要信息写回 Markdown。
相关推荐
坐吃山猪4 天前
OpenClaw04_Gateway常见问题
网络·gateway·openclaw
Blockchina4 天前
OpenClaw 深度搭建与运行实录
ai agent·openclaw
行走的小派4 天前
普惠新篇章:香橙派全志系列开发板全面拥抱OpenClaw时代
全志·openclaw
冀博4 天前
2026爆款AI Agent|OpenClaw从入门到中级实操指南(含飞书对接+多Agent配置+避坑指南)
人工智能·飞书·openclaw
小马过河R4 天前
OpenClaw 记忆系统工作原理
人工智能·机器学习·语言模型·agent·openclaw·智能体记忆机制
码农垦荒笔记4 天前
OpenClaw 实战#05-5:第五层工程拆解——Skill 工程设计规范(硬干货版)
人工智能·agent·设计规范·openclaw
小小工匠4 天前
LLM - awesome-openclaw-usecases 用 OpenClaw 把生活“外挂化”:从技能到真实场景的系统指南
openclaw·claw cases
FserSuN4 天前
OpenClaw接入飞书远程控制机器完成任务
openclaw
木尧大兄弟4 天前
Ubuntu 系统安装 OpenClaw 并接入飞书记录
linux·ubuntu·飞书·openclaw
cxr8284 天前
Moonshine专为端侧/边缘设备做的深度架构优化+可变长度推理+隐私原生+多语言强适配
人工智能·ai智能体·openclaw