每条记忆先定好来源、能不能公开、可信度和出处,后面检索时才不会乱。
windows-bot-memory/record-schema
给 AI 助手做长期记忆时,很容易先想检索:全文检索怎么做,向量库怎么选,召回结果怎么喂给模型。
但检索之前还有一件更基础的事:每条记忆到底该长什么样。
如果记录本身没有统一格式,后面的 FTS、向量检索、生命周期管理和安全过滤都会变得很脆。系统能搜到很多东西,却说不清它们来自哪里、是否可信、是否过期、能不能被公开复用。
所以本地记忆中心里我更愿意先写 memory-record 的 schema,再谈召回。
一段 text 不够长期用
最简单的记忆格式是:
{ "text": "用户喜欢某类内容" }这种格式适合 demo,不适合长期运行。
真实的本地助手会遇到很多来源:云端机器人、Windows 本地任务、项目索引、个人配置、整理后的每日笔记、维护摘要、公开仓库材料。它们的可信度、隐私级别和适用场景都不一样。
所以一条可用的记忆记录至少要能回答:
- 来自哪个 source。
- 属于哪个 namespace。
- 是事实、偏好、规则、项目、任务,还是原始记录。
- 适用 scope 是什么。
- 隐私级别是什么。
- 置信度是多少。
- 证据在哪里。
- 何时创建和更新。
这些字段不是为了表结构好看,主要是让召回时能先判断哪些内容该用、哪些内容该挡掉。
kind 决定怎么使用
一条记忆的 kind 不能靠正文临时猜。
规则、偏好、项目、任务、人物和原始记录,应该在结构上区分开。因为它们被召回后使用方式完全不同。
例如:
rule更像执行约束,应该稳定、谨慎、优先级高。preference是用户偏好,可以影响排序和表达,但不一定是硬规则。project适合做工作区路由。task需要关注状态和时效。raw只能作为弱证据,不该直接当长期结论。boundary用来提醒系统哪些事情不能跨域复用。
如果所有内容都只是 text,模型会在语义上看起来都能理解,但系统无法在执行层面区分“应该遵守”和“仅供参考”。
privacy 是召回前的第一道门
长期记忆里必须有隐私字段。
我倾向于把隐私级别明确分成几类:public、routing、personal、private、sensitive。它们不是装饰字段,召回前就要用它们过滤。
公开写博客时,我只会使用 public 或已经抽象过的 routing 级信息。个人助手回答私聊问题时,可以使用 personal。private 和 sensitive 需要更强限制,甚至默认不进入普通召回。
隐私过滤最好发生在检索阶段;等文本已经进了上下文,再提醒模型小心,风险就高了。
trust 让系统知道该信谁
同一句话来自不同来源,可信度不一样。
用户明确确认过的规则,和模型从一段聊天里推断出来的偏好,权重应该不同。外部导入的资料、本地推断的摘要、未经验证的候选,也不适合混成一个“事实池”。
所以记录里需要 trust:
user_confirmedlocal_inferredexternal_importedmodel_inferreduntrusted有了 trust,系统才能做更稳的召回排序。强信任记录优先,弱信任记录可以作为背景;冲突出现时,也能知道应该先看谁。
这对博客写作也有用。可公开草稿最好来自用户确认、公开仓库或整理摘要;未验证候选只适合当线索。
lifecycle 让记忆会老化
长期记忆最怕“永远有效”。
项目路径会变,工具链会换,部署方式会过期,偏好也会变化。如果记录没有生命周期,系统就会越来越擅长召回旧答案。
所以记录格式里要有 lifecycle:
- candidate:候选,还没稳定。
- active:当前可用。
- stale:可能过期。
- archived:保留历史,不默认使用。
- quarantined:有风险,需要隔离。
- deleted:逻辑删除。
还可以记录 last_reviewed_at、expires_at、decay_score。这样维护脚本才能定期检查,而不是让旧记忆自然堆积。
记忆系统不能一直做加法,它也需要衰减、归档和隔离。
evidence 和 provenance 负责可解释
模型召回时,我最想让系统回答的是:
你为什么想起这条?如果记录只有 text,系统只能说“搜索命中了”。这不够。
记录里应该有 evidence 和 provenance。evidence 可以指向证据来源、路径、行号或 quote hash;provenance 则说明这条记录从哪个文件、快照或远端同步而来。
这让召回结果可解释,也让维护脚本能回头查证。发现某条记录错了,可以追到源头;发现某个来源不该进入索引,也可以重新构建。
没有出处的记忆,长期看会变成谣言。
relations 处理冲突和演进
长期记忆不是静态表。
同一件事可能有别名,旧规则可能被新规则取代,两条记录可能互相冲突,一个项目可能和另一个项目共享部分流程。
所以记录格式里还需要 relations:
- links:相关记录。
- aliases:别名。
- supersedes:取代了哪些旧记录。
- conflicts:和哪些记录冲突。
这样检索结果不再是一堆散落记录,脚本也能知道它们之间谁替代了谁、谁和谁冲突。
尤其是 supersedes 和 conflicts,很适合处理工具链升级、配置迁移和项目范围变化。否则旧记录不会自动消失,只会和新记录一起挤在检索结果里。
schema 比口头提醒更可靠
很多人会把这些规则写进给模型的说明里:
请注意隐私,不要混淆来源,不要使用过期记忆。文字说明可以提醒模型,但字段过滤这类事更适合放在数据层和检索层处理。
schema -> index -> scoped retrieval -> model context这个顺序比“先搜一堆文本,再提醒模型小心”可靠。
维护结果也要写回记录
记录格式不是写完就结束。
维护脚本跑完以后,应该能更新状态、生成候选、发现冲突、标记 stale、补充 relation,甚至隔离风险记录。一次维护摘要里可以有索引数量、冲突候选、生命周期检查结果和测试结果,但这些结果最后要能反馈到记录层。
否则维护只是在写日志,系统本身没有变好。
我更喜欢把维护理解成一个回路:
records -> index -> search/use -> review -> lifecycle updates -> records这个回路存在,记忆系统才不会只会越堆越大。
先把一条记忆写清楚
长期记忆的第一步,我会先放在记录格式上。向量库和上下文组织都可以往后排。
记录里先写清来源、隐私、可信度、状态和出处,后面做检索、召回、写作过滤时才有东西可查。
模型助手不缺文本,缺的是每段文本能不能用、该怎么用、什么时候该停用。
先定记录格式,再做长期记忆。
继续读