Skip to content

Latest commit

 

History

History
128 lines (80 loc) · 8.74 KB

File metadata and controls

128 lines (80 loc) · 8.74 KB

记忆分层规则引擎:决策思路复盘

2026-08-26 · MinimalAgent 记忆系统设计记录 对应设计文档:design-20260826-memory-rule-engine.md(规则集/流程/验收标准) 本文档回答另一个问题:这些设计是怎么一步步拍板出来的


一、要解决的问题

agent 会积累大量候选记忆:用户说过的话、项目约定、踩过的坑、临时状态。如果全存成永久记忆,长期层被噪音淹没,真正重要的信息提取成本变高;如果存得保守,关键身份和偏好丢失,agent 反复问用户已经说过的事。

核心问题:什么值得长期记忆,什么只配短期停留?

当时摆在我面前两条路:交给 LLM 判断,或者自己定规则。我选了后者。下面的五个决策,是这条路逐步展开的过程。

二、决策一:判断器用规则引擎,不用 LLM 黑盒

第一个念头其实是"让 LLM 判断重要不重要"——模型读得懂语义,似乎天然适合。但被一个问题拦住了:记忆事故发生时,怎么回答"为什么"?

"这条记忆为什么进了长期层?"——LLM 给不出答案。它是个黑盒,判断结果无法回放、无法审计、无法修正。而记忆系统最怕的就是这种不可追责:记错了,你甚至不知道它是怎么错的。

规则引擎正好相反:判断是确定性分支,任何一条记忆都能回放完整的规则链。出了事故,回答"为什么"→ 找到规则 → 改规则即可。可解释性是记忆系统的底线,规则引擎是唯一能满足它的方案。

于是 LLM 的位置从"法官"降级为"司法解释":只处理规则拿不准的灰色地带,比例控制在 90% 规则 / 10% LLM。判断的主体是规则,模型只是补充。

三、决策二:规则不是拍脑袋,锚在"知识生命周期"上

定了用规则,下一个问题:规则凭什么定?

如果规则是我临时想的("我觉得身份重要"),那它和拍脑袋没有区别。需要一个统一的判别标准。我借用了认知科学里的一个视角——知识生命周期

变更成本 ≈ 生命周期 ≈ 重建成本

一句话:知识的变更成本越高,越值得长久存。家乡(物理不可变)、职业(转换成本高)、设计目标(推翻=全盘重来)一眼长命;丢了重建代价大的知识必须深存——"存那个丢了最心疼的";八股短命,因为考纲变更成本为零。

落到规则上就是类型查表:身份/原则 → 长期;稳定偏好 → 长期;具体技术用法 → 短期(带 TTL);临时状态 → 最短命。每一条规则背后都有这个判据撑着,而不是"我觉得"。

四、决策三:分层靠淘汰策略,不靠预测

记忆分层(L1 临时 / L2 工作 / L3 长期)最容易踩的坑是:想靠预测一次分对。但预测总会错——误杀一条长命知识的代价,远大于多存一条短命知识。

所以我的原则是:以使用定生死,不以预测定生死。 分层不是靠预测,是靠每层不同的淘汰策略:

  • L1:会话结束即过期,不值得存
  • L2:带 TTL,到期降级 + 对账提示,绝不静默删除(防误杀)
  • L3:几乎不淘汰,仅显式纠正可降级

并且留了复活机制:L2 的记忆被频繁召回(≥3 次/30 天)自动升级 L3——初判错了没关系,使用反馈会修正。判断器给的是先验,使用验证给的是后验,后验永远有权推翻先验。

五、决策四:实现选最简档,不碰重武器

"规则引擎"这个词听起来很重——八股里听过 Drools、Rete 算法,好像是个需要专门学的体系。但调研了一遍才发现它是个光谱,从轻到重三档:

  1. 代码里的 if/elif 查表(零依赖)
  2. 决策表(规则写成 JSON/YAML,代码只写解释器)
  3. 正经规则引擎(Drools / durable_rules,Rete 算法,处理上千条规则)

我的选择是第一档,理由很直接:记忆分层的规则一共 12 条——4 条硬分流(类型查表/变更成本/来源门槛/显式反馈)+ 5 条打分 + 3 条后验修正。规则是"宪法"级的:数量少、几乎不变、需要可审计。这个量级用纯函数查表就是最优解,引一个 Drools 进来纯属给项目背了个大象。

