乐于分享
好东西不私藏

OpenClaw 记忆召回系统:置信度计算与混合搜索机制

OpenClaw 记忆召回系统:置信度计算与混合搜索机制

一、记忆召回置信度计算与使用

1.1置信度计算方法

OpenClaw 的记忆召回系统使用多种方法计算置信度,主要包括:

1. 向量搜索置信度

  • • 基于嵌入向量相似度:使用余弦相似度计算查询向量与文档向量之间的相似性
  • • 实现位置src/memory/manager-search.ts 中的 searchVector 函数
  • • 范围:0-1,值越高表示相似度越高

2. 关键词搜索置信度

  • • 基于 BM25 算法:通过 bm25RankToScore 函数将 BM25 排名转换为 0-1 之间的分数
  • • 实现位置src/memory/hybrid.ts 中的 bm25RankToScore 函数
  • • 范围:0-1,值越高表示关键词匹配度越高

3. 混合搜索置信度

  • • 加权平均:结合向量搜索和关键词搜索的结果
  • • 权重配置
    • • 向量权重 (vectorWeight):默认为 0.7
    • • 文本权重 (textWeight):默认为 0.3
  • • 实现位置src/memory/hybrid.ts 中的 mergeHybridResults 函数

置信度的使用方式

1. 阈值过滤

  • • 最小置信度阈值:默认为 0.35 (DEFAULT_MIN_SCORE)
  • • 过滤逻辑:搜索结果会过滤掉低于此阈值的条目
  • • 实现位置src/memory/manager.ts 中的 search 方法

2. 搜索模式处理

  • • 混合模式:同时使用向量和关键词搜索,结合两者的置信度
  • • 仅 FTS 模式:当没有嵌入提供者时,仅使用关键词搜索
  • • 向量模式:当 FTS 不可用时,仅使用向量搜索

3. 结果排序与限制

  • • 排序:按置信度分数降序排列
  • • 限制:最多返回 maxResults 个结果(默认为 6)
  • • 候选结果:先获取更多候选结果(maxResults * candidateMultiplier),然后进行过滤

4. 特殊处理

  • • 关键词匹配调整:当混合模式下没有符合阈值的结果时,会适当放宽阈值以保留纯关键词匹配的结果
  • • 时间衰减:可选启用时间衰减功能,降低旧文档的置信度

1.2配置参数

参数
默认值
说明
位置
minScore
0.35
最小置信度阈值
src/agents/memory-search.ts:93
vectorWeight
0.7
向量搜索权重
src/agents/memory-search.ts:95
textWeight
0.3
关键词搜索权重
src/agents/memory-search.ts:96
maxResults
6
最大结果数
src/agents/memory-search.ts:92
candidateMultiplier
4
候选结果乘数
src/agents/memory-search.ts:97

搜索流程

  1. 1. 查询处理:清理查询文本
  2. 2. 同步检查:如果启用了搜索时同步,执行内存同步
  3. 3. 模式判断
    • • 无嵌入提供者:使用仅 FTS 模式
    • • FTS 不可用:使用仅向量模式
    • • 两者都可用:使用混合模式
  4. 4. 执行搜索
    • • 向量搜索:计算嵌入向量并执行相似性搜索
    • • 关键词搜索:使用 FTS 执行关键词匹配
  5. 5. 结果合并
    • • 混合模式:加权合并两种结果
    • • 单一模式:直接使用对应结果
  6. 6. 置信度过滤:过滤掉低于 minScore 的结果
  7. 7. 结果限制:返回前 maxResults 个结果

通过这些机制,OpenClaw 的记忆召回系统能够有效地评估搜索结果的相关性,并根据置信度过滤和排序结果,确保返回最相关的记忆内容。

二、时间衰减功能

2.1核心实现原理

OpenClaw 的时间衰减功能通过指数衰减模型实现,用于降低旧文档的置信度,使搜索结果更加偏向于近期内容。

1. 衰减计算模型

exportfunctioncalculateTemporalDecayMultiplier(params: {
  ageInDays: number;
  halfLifeDays: number;
}
): number {
const lambda = toDecayLambda(params.halfLifeDays);
const clampedAge = Math.max(0, params.ageInDays);
if (lambda <= 0 || !Number.isFinite(clampedAge)) {
return1;
  }
returnMath.exp(-lambda * clampedAge);
}

关键公式

  • • 衰减率计算:lambda = ln(2) / halfLifeDays
  • • 衰减乘数:decay = exp(-lambda * ageInDays)

