一、记忆召回置信度计算与使用
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 | src/agents/memory-search.ts:93 | ||
vectorWeight | src/agents/memory-search.ts:95 | ||
textWeight | src/agents/memory-search.ts:96 | ||
maxResults | src/agents/memory-search.ts:92 | ||
candidateMultiplier | src/agents/memory-search.ts:97 |
搜索流程
1. 查询处理:清理查询文本 2. 同步检查:如果启用了搜索时同步,执行内存同步 3. 模式判断: • 无嵌入提供者:使用仅 FTS 模式 • FTS 不可用:使用仅向量模式 • 两者都可用:使用混合模式 4. 执行搜索: • 向量搜索:计算嵌入向量并执行相似性搜索 • 关键词搜索:使用 FTS 执行关键词匹配 5. 结果合并: • 混合模式:加权合并两种结果 • 单一模式:直接使用对应结果 6. 置信度过滤:过滤掉低于 minScore的结果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. 日期命名的记忆文件: • 从文件名提取日期,如 memory/2024-01-01.md• 使用正则表达式 /(?:^|\/)memory\/(\d{4})-(\d{2})-(\d{2})\.md$/匹配2. 常青知识文件: • 根级记忆文件(如 MEMORY.md)• 非日期命名的记忆文件 • 这些文件被视为"常青"知识,不应用时间衰减 3. 其他文件: • 使用文件系统的修改时间(mtime)
2.2配置参数
enabled | ||
halfLifeDays |
2.3工作流程
1. 搜索执行:执行向量搜索和关键词搜索 2. 结果合并:计算混合分数(向量得分 * 向量权重 + 文本得分 * 文本权重) 3. 时间衰减应用: • 提取每个结果的时间戳 • 计算文档年龄(以天为单位) • 计算衰减乘数 • 将衰减乘数应用到混合分数上 4. 结果排序:按衰减后的分数降序排列 5. MMR重排序:如果启用,进行多样性重排序
2.4时间衰减的影响
示例:半衰期为30天的情况
特殊处理
1. 常青知识:根级记忆文件和非日期命名的记忆文件不应用时间衰减 2. 无时间戳文件:无法确定时间戳的文件不应用时间衰减 3. 时间戳提取失败:如果无法提取时间戳,保持原始分数不变
2.5总结
OpenClaw 的时间衰减功能通过指数衰减模型,根据文档的年龄动态调整其置信度分数,使搜索结果更加偏向于近期内容。这对于需要保持信息新鲜度的场景非常重要,如项目文档、会议记录等。
时间衰减的实现考虑了不同类型文件的特点,对常青知识文件不应用衰减,同时通过灵活的配置参数,允许用户根据具体需求调整衰减速度。
三、记忆召回触发时机与流程分析
3.1触发时机
OpenClaw 的记忆召回主要在以下情况下触发:
1. 显式工具调用
• 用户查询触发:当用户提出涉及以下内容的问题时,系统会调用 memory_search工具• 先前的工作 • 决策历史 • 日期和时间 • 人员信息 • 偏好设置 • 待办事项
2. 系统自动触发
• 强制召回步骤:根据工具描述,记忆搜索是一个"强制召回步骤",在回答问题前自动执行 • 搜索时同步:当启用 sync.onSearch配置时,搜索前会自动同步内存
3. 配置相关触发
• 会话启动同步:当启用 sync.onSessionStart配置时,会话开始时会预热内存• 定时同步:当设置了 sync.intervalMinutes时,会定期同步内存
3.2召回流程
记忆召回的完整流程如下:
1. 工具注册与初始化
1. 工具注册: memory_search工具在tool-catalog.ts中注册到 "memory" 部分2. 工具创建:通过 createMemorySearchTool函数创建记忆搜索工具实例3. 上下文解析:解析配置和代理会话信息,确定是否启用记忆搜索
2. 搜索执行
1. 参数处理:解析查询文本、最大结果数、最小分数等参数 2. 管理器获取:调用 getMemorySearchManager获取内存搜索管理器3. 同步检查:如果启用了搜索时同步,执行内存同步 4. 搜索执行: • 向量搜索:计算查询的嵌入向量,执行相似性搜索 • 关键词搜索:使用 FTS 执行关键词匹配 • 混合模式:结合向量和关键词搜索结果,应用权重计算 • 时间衰减:如果启用,应用时间衰减降低旧文档的置信度 • MMR重排序:如果启用,进行多样性重排序
3. 结果处理
1. 引用添加:根据配置添加来源引用 2. 结果限制:根据字符预算限制结果大小 3. 状态收集:收集搜索状态信息(提供者、模型、模式等) 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 / halfLifeDaysln(2) ≈ 0.693 是确保"减半"这个特性的数学常数。
第二步:衰减乘数的计算
decay = exp(-lambda * ageInDays)
= e^(-ln(2)/halfLifeDays * ageInDays)
= 2^(-ageInDays/halfLifeDays)4.3直观理解(以 halfLifeDays = 30 为例)
| 1.0 | ||
| 0.5 | ||
| 0.25 | ||
| 0.125 |
规律:每过一个半衰期,权重乘以 1/2。
4.4在 OpenClaw 中的应用
// 原始置信度 * 衰减乘数 = 最终置信度
finalScore = hybridScore * decayMultiplier效果:
• 新文档(0-30天):置信度几乎不受影响 • 30天前文档:置信度打 5 折 • 60天前文档:置信度打 2.5 折 • 90天前文档:置信度仅剩 12.5%
这样系统会优先返回近期记忆,但旧文档不会完全消失(只是权重降低)。
4.5为什么选指数衰减而非线性
指数衰减更符合艾宾浩斯遗忘曲线——人脑也是先快后慢地遗忘。
夜雨聆风