记忆 GC 与摘要压缩
wesgine 的记忆系统通过 GC(垃圾回收)和 Digest(摘要压缩)两个机制管理记忆的生命周期,防止记忆无限膨胀并保持召回质量。
GC(垃圾回收)
RetentionScore 加权淘汰
GC 不使用纯 LRU(最近最少使用)策略。runMaxEntries 使用 recall-frequency weighted 淘汰(RetentionScore),综合考虑:
- 召回频率(
recall_count) - 最后访问时间(
accessed_at) - 创建时间(
created_at) - Trust 等级
GC 豁免
以下类型的记忆不参与 GC 淘汰:
KindConstraint(约束)KindInstruction(指令)KindEnvironment(环境)
豁免是基于 Kind 的,不按 Actor 区分——物理清理对所有人平等。
TTL 机制
每种 scope 有独立的 TTL 配置:
GCConfig{
TTL: map[string]time.Duration{
"session": 24 * time.Hour,
"working": 7 * 24 * time.Hour,
"agent": 30 * 24 * time.Hour,
// ...
},
}
gcTTLBatch 单次只回收一批——与"全部"读写的分页至清空策略相反,节流判据是"剩下的会不会被再访问一次"。
accessed_at 下界(INV-MEM-51)
accessed_at 列 NOT NULL DEFAULT 0,零值是 1970-01-01——这是该字段最坏的取值。
最新写入的行 accessed_at = 0 会导致:
- GC
retentionScore衰减到 ~0 - Hybrid ranker 压到底
- Digest 读作 stale
ORDER BY accessed_at DESC排到末尾
治法:saveCore 落盘前将 accessed_at 抬平到 created_at,存量通过 ddlMemoriesV10 幂等修复。
Digest(摘要压缩)
Digest 是定期运行的认知整理过程,在 GC 之上提供语义级别的记忆质量管理。
Stale 检测(INV-MEM-29)
markStaleEntries 将 30+ 天零召回 的 L4(角色记忆)条目标记 stale。
Stale 条目从全部自动注入面排除——但显式检索路径(memory(search))不受此门约束。
取代检测(INV-MEM-30)
detectSupersession 检测"较新条目显式否定较旧条目"。
否定判据必须是整词:
// ❌ 曾经的问题:裸字"不"
negationMarkers = []string{"不", "禁止", ...}
// "不错"、"差不多"、"对不起" 全成否定信号
// ✅ 现在:整词匹配
// 只有 "不要"、"禁止"、"取消" 等完整否定词
冲突标记
检测到取代关系后,旧条目标记 Conflicted=true,从自动注入面排除。
执行点是 RecallQualityOK 单点——所有自动注入面(eager 5 + lazy 3 + cold-start 1 = 9 个 arm)共用此门。
Digest 按认知主体分区
Digest 的跨条目认知判断按 (Namespace, CognitiveOwner) 分区。
跨主体做的不是整合而是不可逆损坏:
dedup物理删除败者detectConflicts让两人对相反事物的偏好互相消音combinedRecall把别人的召回热度累加进淘汰打分
自动注入面(INV-MEM-50)
把记忆放到模型面前而无人请求的地方有 3 处、共 9 个 arm:
| 注入面 | Arm 数 | 说明 |
|---|---|---|
| Eager(系统提示词索引) | 5 | 每轮注入 |
| Lazy(当轮 overlay) | 3 | 按相关度注入 |
| Cold-start(跨会话摘要重放) | 1 | 首轮注入历史 |
质量门 RecallQualityOK
每个 arm 问两半——可见性与"这行还好不好"。RecallQualityOK 单点回答后者。
显式检索故意不设此门——memory(search) 回答"我存过什么",对指名索取者隐藏被取代的行是把错答换成缺答。
写入质量门控(INV-MEM-31)
saveCore 在 threat scan 之后运行 ContentQualityError():
- 拦截引擎状态前缀(
PLAN_STATE:/TASK_STATE:/SUBAGENT_RESULT:) ScopeWorking豁免- 返回
ErrContentQualityRejected(硬拒绝)
代码与 JSON 是合法记忆内容——R2(大段 JSON)、R3(plan 签名)、R4(原始代码块)均已废除。
威胁模式扫描(INV-MEM-24)
Store.Save 必须对 entry.Content 运行 FirstThreatError() 扫描:
| 模式 | 说明 |
|---|---|
hardcoded_secret | 硬编码密钥 |
connection_string_password | 连接串密码 |
aws_access_key | AWS 访问密钥 |
bearer_token | Bearer Token |
private_key | PEM 私钥 |
加上 invisible unicode 检测。匹配时返回 ErrThreatPatternDetected,拒绝写入。
Always-on,无 opt-out。
写入审批门控(INV-MEM-27)
CellSpec.MemoryWritePolicy 控制写入审批:
| 策略 | 行为 |
|---|---|
silent | 静默写入(默认) |
logged | 写入并记录日志 |
gated | 需要审批才能写入 |
Store.saveCore 在安全扫描通过后、embedding 前执行 WriteGate.Evaluate。
各产品场景
| 产品 | GC/Digest 行为 |
|---|---|
| wescode | 1 workspace = 1 Cell,记忆按项目隔离;correction 跨会话保留 |
| wesclaw | 个人助手,记忆随时间增长需要 GC |
| wescraft | 团队版多 actor 共享 Cell,Digest 按 CognitiveOwner 分区 |
| 企业版 | 部门 Cell 多员工,GC/Digest 尊重 Actor 边界 |