OpenClaw 学习系列之十:记忆系统
记忆系统是 OpenClaw 的长期记忆组件,负责存储、索引和检索对话历史中的重要信息。本文档将深入解析记忆系统的设计、存储结构和检索机制。理解记忆系统的概念和作用掌握记忆存储结构和格式了解混合检索机制理解记忆管理和优化策略✅对话摘要:对话的摘要和关键信息✅用户偏好:用户的喜好和习惯✅重要事实:用户提到的重要事实和信息✅任务记录:完成的任务和待办事项。
·
记忆系统
📚 学习路径:本文档是架构文档的第 8 部分。建议按顺序阅读:
- 01. 技术基础 - 了解 TypeScript 技术特性
- 02. 整体框架 - 理解 OpenClaw 架构
- 03. 消息流转 - 掌握消息生命周期
- 04. 设计原理 - 理解反共识设计
- 05. Gateway 深度解析 - 理解控制平面
- 06. Agent 运行机制 - 了解 Agent 如何工作
- 07. 会话管理 - 理解会话生命周期
前言
记忆系统是 OpenClaw 的长期记忆组件,负责存储、索引和检索对话历史中的重要信息。本文档将深入解析记忆系统的设计、存储结构和检索机制。
通过阅读本文档,你将能够:
- 理解记忆系统的概念和作用
- 掌握记忆存储结构和格式
- 了解混合检索机制
- 理解记忆管理和优化策略
一、记忆系统概述
1.1 什么是记忆?
记忆(Memory)是指 Agent 的长期记忆,用于存储和检索对话历史中的重要信息,包括:
- ✅ 对话摘要:对话的摘要和关键信息
- ✅ 用户偏好:用户的喜好和习惯
- ✅ 重要事实:用户提到的重要事实和信息
- ✅ 任务记录:完成的任务和待办事项
1.2 记忆 vs 会话
| 维度 | 会话 | 记忆 |
|---|---|---|
| 类型 | 短期记忆 | 长期记忆 |
| 内容 | 完整对话历史 | 摘要和关键信息 |
| 范围 | 会话级别 | 全局级别 |
| 更新 | 实时更新 | 定期更新 |
| 存储 | JSONL 文件 | SQLite + 向量数据库 |
| 检索 | 按时间顺序 | 语义搜索 + 关键词搜索 |
1.3 记忆的作用
| 作用 | 说明 | 实现方式 |
|---|---|---|
| 上下文增强 | 为 Agent 提供相关历史信息 | 语义检索 |
| 个性化体验 | 记住用户的偏好和习惯 | 用户画像 |
| 知识积累 | 积累重要的事实和信息 | 事实提取 |
| 跨会话记忆 | 跨越不同会话的记忆 | 全局索引 |
二、记忆存储结构
2.1 物理存储路径
~/.openclaw/memory/
├── memory.db # SQLite 数据库
├── embeddings.db # 向量嵌入数据库
└── cache/ # 嵌入缓存
└── <hash>.json # 嵌入缓存文件
说明:
memory.db:SQLite 数据库,存储记忆元数据和关键词索引embeddings.db:向量数据库,存储嵌入向量cache/:嵌入缓存,避免重复计算
2.2 SQLite 数据库结构
表:memories
| 字段 | 类型 | 说明 |
|---|---|---|
id |
TEXT | 记忆 ID |
session_key |
TEXT | 关联的会话键 |
content |
TEXT | 记忆内容 |
type |
TEXT | 记忆类型(fact/preference/task/summary) |
importance |
REAL | 重要性评分(0-1) |
created_at |
TEXT | 创建时间 |
updated_at |
TEXT | 更新时间 |
表:keywords
| 字段 | 类型 | 说明 |
|---|---|---|
id |
TEXT | 关键词 ID |
memory_id |
TEXT | 关联的记忆 ID |
keyword |
TEXT | 关键词 |
frequency |
INTEGER | 词频 |
2.3 向量数据库结构
表:embeddings
| 字段 | 类型 | 说明 |
|---|---|---|
id |
TEXT | 嵌入 ID |
memory_id |
TEXT | 关联的记忆 ID |
vector |
BLOB | 嵌入向量(二进制) |
model |
TEXT | 使用的嵌入模型 |
created_at |
TEXT | 创建时间 |
2.4 记忆数据示例
{
"id": "mem_abc123",
"sessionKey": "agent:main:telegram:default:dm:123456789",
"content": "用户喜欢简洁的回答,不喜欢长篇大论",
"type": "preference",
"importance": 0.9,
"createdAt": "2024-01-01T12:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z"
}
三、混合检索机制
3.1 检索流程
3.2 向量搜索
代码位置:src/memory/vector-search.ts
export async function vectorSearch(
query: string,
options: VectorSearchOptions,
): Promise<MemoryResult[]> {
// 1. 生成查询嵌入
const queryEmbedding = await generateEmbedding(query);
// 2. 在向量数据库中搜索
const results = await vectorDb.search({
vector: queryEmbedding,
limit: options.limit || 10,
filter: options.filter,
});
// 3. 返回结果
return results.map(result => ({
memoryId: result.memoryId,
score: result.score,
memory: await loadMemory(result.memoryId),
}));
}
3.3 关键词搜索
代码位置:src/memory/keyword-search.ts
export async function keywordSearch(
query: string,
options: KeywordSearchOptions,
): Promise<MemoryResult[]> {
// 1. 提取查询关键词
const keywords = extractKeywords(query);
// 2. 在 SQLite 中搜索
const results = await sqliteDb.search({
keywords,
limit: options.limit || 10,
filter: options.filter,
});
// 3. 返回结果
return results.map(result => ({
memoryId: result.memoryId,
score: result.score,
memory: await loadMemory(result.memoryId),
}));
}
3.4 结果融合
代码位置:src/memory/hybrid.ts
export function mergeHybridResults(
vectorResults: MemoryResult[],
keywordResults: MemoryResult[],
alpha = 0.7,
): MemoryResult[] {
// 1. 合并结果
const merged = new Map<string, MemoryResult>();
// 2. 处理向量搜索结果
for (const result of vectorResults) {
merged.set(result.memoryId, {
...result,
score: result.score * alpha,
});
}
// 3. 处理关键词搜索结果
for (const result of keywordResults) {
const existing = merged.get(result.memoryId);
if (existing) {
// 加权融合
existing.score = existing.score + result.score * (1 - alpha);
} else {
merged.set(result.memoryId, {
...result,
score: result.score * (1 - alpha),
});
}
}
// 4. 排序并返回
return Array.from(merged.values())
.sort((a, b) => b.score - a.score);
}
融合算法:
最终得分 = 向量搜索得分 × α + 关键词搜索得分 × (1 - α)
参数说明:
alpha:向量搜索权重(默认 0.7)1 - alpha:关键词搜索权重(默认 0.3)
四、嵌入模型
4.1 支持的模型
| 模型类型 | 提供商 | 特点 | 适用场景 |
|---|---|---|---|
| openai | OpenAI | 高质量嵌入,API 依赖 | 通用场景 |
| gemini | 多语言支持,API 依赖 | 多语言场景 | |
| mistral | Mistral AI | 开源模型,平衡性能和质量 | 本地部署 |
| ollama | 本地 | 完全离线,隐私友好 | 隐私敏感场景 |
| local | 本地 | 基于 llama.cpp,完全离线 | 完全离线场景 |
| voyage | Voyage AI | 长文本嵌入能力 | 长文本场景 |
4.2 嵌入生成
代码位置:src/memory/embedding-provider.ts
export async function generateEmbedding(
text: string,
options: EmbeddingOptions,
): Promise<number[]> {
// 1. 检查缓存
const cacheKey = hashText(text);
const cached = await loadFromCache(cacheKey);
if (cached) {
return cached;
}
// 2. 生成嵌入
const provider = resolveEmbeddingProvider(options.provider);
const embedding = await provider.embed(text);
// 3. 保存到缓存
await saveToCache(cacheKey, embedding);
// 4. 返回嵌入
return embedding;
}
4.3 嵌入缓存
代码位置:src/memory/embedding-cache.ts
export class EmbeddingCache {
private cache = new Map<string, number[]>();
async get(key: string): Promise<number[] | undefined> {
// 1. 检查内存缓存
const cached = this.cache.get(key);
if (cached) {
return cached;
}
// 2. 检查磁盘缓存
const cachePath = resolveCachePath(key);
if (await fs.exists(cachePath)) {
const content = await fs.readFile(cachePath, 'utf-8');
const embedding = JSON.parse(content);
this.cache.set(key, embedding);
return embedding;
}
return undefined;
}
async set(key: string, embedding: number[]): Promise<void> {
// 1. 保存到内存缓存
this.cache.set(key, embedding);
// 2. 保存到磁盘缓存
const cachePath = resolveCachePath(key);
await fs.writeFile(cachePath, JSON.stringify(embedding), 'utf-8');
}
}
五、记忆管理
5.1 记忆创建
代码位置:src/memory/memory-manager.ts
export async function createMemory(
content: string,
options: CreateMemoryOptions,
): Promise<Memory> {
// 1. 生成记忆 ID
const memoryId = generateMemoryId();
// 2. 提取记忆类型
const type = await classifyMemoryType(content);
// 3. 计算重要性
const importance = await calculateImportance(content);
// 4. 生成嵌入
const embedding = await generateEmbedding(content);
// 5. 保存到数据库
const memory: Memory = {
id: memoryId,
sessionKey: options.sessionKey,
content,
type,
importance,
createdAt: new Date(),
updatedAt: new Date(),
};
await saveMemory(memory);
await saveEmbedding(memoryId, embedding);
// 6. 提取关键词
const keywords = await extractKeywords(content);
await saveKeywords(memoryId, keywords);
return memory;
}
5.2 记忆更新
export async function updateMemory(
memoryId: string,
updates: Partial<Memory>,
): Promise<void> {
// 1. 加载现有记忆
const memory = await loadMemory(memoryId);
// 2. 更新字段
const updated = {
...memory,
...updates,
updatedAt: new Date(),
};
// 3. 保存更新
await saveMemory(updated);
// 4. 如果内容变化,重新生成嵌入
if (updates.content) {
const embedding = await generateEmbedding(updates.content);
await saveEmbedding(memoryId, embedding);
// 重新提取关键词
const keywords = await extractKeywords(updates.content);
await saveKeywords(memoryId, keywords);
}
}
5.3 记忆删除
export async function deleteMemory(memoryId: string): Promise<void> {
// 1. 删除记忆
await sqliteDb.delete('memories', { id: memoryId });
// 2. 删除嵌入
await vectorDb.delete({ memoryId });
// 3. 删除关键词
await sqliteDb.delete('keywords', { memoryId });
}
5.4 记忆清理
export async function cleanupMemories(options: CleanupOptions): Promise<CleanupResult> {
const result: CleanupResult = {
deleted: 0,
archived: 0,
};
// 1. 删除低重要性记忆
if (options.deleteLowImportance) {
const lowImportance = await findLowImportanceMemories(options.threshold);
for (const memory of lowImportance) {
await deleteMemory(memory.id);
result.deleted++;
}
}
// 2. 归档旧记忆
if (options.archiveOld) {
const oldMemories = await findOldMemories(options.days);
for (const memory of oldMemories) {
await archiveMemory(memory.id);
result.archived++;
}
}
return result;
}
六、核心代码文件索引
| 文件路径 | 功能 | 重要性 |
|---|---|---|
| src/memory/hybrid.ts | 混合检索 | ⭐⭐⭐⭐⭐ |
| src/memory/vector-search.ts | 向量搜索 | ⭐⭐⭐⭐⭐ |
| src/memory/keyword-search.ts | 关键词搜索 | ⭐⭐⭐⭐⭐ |
| src/memory/embedding-provider.ts | 嵌入提供者 | ⭐⭐⭐⭐ |
| src/memory/embedding-cache.ts | 嵌入缓存 | ⭐⭐⭐⭐ |
| src/memory/memory-manager.ts | 记忆管理器 | ⭐⭐⭐⭐⭐ |
| src/memory/memory-store.ts | 记忆存储 | ⭐⭐⭐⭐ |
七、下一步
恭喜你完成了记忆系统的学习!接下来建议:
- 📖 阅读 09. 并发控制 - 了解并发管理系统
- 🔄 查看 03. 消息流转 - 理解完整消息流程
- 🛠️ 探索 message_flow/ - 查看详细步骤文档
通过理解记忆系统的工作原理,你已经掌握了 OpenClaw 的长期记忆管理!
更多推荐




所有评论(0)