这篇 19 个系统系列的最终章稍有些延迟,不过迟到总比不到好。
在我深入研究的 19 个系统中,有六个通用模式构成了这个系列的骨架:写作时的质量投入、随事实一同传递的溯源、RRF 融合的混合检索、基于热度进行层级晋升的分级存储、显式的上下文预算、以及 Agent 层面的"工具而非注入"。每个模式都值得单独成文,因为至少有三个不同的系统独立地得出了同样的方法。
通用模式到此为止。接下来是正在兴起的模式。
这篇文章要讲八个尚未普及的模式,它们目前只出现在一个或两个系统中。它们的实现如此精准地解决了某个真实问题,以至于很难相信它们会长期保持小众。其中七个模式出现在唯一一个系统中。一个模式出现在两个系统中,距离"晋升"为通用模式只差一次被采纳。第一个模式会得到最深入的剖析,因为它最为重要。
过于领先,意味着有些模式可能最终无法普及。但落后更糟:假设你在 2026 年构建系统时,因为没有存储层的授权机制而错过了这个模式,因为某份分析报告将其定义为孤例。结果到了 2027 年,你的系统就会因为一个在 Hacker News 上被曝光的提示注入漏洞而声名狼藉。
存储引擎是唯一的权威持有者
上一篇文章主张 Agent 应该持有工具。给它一个 SQL 工具,一个尖锐的问题就会立刻浮现:是什么阻止了它查询不应该查询的表?
那些天真的方法早已为人熟知,但通通都是错的。
在提示层面进行指令约束:"你无权读取 conversations 表。"这在模型合作时有效。但一旦模型误读了指令,认为禁令不适用于当前任务,或是处于越狱模式下,这种方法就会失效。
在应用层面进行过滤器拦截:sql_query 工具包装了模型的 SQL,解析它是否存在被禁止的表引用,并在查询被提交到数据库之前将其拒绝。对于天真的模型有效。但对于任何会转义表名、使用 ATTACH、利用包装器和数据库之间的解析不匹配,或者通过其他地方定义的视图来绕过的模型,这种方法都会失效。
仅通过 ORM 访问:Agent 从不接触原始 SQL,只调用有类型的方法。这个方法在工作时没问题,直到系统出现一个调试工具、分析工具、迁移工具,或者一个“让 Agent 连接两个表”的功能。到那时,规则就会被打破,并且这种被破坏的状态往往难以被察觉。
直白地说:上述这些都不是真正的执行机制。它们只是提示。一个想要实现真正子 Agent 隔离的系统,必须让存储引擎本身拒绝读取,而不是它上面的那一层。这就是基于能力的安全模型对操作系统资源施加的纪律:是内核说不行,而不是应用程序。这也是 PostgreSQL 的行级安全对多租户 SaaS 实施的纪律:策略存在于数据库中,而非 ORM 中。因为“构建新微服务的工程师忘记应用租户过滤器”这类 bug,只有存储引擎层的策略才能彻底杜绝。
second-brain 是这套体系中的首个工作实例。它的作用域数据库包含三个层次,每一层都必不可少,但单独来看都不足以胜任。
首先,为每个作用域 Agent 创建一个新的内存 SQLite 连接。构造函数会打开 :memory: 数据库,并以只读模式附加真实数据库。这个 Agent 的连接没有真实的主模式,除了下一层放置的内容外,没有任何东西可读。
其次,在主模式中创建临时视图,将这些视图重定向到源数据库中允许访问的表。视图定义来自 Agent 的配置,可以编码列级别的脱敏或行级别的过滤。一个视图名称验证器可以防止通过配置注入恶意的表名。
最后,使用一个SQLite C-API 授权钩子,拒绝任何不经过视图的源模式读取。这个钩子会在 SQLite 即将执行任何读取操作之前触发,甚至在优化器解析表名之前。视图内部的读取是被允许的——视图本身就是作用域过滤器。而顶层的读取则会根据作用域创建的视图名称集合进行检查。任何直接针对源模式的读取都会被无条件拒绝。
LLM 可以编写任何它想要的 SQL。它可以转义表名、使用 UNION、使用 ATTACH,甚至使用 SQLite 的完整语法。但它永远无法成功读取不在允许列表中的表的任何一行数据,因为授权器在 C 层、在表名被解析之前就拦截了读取。应用层的过滤器是可绕过的。但存储引擎的授权则不然。
这套实现仅需大约 50 行标准 Python 库代码。没有额外的依赖,没有额外的进程,也没有数据迁移。每个查询的开销仅仅是每次读取时的一个 C 回调,与查询本身的成本相比可以忽略不计。这个模式可以与其他所有部分干净地组合:Agent 的工具注册表仍然可以进行功能开关控制,视图定义仍然可以实现列级脱敏,对话历史仍然可以在写入时进行编辑。存储层的执行机制不会削弱这些层面,反而会强化它们。
这个框架至关重要。在 19 个系统中,其他所有的安全模式都只是提示。而存储引擎,才是真正的权威。
另外三个值得一提的模式
异步清理的竞态保护 (llm-wiki)
后台的内存维护从根本上与前台用户的操作存在竞态条件。一个针对项目 A 启动的扫描操作,如果在项目 B 上完成,那么这两个项目的数据都会被破坏。它会将项目 A 的决策结果移入项目 B 的审查存储中,或者将项目 B 的项目标记为已解决,使用的却是项目 A 的数据。这是一类极易引入、难以检测,并且几乎无法彻底恢复的 bug,因为被破坏的状态看起来是合法的。
llm-wiki 运行着一个两阶段的后台审查循环,并且在每个产出点都会重新检查两个竞态保护信号:一个是由项目切换处理器触发的终止信号,另一个是与 UI 存储中当前项目路径的比对。任何一个检查失败,扫描操作都会在过程中途返回,不应用任何决策。队列端的项目切换握手则完成了整个流程:它在清空内存前将当前活跃项目的状态刷入磁盘,将正在处理的项目回退到待处理状态,同时中止正在运行的 LLM 调用和正在进行的扫描判定,最后才写入被暂停项目的路径。
其元模式是核心要点:在能确定的地方使用确定性方法,在必须的地方使用 LLM,并且在所有地方都能做到可中止。两阶段结构能够让 LLM 远离那些简单的存在性检查就能处理的情况。竞态保护机制则使两个阶段都可中止。这种组合为任何系统中的后台内存维护循环提供了一个可复用的模板。
自动降级的空操作构造函数 (graymatter)
库 API 设计一直存在着一种张力。最简单的“hello world”示例希望库能开箱即用,一行代码构造,一行代码调用。而最稳妥的生产环境姿态则希望它能在构造时明确地失败并报错,同时返回一个调用者无法忽略的结构化错误。
graymatter 选择了静默失败,但其采用的纪律将这种权衡变得富有成效。它的构造函数从不返回错误。如果初始化失败——比如 bbolt 被锁定、数据目录不可写、向量存储无法打开——它会向标准错误输出日志,并返回一个降级了的 Memory 对象,该对象的所有方法都是空操作。生产环境的调用者在使用句柄之前,需要通过 Healthy() 方法来验证其状态。这个库可以 go get 安装,三行代码即可导入,并且在演示中可以正常工作。而 Healthy() 方法就是生产环境纪律的代价。
这种模式使得该库可以安全地嵌入到那些拥有自身启动流程的 Agent 框架中。一个 Agent 框架在启动时调用 graymatter.New(...),由于构造函数没有错误路径,它会忽略错误,并继续执行。这样,在正常路径下它能获得一个可用的内存层,而在数据目录只读的故障路径下,则会得到一个无内存的备用方案。无论哪种情况,框架都能成功启动。这是一种特定类型的防御性组合,是那些“大声报错”的构造函数在没有任何嵌入点显式处理错误的情况下所无法提供的。
影子模式下的重复检测 (mem9)
每个实现重复数据抑制的系统都必须选择一个余弦相似度阈值。高于 0.95 几乎可以肯定是重复的。低于 0.7 几乎可以肯定不是。两者之间的空间是充满争议的。正确的阈值取决于嵌入模型、领域、查询分布,以及在这个特定系统中误报和漏报之间的成本权衡。
人们面临的最大诱惑就是凭借直觉选择一个阈值就直接上线。但 mem9 没有这么做。它对每条事实都运行重复检测查询,将余弦得分记录到 Prometheus 直方图中,却不采取任何后续动作。阈值的选择被推迟了,直到生产数据能证明其合理性。这就是“上线的是观测数据,而不是启发式规则。”
同样的逻辑也适用于每个内存系统中的每个阈值决策:重排序阈值、召回信度截断点、层级晋升热度门限、洞察合并相似度门限。在探索的 19 个系统中,大多数是凭猜测上线的这些值。而 mem9 则推迟了值的确定。这种纪律非常罕见,也因此带来了更好的结果。
另外四个,更加紧凑
每租户物理数据库隔离(mem9)。
mem9 没有在共享存储上使用 WHERE tenant_id = ? 过滤器,而是通过 TiDB Zero 为每个租户提供了一个独立的 TiDB 集群。隔离发生在存储引擎一侧。应用程序不可能意外地跨租户查询,因为根本没有共享存储可以查询。这是与存储层授权相同终态的一个更粗粒度的版本:由引擎强制隔离,而非应用程序。过去使这种模式不切实际的基础设施成本已经不复存在。TiDB Zero 可以自动配置,Neon 也为 PostgreSQL 提供了类似能力,Cloudflare D1 则为 SQLite 提供了支持。
带有显式上下文预算的源轮次装饰(mem9)。
一个被检索到的记忆只是一个字符串:“用户偏好 Postgres。”正确、简洁,但脱离了上下文就无法溯源。mem9 将原始的对话轮次作为装饰信息附加到记忆上,根据查询进行评分,并由一个预算三元组进行限制:最低分数、每条记忆限制、总量限制。当一个 Agent 读到“用户偏好 Postgres”时,它还会同时看到用户说过“我们试过 MongoDB,但连接操作太慢了,所以上个季度我换成了 Postgres”的那个具体对话轮次。它不需要第二次工具调用。溯源信息就在结果里。其前置条件已经是通用条件:溯源加上混合检索。19 个系统中的大部分都可以在两天内实现这个模式。
purpose.md 作为第四个文件(llm-wiki)。
Karpathy 的 LLM Wiki 模式包含三个标准文件:原始来源、Wiki 工作集以及用于结构规则的 schema.md。llm-wiki 增加了第四个:purpose.md。这个文件由用户填写,并会被嵌入到系统发起的每一个 LLM 调用中——每个摄取提示、每个生成提示、每个聊天检索都会读取它。它的效果是提供一个稳定的方向性先验,从而调节每一个下游行为。反正 LLM 都会读取系统提示。加入用户的意图没有任何成本,却能让所有事情变得更好。其他大多数系统没有这样做,这比 llm-wiki 有这种做法更难以解释。
AGENTS.md 作为权威的 Agent 契约(Tolaria,OpenContext)。
大多数拥有 AGENTS.md 或 CLAUDE.md 文件的仓库将其视为一个提示文件。而 Tolaria 和 OpenContext 则将其视为一份契约。他们为每一个具有约束力的条款都配了一个机械检查,如果 Agent 违反了该条款,构建就会失败。“不要跳过预提交钩子”不是一个礼貌的请求,而是一个会被 CI 强制执行的规则。“测试覆盖率必须保持在阈值以上”也不是一个指南,而是一个测试运行器会在低于其值时中止构建的门槛。提示可以被忽略,但由检查所支持的契约则不能。已经有两个系统这么做了。再多一个,它就能晋升为通用模式。
哪些模式会率先普及?
存储层的授权将会第一个得到普及。这是本次源代码分析中最有信心的预测。任何给予子 Agent SQL 访问权限的内存系统,如果没有存储层的强制机制,都距离一次因提示注入导致的数据泄露只有一步之遥。相关的基础设施已经准备就绪。SQLite 从 2000 年代初就有了 set_authorizer。PostgreSQL 的 RLS 已是主流。LanceDB 和 ClickHouse 也都有自己的策略钩子。障碍不是技术上的,而是认知上的。second-brain 提供了一个工作实例。下一代托管 API 将会复制这种纪律,因为其替代方案是站不住脚的。
源轮次装饰将会第二个普及。其前置条件已经通用。实现方法不过是两个查询加上一个预算。其给 Agent 侧带来的信息增益非常巨大,以至于在托管 API 中,谁先推出这个功能,谁在基于源对话进行溯源回答方面,就会比后来者明显做得更好。复制的压力很大。graymatter 有事实的源头数据,supermemory 有数据谱系,Hindsight 有完整的对话溯源能力。它们中的任何一个,都只差一个 PR 的距离来实现这个模式。
自动降级的空操作构造函数将会第三个普及,但会出现在另一种语言中。Go 的语言文化条件使得这个模式是安全的。下一个采用者不太可能是 Python(其异常处理文化太强烈),但可能是 Rust。这是一个库 API 设计的选择,与具体的内存系统无关。它将在任何认为“演示美观加上生产纪律”是正确权衡的地方传播开来。
影子模式部署则是一匹黑马。技术上微不足道,但文化上难以推行。如果第二个系统在基于某个阈值做出决策之前,先将其进行埋点观测,那么这个模式会立刻晋升。之后第三、第四个系统就会在一个发布周期内跟进,因为其工程上的便利性一旦被展示出来,就难以被抗拒。
剩下的四个模式,各自的普及都取决于特定的部署形态是否变得更加普遍。竞态保护会在更多系统拥有多对话并行能力时普及。每租户物理隔离会在受到监管的企业客户开始提出需求时普及。purpose.md 会在 Karpathy LLM Wiki 范式得到第三次或第四次实现时普及。而 AGENTS.md 作为契约,则会在“Agent 是同事”的框架成为主导的 Agent 宿主隐喻时普及。这些都不是不可能,但也都不是必然。
总结
贯穿这八个模式的统一主线是同一个立场:应用层不是一个值得信赖的隔离边界。存储层授权是其按 Agent 划分的表达形式。每租户物理数据库是其按租户划分的表达形式。AGENTS.md 作为契约则是其按 Agent 行为划分的表达形式。本系列的下一个迭代版本,按照这个预测,将会包含一个以此命名的新的通用模式。
上一篇文章论证了 Agent 应该持有工具并决定检索什么。而这篇文章关于的是:当你将那些工具指向了你未曾预期的地方时,是什么在兜底。那六个通用模式是共识。这里的八个则是显示共识将向何处演变的领先指标。存储层授权是这个领先集群中的最前沿,而错过它的代价,将是那种会出现在 Hacker News 上的代价。





