跳到主要内容

没人召集的索引策略委员会:超越一次性迁移的 RAG 语料库治理

· 阅读需 11 分钟
Tian Pan
Software Engineer

两年前,一个团队将他们的检索索引指向了 Wiki、Zendesk 导出文件以及公共文档的快照。上周,同一个索引返回了一个已弃用的运行手册(runbook),告诉 SRE 去重启一个已不存在的服务。该运行手册已经废弃了 18 个月。没人负责它的下线工作,所以没人把它删掉。Agent 自信地引用了它。模型没有错;错的是语料库(corpus)。

这是检索评估(retrieval evals)中不会出现的故障模式:语料库被视为一次性的工程决策,而实际上它是一个持续的治理问题。负责初始摄取(ingestion)的团队早已解散。本应标记出客户机密 PDF 的法律审查从未发生,因为没人告诉法务部门存在这个流水线(pipeline)。“新鲜度策略”(freshness strategy)只是一个在第三季度离职的人留下的 Slack 消息。检索索引变成了任何人抓取过的每一份文档的共享收件箱,而纳入标准已逐渐演变为“任何容易摄取的内容”。

大多数事后分析(postmortems)中没有提及的架构共识是:检索索引是一个具有编辑标准的产品展示面,而不是一个搜索后端。 如果你把它当作后者对待,你交付的系统就会根据相互矛盾的来源产生幻觉(confabulates)、跨租户泄露、呈现法务原本会禁止的内容,并在有人注意到之前悄无声息地退化数年。

解决方案不是更好的 Embedding 模型。而是一个索引策略委员会——以及他们每个季度需要讨论的四个维度。

法律维度:没人告诉法务你的 RAG 流水线

语料库第一次出现在监管对话中不应该是在事故发生后。但通常情况就是如此。RAG 跨越了法律、信息治理和 IT 部门,并且是在任何控制框架之外运行的 AI 团队内部构建的。语料库继承了抓取者的访问权限,而不是查询用户的权限。

具体的故障模式已有详尽记录。跨租户泄露(Cross-tenant leakage)是最受关注的:在针对多租户 RAG 部署的渗透测试中,由于向量相似度是唯一应用的过滤器,用户 A 的查询检索到了属于用户 B 的文档。一项已发表的红队研究报告称,在尝试的每一次查询中,跨租户检索都成功了——20 次尝试中成功了 20 次——且不需要任何高深的技术。向量数据库在设计时从未将单文档访问控制作为一等公民功能,而编排层则完全信任排序器(ranker)。

虽然声响不大但更常见的是:受监管的内容。由于在摄取时没人对来源进行分类,Agent 不得呈现的内容最终被编入索引。CRM 导出中的个人隐私信息(PII)、从共享驱动器中提取的客户机密幻灯片、尚未生效的草案策略——所有这些都被切片(chunked)和嵌入(embedded),却没有任何强到足以过滤的出处元数据。当有人注意到 Agent 向错误的受众引用机密路线图时,切片已经存在于索引中了,而你并没有一个清晰的溯源链来将其下线。

弥合这一差距的方法是为每类来源(per-source-class)制定政策并指定负责人。每个来源类别——公共文档、内部 Wiki、支持工单、Slack 导出、CRM、代码注释——在摄取时都会获得一个分类:谁被允许检索它,它属于哪个租户范围,它属于哪个监管类别。分类作为元数据跟随每一个切片,检索时的过滤器在数据库层强制执行,而不是在应用层。如果你唯一的执行点是“提示词(prompt)只包含用户应该看到的结果”,那么你已经输了;提示词是在泄露发生之后的下游。

新鲜度维度:每类来源都有自己的衰减率

一个常见的错误是把“RAG 新鲜度”当成一个单一的数字。事实并非如此。每类内容都有不同的衰减率(decay rate),统一对待它们会产生可预见的失败。

昨天的产品规格书是黄金。如果上季度的事故回顾(incident retro)与当前行为相悖,那它就是毒药。一份两年前的架构概述可能仍然是系统上最好的文档;一份两周前的支持工单可能已经错了,因为 bug 已经被修复了。“当前产品功能”的正确重索引频率是每天;对于“公司历史”,频率可能是永不。没有一个全局新鲜度阈值能同时满足这两者。

行之有效的模式是:为每个来源类别定义刷新频率,监控每个类别的最大陈旧度(staleness),并在超过特定阈值时报警。对于高频变动的来源——任何由每小时发布更改的创作工具支持的内容——你需要流式或近实时的流水线,而不是夜间的批处理。对于低频变动的来源,批处理是可以的,但删除路径比刷新频率更重要。

删除是大多数团队卡壳的地方。许多向量索引不支持干净的增量更新,因此团队最终会运行“暂存与交换”(staging-and-swap)模式:插入带有临时标志的新向量,原子性地提升它们,然后清理旧向量。这可行,但前提是系统确实有“旧”的概念。如果在摄取切片时没有 source_doc_idsource_version,你将无法识别哪些向量属于已弃用的文档。你最终只能重建索引,这意味着你的“删除”取决于重建频率,而重建通常是每季度一次,这就是为什么已弃用的运行手册能存活两年的原因。

