什么是数据投毒?RAG 知识库怎么防投毒?

进阶安全原理约 6 分钟读完

一句话回答

数据投毒是攻击者往模型会"学到"或"读到"的数据里掺入恶意内容。分两类:训练数据投毒影响模型本身,比如植入后门,遇到特定触发词就输出攻击者想要的内容;检索数据投毒往知识库或会被检索到的网页里放误导信息或带指令的内容,影响 RAG 的回答。对大多数应用团队来说,后者更现实。RAG 防投毒的重点是管住入口:控制知识库的写入权限和来源、入库前审核、标记来源可信度,回答时给出引用便于核对,并检测异常内容。

详细解析

两类投毒

训练数据投毒 检索数据投毒
投毒位置 预训练语料、微调数据集、公开下载的模型和数据集 知识库文档、用户上传的文件、会被搜索到的网页
影响范围 模型的参数,所有使用这个模型的应用 检索到这些内容的回答
持续时间 训练后长期存在,难以发现和清除 入库即生效,删除文档即可清除
典型后果 后门、偏见、特定问题上的错误回答 错误答案、钓鱼链接、间接提示注入
主要防守方 模型提供方;自己微调时由自己负责 应用开发者

检索投毒为什么有效

  • 抢排名:攻击者针对某类问题写一段"看起来最相关"的内容,让它在检索时排到前面。向量检索按语义相似度排序,不判断内容真假
  • 不需要大量篡改:模型倾向于相信上下文里的资料,错误内容只要进入检索结果的前几条,就可能被采信
  • 夹带指令:文档里藏着写给 AI 的指令,这就和间接提示注入重合了

所以两者的关系是:带指令的投毒,是间接提示注入的一种投递方式;只含错误事实的投毒不需要任何指令,"把外部内容当数据"的防御对它无效,要靠来源可信度和核对机制。

RAG 知识库的防护

  1. 控制写入:谁能往知识库里加内容、加到哪个范围,要有权限控制和审计日志。用户上传的文件只进入他自己的检索范围,不影响其他人
  2. 来源分级:官方文档、内部系统同步的数据标为高可信;外部网页、用户投稿标为低可信,审核后才能被检索,或者只在特定场景使用
  3. 入库检查:检测隐藏文字、像是写给 AI 的指令、短时间内大量相似的文档、和已有权威内容矛盾的说法,命中就转人工审核
  4. 检索时利用可信度:排序时给高可信来源加权;把来源和可信度一起放进上下文,让模型优先采用可信资料
  5. 回答给出引用:用户能点开核对原文;资料之间有矛盾时如实说明
  6. 可追溯、可回滚:知识库有版本记录,发现投毒后能查到是谁、什么时候加的,批量清理并重建索引

训练数据和模型投毒

自己微调时:只用可信来源的数据,训练前去重、过滤、抽样人工检查;用独立的评测集和红队测试检查模型行为有没有异常。下载开源模型时:从可信来源获取并校验文件哈希;优先使用 safetensors 格式的权重,pickle 格式的文件在加载时可能执行任意代码。

代码示例

入库时按来源和检查结果决定文档的状态,检索时只使用审核通过的文档。hasHiddenText 等检查函数可以用规则或小模型实现,它们只是送审的信号,不是最终判断:

TypeScript
type Trust = 'official' | 'internal' | 'external'

async function ingest(doc: { content: string; source: string; uploaderId: number }) {
  const trust: Trust = classifySource(doc.source) // 按来源系统或域名判断可信度
  const flags: string[] = []
  if (hasHiddenText(doc.content)) flags.push('hidden_text') // 隐藏文字、注释里的内容
  if (looksLikeInstruction(doc.content)) flags.push('instruction') // 像是写给 AI 的指令
  if (await isSimilarBurst(doc)) flags.push('burst') // 短时间内出现大量相似文档

  await db.documents.insert({
    ...doc,
    trust,
    flags,
    contentHash: sha256(doc.content), // 便于追溯和批量清理
    // 只有非外部来源、且没有异常信号的文档自动生效,其余进入人工审核
    status: trust !== 'external' && flags.length === 0 ? 'approved' : 'pending_review',
  })
}

// 检索时只查审核通过的文档,并把来源和可信度一起放进上下文
const chunks = await vectorSearch(query, { filter: { status: 'approved' }, topK: 20 })

面试官可能追问

知识库只给公司内部员工用,还需要防投毒吗?

需要,只是力度可以不同。员工账号可能被盗用,也可能有恶意的内部人员;知识库同步的数据里常有外部来源,比如客户提交的工单、收到的邮件;过时的文档虽然不是恶意的,效果和投毒一样。写入权限、审计日志和版本回滚这几项无论如何都要有。

AI 搜索直接使用网页内容,没法在入库前审核,怎么办?

在检索结果上做控制:维护来源的信誉名单,降低或屏蔽低质量站点;关键结论要求多个独立来源交叉印证;医疗、金融这类问题优先使用权威来源;给出引用,让用户自己判断。网页内容同样只当数据处理,见 AI 搜索引擎的设计。

怎么发现知识库已经被投毒了?

定期用固定的评测集跑一遍问答,答案突然变化就排查;关注用户的点踩和纠错反馈;从答错的回答顺着引用找到源文档,再通过审计日志查到写入者,看同一来源还写了什么。也可以监控低可信来源的文档被检索到的频率,异常升高就要警惕。

易错点

  • 把投毒等同于提示注入:只含错误事实的投毒里没有任何指令,注入的防御手段对它无效
  • 以为检索排在前面就说明内容可信:向量相似度只代表相关,不代表真实
  • 允许用户上传的文件直接进入所有人共享的知识库

AI 模拟面试官

用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮

登录后就可以和 AI 面试官对练,面试记录也会保存下来。登录

这道题你掌握了吗?

选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。

学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。