记忆系统

📚 学习路径:本文档是架构文档的第 8 部分。建议按顺序阅读:

前言

记忆系统是 OpenClaw 的长期记忆组件,负责存储、索引和检索对话历史中的重要信息。本文档将深入解析记忆系统的设计、存储结构和检索机制。

通过阅读本文档,你将能够:

  • 理解记忆系统的概念和作用
  • 掌握记忆存储结构和格式
  • 了解混合检索机制
  • 理解记忆管理和优化策略

一、记忆系统概述

1.1 什么是记忆?

记忆(Memory)是指 Agent 的长期记忆,用于存储和检索对话历史中的重要信息,包括:

  • 对话摘要:对话的摘要和关键信息
  • 用户偏好:用户的喜好和习惯
  • 重要事实:用户提到的重要事实和信息
  • 任务记录:完成的任务和待办事项

1.2 记忆 vs 会话

记忆特点

会话特点

记忆 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

字段类型说明
idTEXT记忆 ID
session_keyTEXT关联的会话键
contentTEXT记忆内容
typeTEXT记忆类型(fact/preference/task/summary)
importanceREAL重要性评分(0-1)
created_atTEXT创建时间
updated_atTEXT更新时间

表:keywords

字段类型说明
idTEXT关键词 ID
memory_idTEXT关联的记忆 ID
keywordTEXT关键词
frequencyINTEGER词频

2.3 向量数据库结构

表:embeddings

字段类型说明
idTEXT嵌入 ID
memory_idTEXT关联的记忆 ID
vectorBLOB嵌入向量(二进制)
modelTEXT使用的嵌入模型
created_atTEXT创建时间

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 支持的模型

模型类型提供商特点适用场景
openaiOpenAI高质量嵌入,API 依赖通用场景
geminiGoogle多语言支持,API 依赖多语言场景
mistralMistral AI开源模型,平衡性能和质量本地部署
ollama本地完全离线,隐私友好隐私敏感场景
local本地基于 llama.cpp,完全离线完全离线场景
voyageVoyage 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记忆存储⭐⭐⭐⭐

七、下一步

恭喜你完成了记忆系统的学习!接下来建议:


通过理解记忆系统的工作原理,你已经掌握了 OpenClaw 的长期记忆管理!

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