3.0 KiB
3.0 KiB
P2+P3: 织忆记忆离线整合 + 双缓冲触发改造
2026-08-11 | 小唯 | 借鉴 zjunlp/LightMem(ICLR 2026) 前置:P1 逐条事实提取已完成(commit 0734ffa)
P2: 离线整合 UPDATE_PROMPT(记忆合并/冲突消解)
目标
对相似记忆做 LLM 三选一决策(update 合并细节 / delete 冲突删旧 / ignore 不相关),解决记忆冗余和冲突。
实现(新增 go/internal/distill/consolidate.go)
ConsolidateMemory(ldb, llmConfig, namespace string)— 离线整合入口:ldb.Search("memories", zeroVec, 200, namespace)取全部记忆- 两两计算相似度(复用 bge 向量?简单方案:用 recall 端点向量检索找候选)
- 对高相似候选对(score ≥ 0.85)调 LLM 三选一
- UPDATE_PROMPT(移植 LightMem 原文精髓):
- update:目标与候选描述同一事实但不完全一致 → 合并额外信息
- delete:直接冲突且候选更新 → 删目标
- ignore:不相关 → 跳过
- 输出 JSON
{"action": "update"|"delete"|"ignore", "new_memory": "..."}
- 执行:
- action=update →
UpdateMemoryContent(id, new_memory) - action=delete →
DeleteMemory(id) - action=ignore → 跳过
- action=update →
- 触发:新增 API
POST /api/v1/consolidate/memory(手动触发)+ 每日 cron 自动触发
依赖
ldb.Search/ldb.UpdateMemoryContent/ldb.Delete(需确认 Delete 存在)
P3: 双缓冲触发(token 积累批量 distill)
目标
LightMem 的 Sensory(512) → Short-term(2000) 双缓冲思想:织忆 distill 按 token 积累触发,而非按条数。
实现(改 go/internal/distill/engine.go)
- Engine 新增字段:
pendingTokens int— 当前缓冲的累计 token 数flushTokenThreshold int— 触发阈值(默认 2000,对应 LightMem short-term)maxBatchTokens int— 单批上限(防止超大 batch)
- Enqueue 改造:
- 入队时累加
pendingTokens += estimateTokens(content)(rune count / 2 中文近似) shouldFlush = pendingTokens >= flushTokenThreshold || len(queue) >= batchSize- flush 后
pendingTokens = 0
- 入队时累加
- token 估算:简单函数
estimateTokens(s) = len([]rune(s))/2(中文≈1 token/字符,英文≈1 token/4字符,取折中)
配置
- 通过环境变量
DISTILL_FLUSH_TOKENS(默认 2000)可调,避免硬编码
测试命令
# P2 测试 — 触发手动整合
curl -s -X POST -H "X-API-Key: zhiyi-dev-key-2026" -H "Content-Type: application/json" \
-d '{"namespace":"hermes-main"}' \
http://localhost:7821/api/v1/consolidate/memory
# P3 测试 — 提交 3 条小内容(累计 <2000 token),验证不立即 flush
# 再提交大内容触发 flush,看日志 flush START 时机
验收标准
- go build 通过
- P2: 手动触发后日志显示 update/delete/ignore 决策
- P2: 相似记忆被合并(recall 不再返回重复内容)
- P3: 小内容入队不立即 flush,达阈值才 flush
- 部署后全链路健康