跳到主要内容

把 RAGSieve 的检测思路在自己检索管线里跑一遍的踩坑笔记

abanana
abanana

· 阅读约 4 分钟

前几天在 arXiv 上刷到一篇 8 月 13 日提交的论文,RAGSieve,讲的是 RAG 里的知识投毒检测。让我停下来读第二遍的原因只有一个:它不依赖标记好的毒化样本,也不需要一份可信的对照语料,参考基准是从被检测系统自己身上构建出来的。这一点对我这种手头根本没有“干净语料”可当锚点的人太有吸引力了,所以今天花了一个下午,把它的两个组件在自己脑子里各跑了一遍,顺手把可操作的验证思路记下来。这篇笔记讲清楚两件事:RSQ 和 RSG 各自的检测逻辑怎么落成可执行的步骤、以及拿什么指标判断它是不是真的有用。

先拆开看看 RSQ(RAGSieve-Query)。它的做法是在查询阶段,把同一次检索的结果切成两段:

# 伪代码,只表达结构
top_head = results[0:5]    # 前 5 名
top_tail = results[5:20]   # 第 6 至 20 名

然后对比这两段:如果毒化内容存在,答案锚点会集中在头部,且出现“载体转换”——同一个被塞进去的答案换着说法反复出现。头部和尾部对同一查询的应答分布差异过大,就是信号。这个设计我一开始没搞懂为什么要切在 5 和 20,后来想明白它本质上是在拿系统自己的长尾当对照组,尾部大概率没被攻击者覆盖到,这就是“自参考”三个字的实际含义。

RSG(RAGSieve-Graph)则更靠前,在查询到达之前就跑。它对语料库里每个文档,找语义相似但用词不同的近邻文档做对比:

doc_i vs. neighbor(doc_i, 语义近、词面远)
→ 一致性异常高的簇 → 标记为协调密度

攻击者要保证毒化内容被检索到,往往得批量铺文档,铺出来的簇在“意思相近但措辞本该分散”这件事上会露馅。这一步是可以做成离线批处理的,挂进 CI 里每天跑一次也不贵。

验证部分我重点看了数字,因为检测类方法不看 AUROC 等于白读。三个问答数据集、六种投毒构造下,RSQ 拿到 95.2% AUROC,移除 5% 干净文档时检出 82.2% 的投毒,基线 GMTP 对应只有 81.1% 和 52.5%。RSG 是 93.3% 和 79.8%,基线 CleanBase 是 79.4% 和 37.6%。最有说服力的是联合部署那条:攻击成功率从 67.4% 压到 14.0%,同时干净检索的 F1 还有 41.3%——说明这不是靠把检索结果大面积误杀换来的安全。

你可以照着这个顺序在自己系统里试一遍:

  1. 先把检索结果按 5/20 切段,跑一批正常查询,记录头尾应答分布差异的基线;
  2. 手工构造几条投毒文档插进语料库(自己造的攻击样本只用来验证,不进检测逻辑本身);
  3. 对比插入前后的分布差异,看信号是不是真的分得开;
  4. 语料库侧跑一遍近邻一致性扫描,看投毒簇能不能被单独圈出来;
  5. 拿误杀率换检出率,找到自己业务能接受的那个平衡点,别照抄论文的阈值。

留一个坑:第 3 步里“分布差异”具体用什么度量,论文的细节我还没啃透,我打算先用最朴素的答案重叠率跑一版,跑通了再回头对论文。这里我也没完全搞懂原理,但先复现行为、再补理解,这个顺序对我来说一直是有效的。

划重点:

  1. 不需要干净对照语料的检测方法,对大多数没有这份奢侈的团队才是真正可用的方法,RAGSieve 的价值首先在这里;
  2. 检测类方法必须同时看检出率和误杀代价,14.0% 的残余攻击成功率配上 41.3% 的 F1 才是完整结论,单看前者没有意义;
  3. 查询侧和语料侧各布一道,比只在任何单侧加过滤更稳,两道防线的组合方式值得抄。

这篇就记到这里,等我把自己那版的第 3 步跑出来,回来补一条实测笔记。

abanana
abanana

把自己踩过的坑整理成一篇能复现的笔记,写给三个月前的自己看。

查看主页 →