乐于分享
好东西不私藏

RAG的隐形杀手:过期文档如何悄悄“投毒”你的知识库

RAG的隐形杀手:过期文档如何悄悄“投毒”你的知识库

提到RAG(检索增强生成)投毒,大家第一反应往往是恶意攻击者往向量索引里塞一条假信息,诱导模型检索出来,一本正经地胡说。但在实际生产环境中,更常见、也更隐蔽的风险来源,其实是没有攻击者的投毒——过期文档

每家RAG系统都可能在踩的坑

绝大多数生产级的RAG系统,为了保证数据完整性,通常不会直接删除旧文档。当文档更新时,新版本会进入向量索引,而旧版本则原封不动地保留在原位。检索时,向量相似度搜索(Dense Search)关注的是”文档内容与查询的语义相似度”,而非”文档本身是否已过时”。

这就带来了一个问题:如果用户的提问恰好命中了旧版本文档里的特定表述,检索器就会把这个旧版本的片段(Chunk)排在最前面,模型就会基于这些过时的信息生成回答。文档作者虽然更新了内容,但用户拿到的依然是旧答案。

这种现象被称为”无攻击者的RAG投毒”。它不是传统意义上的安全攻击,更像是一个系统性的运维或架构问题。但对最终用户而言,结果是一样的:拿到了错误的信息,而且模型还表现得很自信。

三种检索架构的对比与启示

为了解决这个问题,我们可以对比三种常见的检索配置,看看它们在处理”过期文档”时的不同表现:

第一种是纯密集向量检索(Dense Search)加HNSW,这也是大多数商业”私有GPT”产品默认采用的方案。

第二种是BM25稀疏检索

第三种是引入了”资格门槛”的治理型检索(Governed Selector)

我们可以设想一个测试场景:在一个中型知识库(例如1000份文档)中,先更新一批文档,并将旧版本标记为”已被取代”但保留在索引中。然后运行一系列查询,统计回答的正确率。

结果会发现,治理型检索的表现最稳健,BM25次之,而纯密集向量检索的正确率最低。

为什么会有这种差异?核心原因在于治理型检索在进行相似度检索之前,增加了一道”资格检查”。它会先筛选出”当前生效的版本”,只有这些最新版本才有资格进入后续的相似度排序环节,而过期版本则被直接排除。相比之下,密集向量检索是”先检索后过滤”——过期文档一旦进入了候选集,就已经污染了排序结果,后续的过滤(如Rerank)也很难完全挽回。

打个比方:这就像图书馆的新书上架。密集向量检索是”不管新旧,按关键词从所有书架里找”,旧书和新书会一起被捞出来。治理型检索则是”先去当前书架找新书,再按关键词匹配”,旧书架根本不会被翻。

版本链与资格治理设计

一个优秀的治理方案通常需要精心设计的元数据和版本控制机制。每份文档都应包含版本号、创建时间、更新时间以及一个链式哈希值(Chain Hash)。链式哈希的计算方式如下:

chain_hash[n] = SHA-256(chain_hash[n-1] + content_hash[n] + version[n] + author[n] + timestamp[n])

每次文档更新都会产生一个新版本,旧版本作为历史记录保留,但不再作为”当前”版本参与默认检索。任何未授权的篡改、删除或恶意回滚操作,都会破坏哈希链的连续性,从而被轻易检测到。

此外,密集向量检索还有一个容易被忽视的缺点:它在很多查询上表现出非确定性(Non-deterministic)。这意味着同一个查询跑两次,可能会拿到略微不同的文档集合。在投毒场景下,这种不确定性会成为一个隐患——你甚至无法清晰地审计”模型到底看到了什么”。

这套治理方案何时不适用

引入治理型检索并非没有代价,也并非适用于所有场景。

第一,如果你使用的是混合检索(Hybrid Search),即结合了BM25和Dense Search的方案,其表现可能介于两者之间。混合检索在生产环境中非常常见,它的治理逻辑需要单独评估。

第二,治理型检索在一定程度上牺牲了向量语义搜索的灵活性。当用户查询的表述与文档表述差异很大时,过于严格的版本锁定可能会漏掉真正相关的跨版本信息。

第三,维护版本链的成本不低。每一次文档更新都需要重新计算哈希链,这对写入密集型的知识库来说是一笔不小的开销。

第四,如果用户的核心需求就是”查阅历史版本”,这套默认返回最新版本的方案就无法满足。需要系统提供显式的”历史版本查询”入口。

防御的第一道门是资格,而非相似度

核心结论非常清晰:RAG系统的投毒防御,重点不应该放在”检索之后的过滤”,而应该放在”检索之前的资格门槛”。一份文档,如果不是当前批准的有效版本,就不应该有机会进入大模型的上下文。