工作原理

  • • 每经过一个半衰期(halfLifeDays),文档的权重会减少一半
  • • 例如:如果半衰期设置为30天,60天前的文档权重会变为原来的1/4

2. 时间戳提取

系统通过以下方式确定文档的时间戳:

  1. 1. 日期命名的记忆文件
    • • 从文件名提取日期,如 memory/2024-01-01.md
    • • 使用正则表达式 /(?:^|\/)memory\/(\d{4})-(\d{2})-(\d{2})\.md$/ 匹配
  2. 2. 常青知识文件
    • • 根级记忆文件(如 MEMORY.md
    • • 非日期命名的记忆文件
    • • 这些文件被视为"常青"知识,不应用时间衰减
  3. 3. 其他文件
    • • 使用文件系统的修改时间(mtime)

2.2配置参数

参数
默认值
说明
enabled
false
是否启用时间衰减
halfLifeDays
30
半衰期(天),每经过这个时间,文档权重减少一半

2.3工作流程

  1. 1. 搜索执行:执行向量搜索和关键词搜索
  2. 2. 结果合并:计算混合分数(向量得分 * 向量权重 + 文本得分 * 文本权重)
  3. 3. 时间衰减应用
    • • 提取每个结果的时间戳
    • • 计算文档年龄(以天为单位)
    • • 计算衰减乘数
    • • 将衰减乘数应用到混合分数上
  4. 4. 结果排序:按衰减后的分数降序排列
  5. 5. MMR重排序:如果启用,进行多样性重排序

2.4时间衰减的影响

示例:半衰期为30天的情况

文档年龄
衰减乘数
原始分数
衰减后分数
0天(今天)
1.0
0.8
0.8
30天
0.5
0.8
0.4
60天
0.25
0.8
0.2
90天
0.125
0.8
0.1

特殊处理

  1. 1. 常青知识:根级记忆文件和非日期命名的记忆文件不应用时间衰减
  2. 2. 无时间戳文件:无法确定时间戳的文件不应用时间衰减
  3. 3. 时间戳提取失败:如果无法提取时间戳,保持原始分数不变

2.5总结

OpenClaw 的时间衰减功能通过指数衰减模型,根据文档的年龄动态调整其置信度分数,使搜索结果更加偏向于近期内容。这对于需要保持信息新鲜度的场景非常重要,如项目文档、会议记录等。

时间衰减的实现考虑了不同类型文件的特点,对常青知识文件不应用衰减,同时通过灵活的配置参数,允许用户根据具体需求调整衰减速度。

三、记忆召回触发时机与流程分析

3.1触发时机

OpenClaw 的记忆召回主要在以下情况下触发:

1. 显式工具调用

  • • 用户查询触发:当用户提出涉及以下内容的问题时,系统会调用 memory_search 工具
    • • 先前的工作
    • • 决策历史
    • • 日期和时间
    • • 人员信息
    • • 偏好设置
    • • 待办事项

2. 系统自动触发

  • • 强制召回步骤:根据工具描述,记忆搜索是一个"强制召回步骤",在回答问题前自动执行
  • • 搜索时同步:当启用 sync.onSearch 配置时,搜索前会自动同步内存

3. 配置相关触发

  • • 会话启动同步:当启用 sync.onSessionStart 配置时,会话开始时会预热内存
  • • 定时同步:当设置了 sync.intervalMinutes 时,会定期同步内存

3.2召回流程

记忆召回的完整流程如下:

1. 工具注册与初始化

  1. 1. 工具注册memory_search 工具在 tool-catalog.ts 中注册到 "memory" 部分
  2. 2. 工具创建:通过 createMemorySearchTool 函数创建记忆搜索工具实例
  3. 3. 上下文解析:解析配置和代理会话信息,确定是否启用记忆搜索

2. 搜索执行

  1. 1. 参数处理:解析查询文本、最大结果数、最小分数等参数
  2. 2. 管理器获取:调用 getMemorySearchManager 获取内存搜索管理器
  3. 3. 同步检查:如果启用了搜索时同步,执行内存同步
  4. 4. 搜索执行
    • • 向量搜索:计算查询的嵌入向量,执行相似性搜索
    • • 关键词搜索:使用 FTS 执行关键词匹配
    • • 混合模式:结合向量和关键词搜索结果,应用权重计算
    • • 时间衰减:如果启用,应用时间衰减降低旧文档的置信度
    • • MMR重排序:如果启用,进行多样性重排序

3. 结果处理

  1. 1. 引用添加:根据配置添加来源引用
  2. 2. 结果限制:根据字符预算限制结果大小
  3. 3. 状态收集:收集搜索状态信息(提供者、模型、模式等)
  4. 4. 结果返回:返回处理后的搜索结果

4. 错误处理

  • • 管理器不可用:返回内存搜索不可用的错误信息
  • • 搜索失败:捕获并处理搜索过程中的错误
  • • 配额错误:特殊处理嵌入提供者配额耗尽的情况

3.3技术实现细节

1. 搜索模式

  • • 混合模式:同时使用向量和关键词搜索,结合两者的优势
  • • 仅 FTS 模式:当没有嵌入提供者时,仅使用关键词搜索
  • • 向量模式:当 FTS 不可用时,仅使用向量搜索

2. 结果排序与过滤

  • • 置信度过滤:过滤掉低于 minScore 的结果(默认 0.35)
  • • 结果排序:按置信度分数降序排列
  • • 结果限制:最多返回 maxResults 个结果(默认 6)

3. 内存同步

  • • 自动同步:在搜索前和会话启动时自动同步
  • • 文件监听:监控记忆文件的变化,及时更新索引
  • • 会话同步:同步会话记录到内存中

3.4总结

OpenClaw 的记忆召回系统是一个强大的功能,通过语义搜索和关键词搜索的结合,为用户提供了快速访问历史信息的能力。它在用户提出相关问题时自动触发,通过多层次的搜索和处理,返回最相关的记忆内容。

记忆召回的触发时机主要是用户查询涉及历史信息时,流程包括工具调用、搜索执行、结果处理和错误处理等步骤。系统通过灵活的配置选项,允许用户根据具体需求调整记忆搜索的行为。

四、指数衰减模型

关键公式

  • • 衰减率计算:lambda = ln(2) / halfLifeDays
  • • 衰减乘数:decay = exp(-lambda * ageInDays)

这是一个经典的指数衰减模型,广泛应用于放射性衰变、药代动力学、缓存过期等领域。

4.1核心思想

半衰期(Half-life):物质衰减到原来一半所需的时间。

公式设计的目标是:每经过一个半衰期,数值恰好减半

4.2公式拆解

第一步:衰减率 λ 的推导

lambda = ln(2) / halfLifeDays

为什么用 ln(2)?

指数衰减的通式是:N(t) = N₀ * e^(-λt)

要让 t = halfLifeDays 时 N(t) = N₀ / 2

N₀/2 = N₀ * e^(-λ * halfLifeDays)
1/2 = e^(-λ * halfLifeDays)
ln(1/2) = -λ * halfLifeDays
-ln(2) = -λ * halfLifeDays
λ = ln(2) / halfLifeDays ≈ 0.693 / halfLifeDays

ln(2) ≈ 0.693 是确保"减半"这个特性的数学常数。

第二步:衰减乘数的计算

decay = exp(-lambda * ageInDays)
      = e^(-ln(2)/halfLifeDays * ageInDays)
      = 2^(-ageInDays/halfLifeDays)

4.3直观理解(以 halfLifeDays = 30 为例)

文档年龄
计算过程
衰减乘数
0天
2^(-0/30) = 2^0
1.0
(100%)
30天
2^(-30/30) = 2^(-1)
0.5
(50%)
60天
2^(-60/30) = 2^(-2)
0.25
(25%)
90天
2^(-90/30) = 2^(-3)
0.125
(12.5%)

规律:每过一个半衰期,权重乘以 1/2。

4.4在 OpenClaw 中的应用

// 原始置信度 * 衰减乘数 = 最终置信度
finalScore = hybridScore * decayMultiplier

效果

  • • 新文档(0-30天):置信度几乎不受影响
  • • 30天前文档:置信度打 5 折
  • • 60天前文档:置信度打 2.5 折
  • • 90天前文档:置信度仅剩 12.5%

这样系统会优先返回近期记忆,但旧文档不会完全消失(只是权重降低)。

4.5为什么选指数衰减而非线性

特性
指数衰减
线性衰减
近期保护
新文档权重几乎不变
新文档也会被削
远期处理
旧文档缓慢趋近于0
到某天后直接归零
数学性质
连续、平滑、可导
有拐点
物理意义
符合遗忘曲线规律
人为硬性截断

指数衰减更符合艾宾浩斯遗忘曲线——人脑也是先快后慢地遗忘。