若代理记忆使用后置过滤租户作用域则会泄露数据

Reddit r/AI_Agents 工具

摘要

文章阐述了向量搜索中的后置过滤租户作用域如何导致代理记忆系统泄露数据,并建议在写入时设置作用域以防止跨租户数据暴露。

我们最初采用共享索引,并通过系统提示词限定仅使用客户X的记忆数据,但这无法解决问题,因为检索阶段的泄露发生在模型处理数据之前。 泄露发生的位置 提示词只是最后一道防线。如果超出作用域的记录已进入上下文窗口,意味着它们已被读取、查询并消耗了token成本。提示词规则几乎无法阻止数据泄露。存在三种失败路径,且全部发生在检索阶段。 1. 向量搜索中的后置过滤 在单索引结构中将租户ID存入元数据并作为后置过滤条件。近似最近邻搜索会遍历整个索引,返回前k个结果,再丢弃不匹配租户的行。这会导致结果数量减少、小租户的召回率下降,且搜索过程仍会遍历其他租户的向量数据。前置过滤有所改善,但某些ANN实现在过滤条件屏蔽大部分图结构时性能会急剧下降。 单索引+元数据的方案非常脆弱,仅在实际租户数量规模下才会暴露问题,开发环境难以察觉。我们改用了分区方案,要求每次写入时必须指定分区键。 2. 图结构未尊重租户边界 如果存储系统包含图结构,仅限定种子节点的作用域是不够的,必须在每次边遍历时检查作用域。例如两个租户共享同一供应商,该供应商对应一个全局节点。当租户A进行两跳遍历时可能触及此节点,并进入租户B的子图。虽然每条记录都标有正确的租户ID,但边关系并不感知边界。 我们现在对子图而非节点设置作用域,确保实体即使对应同一现实事物也保持租户本地化。虽然这会造成数据重复存储,但这是可接受的代价。 3. 缓存键缺少租户标识 若缓存键基于查询文本和嵌入哈希值,租户A的预热结果可能直接被租户B使用。嵌入缓存、去重表和重排序缓存都存在相同漏洞。建议立即排查此类问题,这虽然是单行代码的缺陷,但可能迅速引发严重后果。 我们的建模方式 作用域在写入时绑定,缺少作用域的写入会直接失败。绝不使用默认租户桶——默认桶就像缓慢的漏气,直到用户离职时才会被发现。 作用域层级按用户→客户→客户端存储为物化路径。检索时将解析后的作用域路径作为参数传递(而非过滤条件),任何查询都必须携带作用域。超出作用域的记录不仅不会返回,而是根本无法检索,因此提示词注入攻击无效——数据从未被载入处理流程。 实体解析也必须限定作用域 若去重相似性搜索未限定作用域,会导致跨租户的实体合并。这比读取泄露更严重,因为错误合并会持久存储在系统中,且任何访问控制机制都无法识别。 解析过程严格限定在作用域内执行,匹配策略按置信度排序,低于阈值的案例进入人工审核队列而非自动合并。我们曾错误地以减少重复记录为优化目标,但未合并的重复只是困扰,错误合并却是严重事故。 删除操作是核心测试 若租户ID仅作为共享索引的元数据,根据引擎不同,向量可能通过墓碑标记保留至压缩阶段,导致已删除数据仍可访问。若采用分区方案,用户离职即删除分区,数据立即消失。 如果不同存储方案的答案不同,说明你并未建立统一的隔离模型,而是存在四种不同模型。 验证建议 准备两个租户的相似记录:相同名称、相同表述、尽可能接近的嵌入向量。检查跨租户检索在所有k值下是否返回零结果。大多数系统无法通过此类测试,因为常规测试套件使用不同租户的测试数据,向量搜索会自然分离结果,无法验证作用域有效性。 随后用某个租户的数据量扩大一千倍进行测试,因为后置过滤导致的召回率下降会在此场景显现。 我们选择在存储层强制执行作用域,确保即使查询层存在缺陷也能保证隔离性,但代价是跨租户分析需要单独路径与鉴权体系。 (注:我是Maximem(Synap)的代理记忆系统开发者,以上是我们的实践方案。无论选择我们的服务还是自建系统,这些原则都适用)
查看原文

相似文章