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。
相关推荐
JaguarJack8 小时前
OpenClaw 最新保姆级飞书对接指南教程 搭建属于你的 AI 助手
ai·clawdbot·openclaw
行者无疆_ty10 小时前
什么是Node.js,跟OpenCode/OpenClaw有什么关系?
人工智能·node.js·openclaw
有时.不昰沉默12 小时前
【linux系统】安装并启动openclaw只需要两条命令
大模型·openclaw·clawbot
Elwin Wong14 小时前
浅析OpenClaw:从“贾维斯”梦想看下一代 AI 操作系统的架构演进
人工智能·agent·clawdbot·moltbot·openclaw
DFCED14 小时前
OpenClaw部署实战:5分钟搭建你的专属AI数字员工(附避坑指南)
人工智能·大模型·agent·openclaw
csdn_life181 天前
openclaw mcporter 操作 chome 在 window10 chrome-devtools-mcp 第2版本
openclaw
csdn_life181 天前
openclaw mcporter 操作 chome 在 window10/linux chrome-devtools-mcp
chrome·mcp·openclaw
智星云算力2 天前
OpenClaw打工人高效摸鱼攻略(6个实用skills)
gpu算力·智星云·gpu服务器·openclaw·crawdbot
穆友航3 天前
配置 OpenClaw 使用 Ollama 本地模型
大模型·ollama·openclaw