第一档落成代码只有 45 行:classify() 里前六行是硬分流(短路),后面是打分和阈值,on_recall / on_ttl_expire / on_correction 三个函数管后验修正。每条记忆落库时把返回的 ["R1", "R3"] 存成 rule_chain——可审计性就是这么来的,不是额外设计,是代码的自然产物

什么时候才需要升级第二档?规则膨胀到 50+ 条、且要让非程序员改规则的时候。这个信号出现前,第一档就是终局(YAGNI)。

六、决策五:提取层和判断层分离

规则引擎能判断的前提是:输入已经是"一条独立的事实"。但对话原文是一大段话——"我是 Java 后端,之前做流批一体,最近在学 RAG,这周五交周报",里面是 4 条生命周期完全不同的记忆。

这里有个容易混淆的点:切句(提取)和分层(判断)是两件事。切句需要语义理解——按标点切是切不对的,中文口语一逗到底,必须读懂内容才知道哪几个事实绑在一起;分层需要确定性——同一套规则永远给同一结果,可审计。前者是 LLM 的强项,后者是规则引擎的强项。所以各干各的:

对话原文 → LLM 提取(原子事实清单 + 类型标签)→ 规则引擎分层 → 落库

切分的粒度标准是一条硬原则:一条记忆只能有一个生命周期。如果一条内容里混着长命的("我是 Java 后端")和短命的("这周五交周报"),规则引擎就没法判。判断粒度够不够细,三个测试:独立失效(这条过期不影响别的)、独立变更(纠正一条不牵连别的)、独立复用(将来某个任务只需要这一条)。

提取时机也刻意低频:不每条消息都切,每 N 轮对话做一次批量提取(background review),正好和"事后批量对账"接上——收尾时一起给"本次我记住了这些"清单让用户确认。省成本,还多一次人工校准。

七、收束:把"猜"变成"可审计的猜"

回头看这五个决策,其实是一条线:判断力是可以制度化的。

  • 该让模型猜的(理解语义)→ 交给 LLM
  • 该让规则定的(判生死)→ 交给规则引擎
  • 猜错了怎么办 → 使用验证修正,规则表越用越厚(判过的灰色地带沉淀为新规则)
  • 未来怎么演进 → 判定日志攒够了蒸馏成专用小模型,但三个升级信号出现之前,这套轻量体系就是终局

规则引擎不复杂。它就是把你不敢硬编码的判断,显式地写出来、编上号、接受审问。对记忆系统来说,这比任何黑盒判断都值钱——因为记忆的错,是要能追责的。


附录:12 条规则清单

硬分流 4 条(命中即短路,直接定层)

规则 内容 判定
R1 知识类型查表 身份/原则/稳定偏好 → L3;具体用法 → L2+TTL;临时状态 → L1
R2 变更成本判据 离底层约束近 / 重建代价大 → L3;可重新获取 → 降级
R3 来源等级门槛 用户亲口说且是身份/原则 → L3 候选;纯工具观察无确认 → 最多 L2
R4 显式用户反馈 置顶 → L3;归档 → 出局/降级

打分 5 条(灰色地带累计 lifetime_score,0–100)

规则 条件 分值
S1 类型接近身份/原则/稳定偏好 +30
S1 类型接近具体用法 +10
S2 变更成本高(重建代价大) +30
S2 变更成本低(可重新获取) -20
S3 来源 = 用户亲口说 +20
S3 来源 = 模型推断 / 工具观察 +5
S4 内容是"为什么"(原理/约束) +15
S4 内容是"怎么做"(步骤/命令) +5
S5 临时状态 -40
S5 带明确时效("这周"/"项目期间") -20

阈值:≥80 → L3 长期;40–79 → L2 工作(带 TTL);<40 → L1 临时

后验修正 3 条(运行时,使用反馈推翻初判)

规则 事件 动作
P1 召回 ≥3 次/30 天 L2 → L3 自动升级(复活机制)
P2 L2 超 TTL 未召回 降级 L1 + 对账提示(不静默删除,防误杀)
P3 用户纠正 覆盖一切先验,按纠正后内容重新判定

优先级:显式反馈(R4/P3)> 来源门槛(R3)> 类型查表(R1/R2)> 打分(S1–S5)。冲突原则:用户说什么就是什么——规则引擎的职责是猜,用户反馈是事实,事实永远压过猜测。