@scotthuang/engram
v0.6.8
Published
分层语义记忆系统 - OpenClaw Plugin
Readme
Engram
分层语义记忆系统 - OpenClaw Plugin
方案文档
架构
短期记忆 (BM25 + jieba)
↓ 凌晨 Cron 沉淀
画像层 (LLM 抽取 + 摘要压缩)
↓ 有价值条目
向量层 (lancedb + text-embedding-v3)
↓ 超过 7 天
归档层 (cold-storage, 不索引)文件结构
src/
├── index.ts # Plugin 入口 (register)
├── config.ts # 配置定义
├── recall.ts # Auto-Recall (双路召回)
├── settle.ts # 沉淀逻辑 (Cron 5步)
├── bm25.ts # BM25 索引 (jieba-wasm 分词)
├── vector.ts # 向量存储 (lancedb + embedding)
├── profile.ts # 画像管理
├── image-store.ts # 图片存储
├── logger.ts # 日志系统
scripts/
├── sim-recall.ts # 模拟召回环境(见下方)
├── self-evolving.ts # 自进化模块(召回质量自动分析,见下方)
├── self-evolving.md # [自动生成] 召回质量分析报告
├── self-evolving-errors.md # [自动生成] 错题集(仅不通过的 case)
├── .self-evolving-checkpoint.json # [自动生成] 增量分析 checkpoint
├── config.md # workspace 路径配置
├── condense_shortterm.cjs # 短期记忆精简工具
├── manual-condense.ts # 手动补 condense(修复遗漏的 session)开发
npm install安装到 OpenClaw
openclaw plugins install @scotthuang/engram配置
{
plugins: {
slots: { memory: "engram" },
entries: {
"engram": {
enabled: true,
config: {
shortTermDays: 7,
halfLifeDays: 30,
recallTopK: 3,
minScore: 0.01,
}
}
}
}
}CLI
openclaw memory-sys settle # 手动触发沉淀
openclaw memory-sys profile # 查看画像
openclaw memory-sys stats # 统计信息自进化模块 (self-evolving)
自动分析 OpenClaw 每天的召回日志,评估 query 与最终召回结果是否匹配,借助 LLM 判断召回质量,生成分析报告和错题集。
流程
触发自进化 → 分析新增召回日志 → 生成/追加报告 → 生成错题集 → 保存 checkpoint增量机制
通过 scripts/.self-evolving-checkpoint.json 记录每个日志文件已处理到第几个召回块,每次触发只分析新增的召回日志。适合定时器反复触发。
- 首次运行(无 checkpoint):自动全量分析
- 后续运行:只分析上次 checkpoint 之后新增的召回块
--full:忽略 checkpoint,清空旧报告全量重新分析
产出文件
| 文件 | 说明 |
|------|------|
| scripts/self-evolving.md | 完整分析报告(所有 case,包含通过和不通过) |
| scripts/self-evolving-errors.md | 错题集(仅包含不通过的 case,附问题分类统计) |
| scripts/.self-evolving-checkpoint.json | 增量 checkpoint(记录每个日期已处理的召回块数量) |
用法
# 分析今天新增的召回日志(增量)
npx tsx scripts/self-evolving.ts
# 分析指定日期(增量)
npx tsx scripts/self-evolving.ts --date 2026-03-24
# 分析最近 N 天(增量)
npx tsx scripts/self-evolving.ts --days 3
# 分析所有日志(增量)
npx tsx scripts/self-evolving.ts --all
# 忽略 checkpoint,全量重新分析
npx tsx scripts/self-evolving.ts --full
# 仅分析不写文件(预览)
npx tsx scripts/self-evolving.ts --dry-run命令行选项
选项:
--date <YYYY-MM-DD> 分析指定日期的日志(增量)
--all 分析所有日志(增量)
--days <N> 分析最近 N 天的日志(默认 1,增量)
--full 忽略 checkpoint,全量重新分析
--dry-run 仅分析不写文件
--threshold <N> 低于此评分才记录详细 case(默认 3)
-v, --verbose 详细输出
-h, --help 显示帮助错题集
错题集 (self-evolving-errors.md) 从报告中提取所有不通过的 case,包含:
- 问题分类统计表(BM25 / 向量 / 查询重写 / 权重 / 时间衰减等分类)
- 每个错题的:原始查询、查询重写、实际召回 vs 理想召回、问题描述、原因分析、改进措施
- 按日期分组,由旧到新排列
典型使用场景
- 日常定时触发:每天/每小时执行
npx tsx scripts/self-evolving.ts,只分析新增日志 - 全量重建:修改评估逻辑后,用
--full重新分析所有历史日志 - 查看问题趋势:打开
self-evolving-errors.md查看错题集和问题分类统计
模拟召回环境 (sim-recall)
独立的命令行召回测试环境,复用项目真实代码(RecallEngine + VectorStore + BM25Index),连接真实的 LanceDB 和 LLM 接口,用于在本地快速测试和迭代召回策略,无需发 npm 包。
原理
scripts/sim-recall.ts
├── 读取 ~/.openclaw/openclaw.json → 获取 API Key、模型配置
├── 读取 scripts/config.md → 获取 workspace 路径
├── import src/recall.ts → RecallEngine(完整召回流水线)
├── import src/vector.ts → VectorStore(LanceDB + Embedding)
├── import src/bm25.ts → BM25Index(jieba-wasm 分词)
├── import src/config.ts → parseConfig(配置解析)
├── import src/logger.ts → Logger(日志系统)
└── import src/profile.ts → ProfileManager(画像注入)与 OpenClaw 线上环境完全一致:同样的 jieba 分词、同样的 LLM query rewrite、同样的双路召回 + 分数融合 + MMR 重排。
前置条件
~/.openclaw/openclaw.json中已配置 engram 插件(包含 embedding/queryRewrite 的 API Key)scripts/config.md中已配置正确的 workspace 路径- 安装依赖:
npm install
基本用法
# 单次查询
npm run sim -- "你的查询内容"
# 详细日志模式(输出完整的召回流水线日志)
npm run sim:v -- "你的查询内容"
# 交互模式(持续输入查询,适合批量调试)
npm run sim:i命令行选项
npx tsx scripts/sim-recall.ts [选项] "查询内容"
选项:
-i, --interactive 交互模式(持续输入查询)
--no-rewrite 跳过 LLM 查询重写,直接用原始 query
--no-vector 仅 BM25 短期记忆(不查向量数据库)
--no-bm25 仅 Vector 长期记忆(不查 BM25)
--top-k <N> 覆盖 recallTopK(默认 3)
--min-score <N> 覆盖 minScore 阈值(默认 0.01)
-v, --verbose 输出完整的调试日志
-h, --help 显示帮助使用示例
# 测试股票相关记忆的召回
npm run sim -- "看看股票相关的有哪些文档"
# 跳过 LLM 重写,直接测试原始 query 的召回效果
npx tsx scripts/sim-recall.ts --no-rewrite "002109 K线"
# 只看 BM25 短期记忆的命中情况
npx tsx scripts/sim-recall.ts --no-vector --no-rewrite "002109"
# 只看向量长期记忆的命中情况
npx tsx scripts/sim-recall.ts --no-bm25 "股票查询偏好"
# 调整 topK 和 minScore
npx tsx scripts/sim-recall.ts --top-k 10 --min-score 0.05 "Wandy"
# 交互模式 + 详细日志,适合反复调试
npx tsx scripts/sim-recall.ts --interactive --verbose输出说明
每次查询会输出:
- 初始化信息 — workspace 路径、短期记忆/向量数据库位置、配置参数
- 召回流水线(verbose 模式)— query rewrite 结果、BM25 命中数、Vector 候选数、融合排序、MMR 重排
- 最终结果 — Top-K 条记忆,标注来源(
[短期]/[长期])、类别标签、得分
典型调试流程
- 先用
npm run sim:v -- "查询"看完整日志,定位问题在 BM25 还是 Vector - 分别用
--no-vector和--no-bm25隔离测试 - 用
--no-rewrite对比 query rewrite 前后的召回差异 - 修改
src/下的代码后,直接再跑npm run sim验证效果,无需重新编译或发包
手动 Condense (manual-condense)
当 session 因 hook 遗漏(如之前缺少 command:reset 监听)或其他异常未被自动 condense 时,可以用此脚本手动补救——从 JSONL session 文件中提取对话,调用 LLM 精简后写入 short-term/ 目录。
用法
# 基本用法:指定 session 文件路径,自动从文件名推断日期
npx tsx scripts/manual-condense.ts <session-file-path>
# 指定目标日期(覆盖自动推断)
npx tsx scripts/manual-condense.ts <session-file-path> <YYYY-MM-DD>示例
# 补救一个因 /reset 未触发 condense 而遗漏的 session
npx tsx scripts/manual-condense.ts \
~/.openclaw/agents/main/sessions/7045fe60-bbf7-43a8-9d74-c378570733c6.jsonl.reset.2026-03-23T20-10-42.346Z \
2026-03-23处理流程
读取 JSONL session → 提取 user/assistant 消息 → 清理 metadata/噪音
→ 分段(每段 ≤5000 字符) → 调用 MiniMax LLM 精简
→ 合并 + 去重 → 追加写入 short-term/YYYY-MM-DD.md特性
- 消息提取:自动解析 JSONL 格式,过滤系统消息、命令、HEARTBEAT 等噪音
- 分段处理:长对话自动切分,避免 token 溢出
- 去重保护:写入前检查指纹,避免重复追加
- 日期推断:从
.reset.YYYY-MM-DDThh-mm-ss文件名自动提取日期 - 标记来源:写入时带
(manual-condense)标签,便于区分自动/手动记录
