【Agent Memory篇】01:OpenClaw整体架构与设计哲学
文章目录
- 一. 引言:为什么要关注 OpenClaw 的记忆实现?🔍
- 二. 设计哲学:“文件即记忆” 📝
- 三. 整体架构总览 🏗️
- 四. 记忆的生命周期 🔄
- 五. 关键设计决策剖析 🎯
- 六. 核心类继承体系 🧬
- 七. 配置体系详解 ⚙️
- 八. 与同类系统的架构对比 📊
- 九. 小结与下篇预告 📢
- 参考文献

一. 引言:为什么要关注 OpenClaw 的记忆实现?🔍
在 Agent Memory 领域,大多数系统要么走云端托管路线(Mem0、Zep),要么走纯学术实验路线(ASMR)。OpenClaw 的记忆系统走了一条独特的中间路线:完全本地化、生产可用、工程成熟度高。
它的独特之处在于:
- 没有外部依赖:不需要 Redis、Pinecone 或任何外部向量数据库,一个 SQLite 文件搞定一切 🏠
- 人机协同:记忆以 Markdown 文件形式存在,人类和 AI 都可以直接读写 ✍️
- 渐进增强:即使没有 Embedding API,也能通过纯 FTS 全文搜索工作 📉→📈
- 多语言支持:内置中、英、日、韩、阿、葡、西 8 种语言的查询优化 🌍
作为一个已经在生产环境中服务大量用户的系统,它的工程实践非常值得学习。
二. 设计哲学:“文件即记忆” 📝
2.1 人机协同的记忆模型
OpenClaw 的记忆设计深受 Unix 哲学影响——一切皆文件。
Agent 的记忆不是存在某个黑盒数据库里,而是以人类可读的 Markdown 文件形式存在:
workspace/
├── MEMORY.md # 长期记忆(精炼的核心知识)
├── USER.md # 用户画像
├── memory/
│ ├── 2026-03-23.md # 每日笔记
│ ├── 2026-03-22.md
│ └── ...
这种设计带来的好处是:
- 透明性:用户可以随时打开文件查看 AI 记住了什么 👁️
- 可编辑性:用户可以直接修改错误的记忆 ✏️
- 版本控制:可以用 Git 追踪记忆的变化历史 📜
- 可移植性:换一个 Agent 框架,记忆文件照样可用 🔄
2.2 隐私优先的本地化架构
OpenClaw 的整个记忆系统运行在本地:
- 存储:SQLite 数据库存在
~/.openclaw/state/memory/目录下 - 索引:所有 chunk 和 embedding 都存在本地 SQLite
- 检索:全文搜索(FTS5)完全本地运行
- 可选的远程组件:仅 Embedding API 调用需要网络(且可用本地模型替代)
┌─────────────────────────────────────────┐
│ 本地 (全部在本机) │
│ ┌─────────┐ ┌──────────┐ ┌────────┐ │
│ │ .md文件 │→│ SQLite │→│ FTS5 │ │
│ │ │ │ + chunks │ │ 全文索引│ │
│ └─────────┘ └──────────┘ └────────┘ │
│ ↕ │
│ ┌──────────┐ │
│ │sqlite-vec│ │
│ │ 向量索引 │ │
│ └──────────┘ │
└─────────────────────────────────────────┘
↕ (仅 Embedding 调用)
┌─────────────────────────────────────────┐
│ 远程 API (可选,可用本地模型替代) │
│ OpenAI / Gemini / Voyage / Mistral │
│ Ollama (本地) / node-llama-cpp (本地) │
└─────────────────────────────────────────┘
2.3 渐进增强:从纯文本到语义搜索
OpenClaw 的记忆系统支持三个渐进的能力等级:
| 等级 | 条件 | 检索能力 |
|---|---|---|
| Level 0 | 无 Embedding API | 纯 FTS 全文检索(关键词匹配) |
| Level 1 | 有 Embedding API | 向量语义检索 |
| Level 2 | Embedding + FTS | Hybrid Search(向量 + 全文混合检索) ✅ |
这意味着即使用户没有配置任何 API key,记忆搜索功能依然可用——只是从语义理解降级为关键词匹配。从源码中可以看到这段逻辑:
// manager.ts - search() 方法
if (!this.provider) {
// FTS-only mode: no embedding provider available
if (!this.fts.enabled || !this.fts.available) {
return [];
}
// Extract keywords for better FTS matching
const keywords = extractKeywords(cleaned);
// ...
}
三. 整体架构总览 🏗️
3.1 数据流全景图
用户/Agent 写入 Markdown 文件
│
▼
┌──────────────┐
│ 文件监听器 │ chokidar (watch 模式)
│ (Watcher) │ 支持 debounce (1500ms)
└──────┬───────┘
│ 文件变化事件
▼
┌──────────────┐
│ 同步引擎 │ manager-sync-ops.ts
│ (Sync) │ 增量同步,hash 比对
└──────┬───────┘
│
┌─────┴──────┐
▼ ▼
┌────────┐ ┌────────────┐
│ 分块 │ │ Embedding │
│(Chunk) │ │ (多提供商) │
│400 tok │ │ │
│overlap │ │ OpenAI │
│80 tok │ │ Gemini │
└───┬────┘ │ Voyage │
│ │ Mistral │
│ │ Ollama │
│ │ Local │
│ └─────┬──────┘
│ │
▼ ▼
┌──────────────────────┐
│ SQLite 存储 │
│ │
│ files 表 (文件元数据)│
│ chunks 表 (分块+向量) │
│ chunks_fts (FTS5索引) │
│ chunks_vec (向量索引) │
│ embedding_cache │
└──────────┬───────────┘
│
▼ 用户查询到来
┌──────────────────────┐
│ Hybrid Search │
│ │
│ 向量检索 (70%权重) │
│ + FTS检索 (30%权重) │
│ → 融合排序 │
│ → MMR去重 │
│ → 时序衰减 │
│ → 引用溯源 │
└──────────┬───────────┘
│
▼
注入 LLM 上下文
3.2 核心模块清单
基于源码 src/memory/ 目录,OpenClaw 的记忆系统由以下核心模块组成:
| 模块 | 文件 | 职责 |
|---|---|---|
| 管理器 | manager.ts |
核心入口,单例管理,搜索调度 |
| 同步操作 | manager-sync-ops.ts |
文件监听、增量同步、分块、索引 |
| Embedding操作 | manager-embedding-ops.ts |
向量嵌入、批处理、重试、缓存 |
| 搜索操作 | manager-search.ts |
向量检索、FTS 检索实现 |
| 混合检索 | hybrid.ts |
向量 + FTS 结果融合排序 |
| MMR去重 | mmr.ts |
最大边际相关性重排序 |
| 时序衰减 | temporal-decay.ts |
基于时间的分数衰减 |
| 查询扩展 | query-expansion.ts |
多语言停用词、关键词提取 |
| 数据库Schema | memory-schema.ts |
SQLite 表结构定义 |
| 向量扩展 | sqlite-vec.ts |
sqlite-vec 加载和管理 |
| Embedding提供商 | embeddings-*.ts |
6 种 Embedding 提供商适配 |
| 会话记忆 | session-files.ts |
从对话历史中提取记忆 |
| 批量嵌入 | batch-*.ts |
OpenAI/Gemini/Voyage 批量 API |
| 多模态 | multimodal.ts |
图片等非文本记忆支持 |
3.3 文件组织结构
src/memory/
├── manager.ts # 🎯 核心管理器(入口)
├── manager-sync-ops.ts # 同步操作基类
├── manager-embedding-ops.ts # Embedding 操作
├── manager-search.ts # 搜索实现
├── manager-runtime.ts # 运行时辅助
│
├── hybrid.ts # 🔀 Hybrid Search 融合
├── mmr.ts # 🎲 MMR 去重排序
├── temporal-decay.ts # ⏰ 时序衰减
├── query-expansion.ts # 🌍 多语言查询扩展
│
├── memory-schema.ts # 📊 数据库 Schema
├── sqlite.ts # SQLite 工具
├── sqlite-vec.ts # sqlite-vec 向量扩展
│
├── embeddings.ts # Embedding 提供商工厂
├── embeddings-openai.ts # OpenAI Embedding
├── embeddings-gemini.ts # Gemini Embedding
├── embeddings-voyage.ts # Voyage Embedding
├── embeddings-mistral.ts # Mistral Embedding
├── embeddings-ollama.ts # Ollama Embedding
├── node-llama.ts # 本地 GGUF 模型
│
├── batch-*.ts # 批量 Embedding 处理
├── session-files.ts # 会话记忆提取
├── multimodal.ts # 多模态支持
├── internal.ts # 内部工具函数
├── fs-utils.ts # 文件系统工具
└── types.ts # 类型定义
四. 记忆的生命周期 🔄
4.1 写入阶段:记忆的诞生
记忆的写入有两种方式:
方式一:Agent 自主写入
Agent 在对话过程中通过文件操作工具(write/edit)直接写入 Markdown 文件。例如:
<!-- Agent 写入 memory/2026-03-23.md -->
## 今日记录
- 主人对 ASMR (Supermemory) 的多Agent记忆系统很感兴趣
- 需要为 Agent Memory 综述博客生成封面图
- 主人的 CSDN 博客风格:结构化强、技术深入、有emoji
方式二:用户手动编辑
用户直接打开 MEMORY.md 或 daily notes 进行编辑。系统通过文件监听自动感知变化。
4.2 索引阶段:从文本到向量
当文件发生变化时,同步引擎自动触发索引流程:
- 文件发现:Watcher 检测到
.md文件变化 - Hash 比对:通过文件 hash 判断是否需要重新索引
- 分块(Chunking):将文件内容按 400 tokens 分块,重叠 80 tokens
- Embedding:调用提供商 API 将每个 chunk 转为向量
- 存储:向量和文本同时写入 SQLite 的
chunks表和chunks_ftsFTS5 虚拟表
4.3 检索阶段:Hybrid Search
当用户提问触发记忆搜索时:
- 向量检索:将查询 Embedding 后,在
chunks_vec表中做 KNN 搜索 - FTS 检索:构建 FTS5 查询,进行全文匹配
- 融合排序:按
0.7 * vectorScore + 0.3 * textScore加权合并 - 后处理:MMR 去重 → 时序衰减 → 分数过滤 → 截断返回
4.4 呈现阶段:注入 LLM 上下文
搜索结果以结构化 JSON 返回给 Agent,包含:
snippet:匹配的文本片段(最大 700 字符)path:来源文件路径startLine/endLine:行号范围score:综合得分citation:引用标记(如Source: memory/2026-03-23.md#L12-L20)
五. 关键设计决策剖析 🎯
5.1 为什么选 SQLite 而不是专业向量数据库?
OpenClaw 选择 SQLite + sqlite-vec 扩展 而非 Pinecone/Weaviate/Qdrant 等专业向量数据库,原因包括:
- 零部署成本:SQLite 是嵌入式数据库,无需启动独立服务 🚀
- 单文件存储:整个记忆索引是一个
.sqlite文件,备份/迁移极简 📦 - 无网络依赖:完全本地运行,保障隐私 🔒
- 事务支持:SQLite 原生支持 ACID 事务,保证数据一致性 ✅
当然,这个选择也有代价——sqlite-vec 的性能不如专业向量数据库。但对于个人 Agent 的记忆规模(通常几千到几万条 chunks),SQLite 完全够用。
5.2 为什么用 Markdown 文件而不是数据库直存?
直接把记忆存入数据库是更"干净"的方案,但 OpenClaw 坚持以文件为主的原因是:
- 人机协同:用户可以用任何文本编辑器查看和修改记忆
- Git 友好:可以把记忆文件纳入版本控制
- Framework 无关:记忆文件不依赖 OpenClaw 的格式,换框架也能用
- 调试友好:出问题时直接看文件就知道 Agent 记住了什么
数据库(SQLite)只是索引层——真正的记忆存在于文件中,数据库可以随时重建。
5.3 FTS-Only 降级模式:无 Embedding 也能用
这是一个非常巧妙的设计。当用户没有配置任何 Embedding API 时,系统自动降级为纯 FTS 搜索模式,并启用查询扩展机制来弥补语义理解的不足:
// query-expansion.ts
// 将对话式查询转为关键词
// "之前讨论的那个方案" → ["讨论", "方案"]
// "that thing we discussed about the API" → ["discussed", "API"]
export function extractKeywords(query: string): string[] {
const tokens = tokenize(query);
return tokens.filter(t => !isQueryStopWordToken(t) && isValidKeyword(t));
}
该模块内置了 中、英、日、韩、阿、西、葡 7 种语言的停用词表,确保跨语言场景下的查询质量。
5.4 多 Embedding 提供商支持的工程考量
OpenClaw 支持 6 种 Embedding 提供商,并通过 auto 模式自动选择最佳提供商:
| 提供商 | 默认模型 | 特点 |
|---|---|---|
| OpenAI | text-embedding-3-small |
最成熟、生态最好 |
| Gemini | gemini-embedding-001 |
支持多模态(图片Embedding) |
| Voyage | voyage-4-large |
高精度、专业级 |
| Mistral | mistral-embed |
欧洲替代方案 |
| Ollama | nomic-embed-text |
完全本地,无需API |
| Local | embeddinggemma-300m |
GGUF 模型,通过 node-llama-cpp |
还支持降级回退(Fallback):如果主提供商不可用,自动切换到备选提供商。
六. 核心类继承体系 🧬
OpenClaw 的记忆管理器采用三层继承结构,职责分明:
MemoryManagerSyncOps (manager-sync-ops.ts)
│ 职责:文件监听、同步、分块、索引
│ 方法:ensureWatcher(), runSync(), indexFile()
▼
MemoryManagerEmbeddingOps (manager-embedding-ops.ts)
│ 职责:Embedding 计算、批处理、缓存、重试
│ 方法:embedBatchWithRetry(), embedQueryWithTimeout()
▼
MemoryIndexManager (manager.ts)
│ 职责:对外暴露搜索接口、状态管理、生命周期
│ 方法:search(), readFile(), status(), close()
▼
实现 MemorySearchManager 接口
6.1 MemoryManagerSyncOps:同步操作基类
负责最底层的文件操作:
- 文件监听:使用 chokidar 监听 workspace 下的
.md文件变化,debounce 1500ms - 增量同步:通过文件 hash 比对,只重新索引变化的文件
- 分块策略:默认 400 tokens 一块,重叠 80 tokens,确保语义连贯
- 会话监听:监听 session transcript 文件变化,支持对话历史记忆化
6.2 MemoryManagerEmbeddingOps:Embedding 操作层
负责向量计算相关的所有操作:
- 批量嵌入:支持 OpenAI/Gemini/Voyage 的 batch API,降低成本
- Embedding 缓存:
embedding_cache表缓存已计算的向量,避免重复计算 - 超时处理:embedQueryWithTimeout 确保单次查询不会无限等待
- 错误重试:网络错误、限流(429)自动重试
6.3 MemoryIndexManager:面向外部的完整管理器
最终暴露给上层的管理器,实现 MemorySearchManager 接口:
interface MemorySearchManager {
search(query: string, opts?): Promise<MemorySearchResult[]>;
readFile(params): Promise<{ text: string; path: string }>;
status(): MemoryProviderStatus;
sync?(params?): Promise<void>;
probeEmbeddingAvailability(): Promise<MemoryEmbeddingProbeResult>;
probeVectorAvailability(): Promise<boolean>;
close?(): Promise<void>;
}
关键设计:单例模式 + 缓存。通过 INDEX_CACHE Map 确保每个 agentId 只有一个管理器实例,避免重复创建数据库连接。
七. 配置体系详解 ⚙️
7.1 ResolvedMemorySearchConfig 配置结构
OpenClaw 的记忆系统拥有极其细粒度的配置能力:
type ResolvedMemorySearchConfig = {
enabled: boolean; // 是否启用
sources: Array<"memory" | "sessions">; // 数据来源
extraPaths: string[]; // 额外监听路径
provider: "openai" | "gemini" | ... | "auto"; // Embedding 提供商
store: {
driver: "sqlite";
path: string; // SQLite 文件路径
vector: { enabled: boolean; extensionPath?: string };
};
chunking: {
tokens: number; // 分块大小 (默认400)
overlap: number; // 重叠大小 (默认80)
};
sync: {
onSessionStart: boolean; // 会话开始时同步
onSearch: boolean; // 搜索时同步
watch: boolean; // 文件监听
watchDebounceMs: number; // 监听防抖 (默认1500ms)
intervalMinutes: number; // 定期同步间隔
};
query: {
maxResults: number; // 最大返回结果数 (默认6)
minScore: number; // 最低分数阈值 (默认0.35)
hybrid: {
enabled: boolean;
vectorWeight: number; // 向量权重 (默认0.7)
textWeight: number; // 文本权重 (默认0.3)
candidateMultiplier: number; // 候选倍数 (默认4)
mmr: { enabled: boolean; lambda: number };
temporalDecay: { enabled: boolean; halfLifeDays: number };
};
};
cache: { enabled: boolean; maxEntries?: number };
};
7.2 关键配置项速查表
| 配置项 | 默认值 | 说明 |
|---|---|---|
chunking.tokens |
400 | 每个 chunk 的 token 数 |
chunking.overlap |
80 | chunk 之间的重叠 token 数 |
query.maxResults |
6 | 每次搜索最多返回的结果数 |
query.minScore |
0.35 | 最低相关性分数阈值 |
query.hybrid.vectorWeight |
0.7 | 向量检索权重 |
query.hybrid.textWeight |
0.3 | 全文检索权重 |
query.hybrid.mmr.lambda |
0.7 | MMR 多样性参数(0=纯多样性,1=纯相关性) |
query.hybrid.temporalDecay.halfLifeDays |
30 | 时序衰减半衰期(天) |
sync.watchDebounceMs |
1500 | 文件变化后等待多久再同步 |
八. 与同类系统的架构对比 📊
| 维度 | OpenClaw | Mem0 | Zep | Letta |
|---|---|---|---|---|
| 存储 | SQLite (本地) | 向量DB + 图谱 (云) | PostgreSQL (云) | 分层内存 |
| 索引 | sqlite-vec + FTS5 | 云端向量索引 | 云端 | 内置 |
| 文件可读 | ✅ Markdown | ❌ | ❌ | 部分 |
| 零依赖 | ✅ | ❌ 需要云服务 | ❌ 需要PG | 部分 |
| 降级能力 | ✅ FTS-only | ❌ | ❌ | ❌ |
| 多语言FTS | ✅ 8种语言 | ❌ | ❌ | ❌ |
| 多模态 | ✅ 图片 | ❌ | ❌ | ❌ |
九. 小结与下篇预告 📢
本文从宏观层面梳理了 OpenClaw 记忆系统的设计哲学和整体架构。核心要点回顾:
- “文件即记忆” 的设计哲学,实现人机协同 📝
- SQLite + sqlite-vec + FTS5 的全本地存储栈 🏠
- 渐进增强 的三级能力模型(FTS-only → 向量 → Hybrid)📈
- 三层继承 的管理器架构(Sync → Embedding → Index)🧬
参考文献
- OpenClaw 源码:github.com/openclaw/openclaw —
src/memory/目录 - sqlite-vec:github.com/asg017/sqlite-vec — SQLite 向量扩展
- SQLite FTS5:sqlite.org/fts5.html — 全文搜索引擎
- chokidar:github.com/paulmillr/chokidar — 文件监听库
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)