跳到主要内容

十篇无害文档怎么占掉整个 top-k——读 Coverage Is Not Containment 的踩坑笔记

abanana
abanana

· 阅读约 4 分钟

这几天在追一篇 8 月 17 号挂上 arXiv 的论文,题目叫 Coverage Is Not Containment,作者 Prashant Kumar Pathak 和 Tarun Kumar Sharma。讲 RAG 投毒攻击的。真正让我坐直的是它的结论:所有在摄入阶段做的防御,理论上就不可能挡住这类攻击——不是“现在的防御不够好”,是“这个位置上的防御原理上不行”。第一遍读的时候我没读懂它凭什么说得这么死,这篇笔记把我后来想明白的这条论证链记一下。

先把攻击本身拆开看看。它不是往库里塞一篇充满恶意关键词的文档,那种老早就会被过滤掉。它的做法是生成一批单独看完全无害的文档,每一篇都普普通通,但它们在向量空间里共同围绕一个目标查询,把 top-k 检索结果整个占掉。数字挺吓人:BGE-large 编码器加 BEIR 基准,10 个目标全中;实时 HNSW 索引上 10 个中 9.9。端到端那条更直接——BGE-large + HNSW + Qwen2.5-7B 的流水线,注入之后生成模型在 88% 的目标上输出了攻击者想要的声明,不注入的时候这个比例是 0%。

到这里为止我都还觉得,“行,又一篇攻击论文,防御方再卷一卷总能跟上”。真正的问题是下一层。

论文里被点名打掉的防御,是那种“在文档摄入时过滤掉类似中心节点文档”的策略——直觉上很合理,攻击文档要围住一个查询,位置上总会有点聚集性吧。但协调攻击恰恰可以不聚集:每一篇单独看都落在合法内容的分布里。论文里有个实验我觉得设计得很狠:给分类器所有特征、几千个标注样本,让它区分攻击文档和合法的小众上传内容——结果不比随机猜好,1% 假阳性率下只能抓到 4.2% 的攻击。而且这不是某个分类器不行,论文从理论上证明了任何只依赖文档本身和参考查询的摄入时统计量,都区分不了这两者。

为什么?我一开始没搞懂,后来才想明白关键词是“合法的小众上传”。任何一个开放接受上传的向量库,都会有大量真实的、冷门的、只服务极少查询的内容。攻击文档在几何上和这类内容是不可区分的——它们都是“离主流远、只对特定查询有意义”。你要是把这类全拦了,等于把长尾内容全清了,检索系统自己就废了。攻击者不需要伪装成热门内容,只需要伪装成没人看但真实存在的东西,而后者是永远不能一刀切掉的。

所以唯一的区分信号不在文档侧,在查询侧:有没有人真的在搜这个东西。攻击文档对应的查询需求是零(或者说攻击者自己控制的),但这个信号在检索发生之前根本看不见。论文顺着这条线给了个对照:检索时的检测器如果能观察到需求信号,同样 1% 假阳性率,能抓到 100% 的攻击。一边是摄入时随机水平,一边是检索时全捕获,这个对比基本把结论钉死了——覆盖不等于遏制,想靠把守入口解决问题,方向本身就不成立。

顺带记一句,攻击在两个语料库、五种编码器上都能复现,所以也不是 BGE 一家的问题。

这条记下来了,下次应该用得上。具体用在两个地方:一是以后看到任何宣称“摄入时过滤就能防投毒”的方案,先问一句它拿什么区分攻击和合法长尾,答不上来的直接跳过;二是自己搭 RAG 的时候,监控点要放在查询侧而不是上传侧——top-k 结果突然被一批新文档集体占据、且这些文档几乎只被同一个查询命中,这种模式在检索日志里是看得见的,在摄入流里是看不见的。

论文我没跑复现,只做了思想实验层面的核对,这点老实交代。等手头这个项目忙完,打算拿本地的库把“需求信号检测”那部分试一遍,真跑通了再补一篇。划重点:第一,协调投毒的每一篇文档都可以单独无害,聚集性过滤对它无效;第二,摄入时防御的失败是理论性的,不是工程没调好;第三,需求信号是唯一区分点,而它只在检索时可见——防御的重心得跟着挪到检索侧。你可以拿自己手上的 RAG 系统问一句:我的 top-k 被占领了,我要多久才能发现。答不上来的话,这篇论文值得读一遍。

abanana
abanana

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

查看主页 →