一个可持续运行的语料库所需的最低元数据:来源文档 ID、来源版本、摄取时间戳、来源类别、负责人、过期时间。过期时间是不太起眼但大多数团队都会跳过的一个字段。它是唯一能将删除从手动考古项目转变为计划任务的字段。

作者-信任轴:Slack 线程不是运维手册

当语料库同时包含一份正式发布的运维手册,以及一段争论该手册是否正确的 Slack 线程时,如果将它们的来源质量视为对等,就会在无形中教会 Agent 产生幻觉。检索排序器(Ranker)并不知道哪一个代表了团队经过深思熟虑后的观点。如果 Slack 线程更近期,它的排名可能会更高。如果运维手册与其矛盾,Agent 现在就有了两个答案,并且会选择与查询请求的嵌入(Embedding)更接近的那一个。

来源质量不是查询时的相关性问题,而是摄取时的编辑决策问题。权威来源需要被标记为“权威”。临时来源——如 Slack、草稿、走廊谈话摘要——需要被标记为“临时”。检索层应该能够做到在两者兼具时优先选择权威来源,并且只有在不存在权威来源时才回退到临时来源。如果没有这种层级结构,语料库的矛盾就会变成用户眼中的“幻觉”,即便模型在技术上确实是基于检索到的文本给出的答案。

实际的操作机制是为每个数据块(Chunk)设置权威层级:canonical(规范)、reference(参考)、provisional(临时)、historical(历史)。“规范”是指编辑签字认可的内容。“参考”是社区维护但非编辑控制的内容。“临时”是任何未经审核的内容。“历史”内容保留用于提供上下文,但除非查询明确针对先前的状态,否则不应被返回。排序器将这些层级用作硬性过滤器或强先验概率,具体取决于使用场景。

这听起来很沉重,得到的反馈通常是“我们没有足够的编辑精力来做这个”。这没问题——但那你同样没有精力去调试为什么 Agent 会自相矛盾,并且在它给出错误答案并上线时,你绝对没有精力向客户解释。编辑纪律的成本是预先支付的;跳过它的代价则是永远在复合型的补救中支付。

所有权轴:语料库无人负责,准入门槛随之漂移

最深刻的失败是结构性的。没有任何一个团队真正拥有“语料库”。AI 团队负责检索流水线。文档团队负责发布的文档。支持团队负责工单归档。法务负责合规。安全负责访问策略。每个团队都只有局部视野,没有人拥有决定 Agent 实际看到内容的决策合集。

在缺乏所有权的情况下,发生的事情是可预见的:准入标准会向“任何易于抓取的内容”漂移。一个包含十行代码的 Notion 连接器被合并,是因为有人为了演示需要它。一个 Google Drive 摄取任务在运行,是因为某个利益相关者的要求。六个月后,没有人记得是谁批准了这些,准入标准变成了“是否有人强烈反对”。

解决办法并不隐晦。指定一个所有者。召集一个真正的委员会——涵盖产品、文档、法务、安全和 AI 团队——像对待 IAM 权限授予一样对待索引决策。每种来源类别都有明确的所有者、准入标准、更新频率、保留策略和删除路径。委员会每季度召开一次会议,审查索引中的内容,就像安全团队审查生产环境的访问权限一样。没有所有者的来源默认被停用。

这在行政上很无聊,在政治上也不舒服,所以没人愿意自荐。但另一种选择——那个没人召集的索引政策委员会——正是那些正在为失败埋单的人。把检索索引视为编辑产品,编辑成本就会出现在某个人的路线图上。把它视为搜索后端,成本就会出现在故障复盘(Postmortem)中。

当治理落实时,会带来什么

一个真正受治理的语料库具有显而易见的属性:每个数据块都有溯源元数据,因此回归测试中的问题可以追溯到教错 Agent 的那份文档。每个来源类别都有对应的政策、明确的所有者、准入标准、更新频率和删除路径。检索时的过滤器在数据库层强制执行,跨租户检索被视为常规的红队演练,而非一次性的审计。权威层级让排序器能够优先选择规范来源而非临时来源。每季度一次的审查,委员会阅读准入名单,并针对每个来源询问:我们是否仍然相信这属于索引?

这些都不需要新的向量数据库。不需要更智能的排序器或更大的嵌入模型。它需要的是一种纪律,即承认“什么进入检索索引”不是一个一次性的工程问题,而是一个由负责的人持续提出的编辑问题。

做对这些的系统看起来会比那些不做的系统更慢、更官僚——直到出现问题。到那时,“我们能识别出是哪份文档导致了问题并在一个小时内撤回它”与“我们必须在下个季度重建索引并寄希望于此”之间的区别,就成了可修复的 Bug 与结构性问题的区别。检索索引是一个产品界面。要么你决定上面有什么,要么你的爬虫替你决定。

References:Let's stay in touch and Follow me for more thoughts and updates