记忆存储是时序关系图而非函数,常规相等断言无法捕获过期值、歧义值;作者给出三条图不变式检查(互惠链接、无环、无孤立)和三条时序有效性检查。
在 Agent 技术栈中,记忆层是唯一一个所有测试都通过、但系统却在悄然腐化的组件。
这不是测试纪律的问题,而是形态问题。栈中其他所有部分都是函数:输入进去、输出出来、断言相等。而记忆库是一张随时间演化的关系图。它的失败不是错误的值——而是过时的值、歧义的值、以及曾经正确但现在不再正确的值。这些都不会出现在 expect(recall(q)).toEqual([...]) 这样的断言中。
以下是我最终实现自动化的六个断言,大致按其捕获问题的时机排列。
如果条目之间可以相互覆写,图结构必须是良好形成的。需做三项检查:
互惠链接:如果 A.superseded_by = B,那么 B.supersedes 必须包含 A。单向链接意味着历史记录在两个方向中的一个方向上不可读。
无环。A → B → C → A 永远是一个 bug,而且这种 bug 会导致 recall 挂起或返回环中任意一个成员。
无孤立覆写:superseded_by 指向的 ID 已被硬删除。
这一项执行只需毫秒级,却比清单上其他所有项捕获了更多真实 bug。它是纯图不变量,不需要 fixture,也不需要人工判断。
在你实际召回路径返回的真实查询样本中,有多少比例的条目已经被标记为已覆写?
这是我在找单一健康指标时最接近答案的一个。它应该接近零,而它的趋势比它的绝对值更重要。如果一个库在一个月内这个比例从 2% 爬升到 15%,就是在告诉你:合并任务没有运行,或者没有针对正确的人群。
这个断言不是一个神奇的阈值——而是一个预算。选一个你能捍卫的数字,超出时就让测试失败,并把失败视为"你的合并任务坏了",而不是"测试太严格了"。
相同库状态、相同查询、相同结果集——包括排序。
这听起来 trivial,但实际不是,因为平局无处不在:嵌入分数会聚集、时间戳会碰撞、你的存储使用的排序算法并不保证稳定。非确定性召回会产生最糟糕的一类 bug:Agent 在周二表现不同,但看不出任何明显原因,然后你把它误归咎于模型。
如果你真的需要多样性,让它显式且带种子的。不要让它从不稳定排序中自然产生。
用不同措辞写两个相同的断言,然后断言库中只保留一个规范条目——而不是两个——同时挂载两个来源。
有意思的失败不是明显的重复。而是不应该被合并的近似重复:"我们使用 Postgres"与"我们仅在计费服务中使用 Postgres"。一个好的测试语料库应同时包含这两种情况,而断言要求第一种合并、第二种不合并。
这组测试是防止过度热情的合并阈值悄悄将两个不同决策平均成一个无用条目的唯一防线。
注入一对刻意矛盾的条目,然后断言召回路径标记了冲突,而不是静默选择其中一个。
这是一个行为测试,不是数据测试,而且这是大多数项目都会跳过的那个。一个自信地读取过时决策的 Agent 严格来说比一个说"我有两条冲突的笔记,哪条是当前的?"的 Agent 更差。前者快但错误;后者让你多花四秒钟和一个问题。
断言标记存在。断言输出中命名了冲突对。不要断言解决方案,因为解决是领域相关的。
在其他条件相同的情况下,六个月内未被引用的条目一定不能排名高于同类型且可比相关性的新鲜条目。
其他条件永远不会真的相同,所以把它作为受控对来测试:两个合成条目,类型和文本形状相同,年龄不同,访问次数相同。老的那个不能赢。如果它赢了,你的衰减函数就是装饰性的。
断言很便宜;fixture 才是工作量。按价值排序的两个来源:
来自真实会话的金对。取二十个你实际运行过的真实查询,写下一个好的召回会返回的记忆条目。这活儿慢、手动,但值得——二十个真实的对比二百个生成的。
合成不变量。图检查、去重对、冲突对、衰减对。这些不需要领域知识,一个下午就能写完。
然后用种子 fixture 库运行所有测试,永远不要用生产库。读取真实库的记忆测试,一周内你就会禁用它,因为它们会因为与你修改的代码毫无关系的原因失败。
把每个断言映射到具体原因,否则测试套件就变成噪音了:
六个断言,一个下午就能写完,而失败表才是真正的交付物——因为重点不是让测试变绿。而是当绿色套件变红时,你知道是哪个子系统动了。
这是关于为编程 Agent 构建本地优先记忆层系列的一部分。第一部分覆盖了让记忆真正work的失败模式;第二部分覆盖了合并——那个防止库腐化的阶段:
I gave my AI coding agents a local long-term memory layer — 8 things that broke
Consolidation: the half of agent memory nobody builds
如果你想看四个访问路径(MCP、desktop、Python/Node SDK)是如何连接的:https://hm.qianshi.cool/api/v2/dl?from=devto