保持向量存储的可靠性:生命周期管理、租户隔离、元数据处理、混合搜索机制。
在生产环境中运行用于RAG的向量存储:文档生命周期管理、嵌入更新、租户过滤、针对精确ID的混合搜索以及元数据与追踪功能。
来源: Vector Store Operations: What Keeps RAG Retrieval Correct in Production
一名现场技术员向内部支持人员询问如何更换液压泵。回复看起来很正确:选对了设备系列,选对了泵的类型,步骤也合理。但这条回复已有半年之久。最新的公告要求在安装泵之前先进行固件升级,而旧公告中从未提及这一点。这两份公告都存放在向量存储中,新公告已被正确索引,却没人删除旧公告。该模型并没有产生任何错误信息,只是得到了过时的信息而已。
这类问题决定了检索系统是否值得信赖。
- 目前可以检索到该文档的哪个版本?
- 内容获批后多久才能被搜索到?
- 一个客户会不会看到另一个客户的内容?
- 当用户搜索确切的零件编号而非大致描述时会发生什么?
这些都与模型质量无关,而是向量存储系统日常运营中的要求。
一个具体示例:多租户技术支持
设想有一个供多个国家设备经销商使用的支持平台,该平台存储有产品手册、维修公告、零件目录、保修政策、维护流程以及各经销商撰写的备注。技术人员可以查询其所在地区针对MX-204液压泵5.2版本的官方更换流程是什么。
那并非普通的语义搜索。系统必须理解维护意图,保留MX-204 5.2版本等精确标识符,返回当前的维修流程,应用正确的区域政策,同时排除属于其他经销商或账户的内容。单纯的相似度查询无法提供这些保障。检索层必须表现得像一个受管理的信息服务。
将索引视为文档发布管理
早期的RAG系统通常将索引视为一个单一流程:上传、分块、嵌入、写入,完成后即可。此后文档会一直可被搜索,直到有人发现问题。随之而来的故障很容易预测。
- 修订后的手册会与旧版本并存。
- 政策草案在获得批准之前就已可被搜索。
对于支持语料库而言,最基本且有用的生命周期状态集合如下:
- 草稿状态:已接收,尚未批准可供检索。
- 候选状态:已索引,正在验证中。
- 活跃状态:已批准,可被检索。
- 已被替代状态:被更新版本取代,为审计目的而保留,对普通查询隐藏。
- 隔离状态:由于验证、元数据检查或内容审核出错而被暂存。
- 已删除状态:已从语料库中移除,必要时也会从底层存储中删除。
有一条规则至关重要:搜索仅应涉及处于“活跃”状态的文档。这一规则必须通过元数据过滤器来强制执行,而不能依赖文件命名习惯或提示词中的指令。
每份文档还需要一个稳定的文档ID和一个独立的版本ID。前者用于标识该逻辑资源,比如某份维修公告,后者则用于标识其某个修订版本。批准新的修订版本后会激活该版本并标记旧版本已被取代,且这一切换应当以原子方式完成。有了这样的机制,系统就不会再返回那些相关但已失效的内容。
嵌入内容刷新:增量式、版本化、可逆
嵌入内容的刷新通常被描述为在模型发生变化时需执行的任务。但实际上触发刷新的情况更为多样:
- 源文档被编辑。
- 某项策略达到其生效日期或过期日期。
- 元数据架构不断扩展。
- 分块策略持续优化。
- 嵌入模型得到升级。
- 某文档被撤下或重新分类。
- 租户的权限发生变动。
每种情况都需要不同的处理方式。修订后的公告可能只需更新相应部分;新的嵌入模型则可能需要重新构建所有内容;新增的元数据字段则需要有序地回填数据,而被撤下的文档必须立即从活跃索引中移除。
因此,刷新流程应追踪四个版本:源代码版本、分块逻辑、嵌入模型以及用于过滤的元数据架构。若没有这些记录,就无人能解释为何在检索时两个分块会表现出不同行为。
在实际操作中,会通过内容哈希或结构化差异对比来将新上传的文件与当前版本进行比对。发生变化的部分会被重新分块并重新嵌入,而未受影响的部分则保持原样,除非分块或嵌入方式发生了变化。
对于大型模型的升级,则需要采用更安全的流程:先构建一个并行候选索引,同时对两个索引运行评估查询,检查访问控制机制,只有当新索引的表现达到预期标准时才将流量引导过去。关键问题不在于新模型在基准测试中的得分是否更高,而在于新索引能否为用户实际发送的查询返回正确且经过审核的证据。
应在检索之前而非之后实施租户隔离
多租户RAG中一种危险却常见的设计缺陷是在搜索之后才按租户进行过滤。系统会先广泛检索,然后再剔除属于其他组织的结果。但为时已晚。在开始任何向量或关键词匹配之前,就必须通过租户和访问过滤器来确定候选范围。
在支持平台上,内容可分为三类。
- 全局内容:制造商手册及共享的安全规程。
- 经销商内容:内部服务指南、商业协议及本地操作说明。
- 客户内容:资产历史记录、合同条款及机密操作笔记。
它们无需采用相同的存储结构。全局内容可以共享一个语料库,而经销商内容则可以共享由强制性的租户过滤器保护的索引。根据监管要求、合同规定及风险控制需求,高度敏感的客户可能需要拥有自己的集合或独立的索引。
租户信息、角色、地区、产品权限以及保密级别必须来自已验证的会话,绝不能来自查询语句中的文字。技术人员在查询中输入其他经销商的名称时,不应能够改变过滤条件。实际上,检索请求只会指定搜索该已验证用户有权访问的内容,只有在此之后才会进行语义或关键词排序。这样既能保护保密性,又能剔除无关结果。
用于精确标识符的混合搜索
当人们用日常语言描述问题时,例如询问在MX-204上安装替换泵之前需要哪一版本的固件,密集向量搜索就能发挥优势。而部件编号、控制器代码和版本字符串的表现则不同,词汇索引在实现精确匹配方面更为有效。
在MX-204的案例中,词汇检索可能会找到包含控制器和泵标识信息的准确公告,而密集检索则会提供相关的维护指南。随后可通过重新排序机制优先选择包含固件要求及规范操作流程的文档。
当检索效果不佳时,向上下文中添加更多内容往往毫无帮助。增加顶部k个结果只会带来更多噪声和延迟,还可能得到毫无依据的错误答案。更好的做法是找出是哪个环节出了问题。
- 是否是正确的文档处于非激活状态?
- 是否因为元数据过滤器存在故障而将其排除?
- 词汇搜索是否遗漏了其他部件编号格式?
- 重新排序机制是否更倾向于选择范围更广的文档而非更具体的文档?
这些都是可以衡量的系统问题。
元数据作为控制平面
元数据通常被视为在数据导入时附加的可选标签。在实际应用中,它决定了系统可以检索哪些内容。一个实用的架构涵盖五个方面。
- 身份标识:源文档、数据块的来源系统以及内容哈希值。
- 生命周期:版本、审批状态、生效日期与过期日期,以及哪些版本具有优先级。
- 访问权限:租户ID、区域、角色权限、产品访问权限、保密等级及法律限制。
- 检索信息:文档类型、语言、设备型号、组件系列、产品线以及内容类别。
通过这种结构,原本复杂的问题可以转化为简单的查询。哪些正在使用的文档仍在使用旧的嵌入模型?哪些修复流程下个月就会过期?哪些数据块缺少区域元数据?哪个租户的空结果比例最高?哪些源系统导致了最多的数据摄入失败?
在文档进入活跃语料库之前,必须对其元数据进行验证。那些没有租户范围、生命周期状态、产品线或审批状态的数据块,绝不能仅仅因为已生成嵌入值就具备搜索功能。许多RAG系统正是在这一点上变得不可靠:数据库按设计正常运行,但元数据模型过于简单,无法体现组织在访问控制、生命周期管理及政策方面的实际规则。
能够定位出出错环节的可观测性
当用户反馈答案错误时,可能是多种问题导致的。正确的来源可能从未被索引,或虽被索引但被标记为无效,或被过滤器过滤掉。它也可能进入了候选集但排名过低。它还可能进入模型上下文却被忽略。又或者模型输出了证据无法支持的内容。每种情况都需要不同的解决方案。
因此,成熟的检索服务会记录完整的路径:
- 查询内容及用户上下文。
- 所应用的访问及生命周期过滤器。
- 密集候选项与词汇候选项。
- 融合后的排名结果及重新排序器的输出。
- 传递给模型的最终证据。
- 答案中引用的参考资料。
有效的措施包括源内容批准与索引激活之间的延迟时间、当前嵌入版本中活跃内容的占比、存在多个活跃版本的文档数量、不同查询类型的无结果率、已知答案测试的覆盖率、过滤被拒率以及任何尝试跨租户访问的行为。
一个实用的指标是候选项覆盖率:对于有已知答案的查询,在重新排序之前,正确的源内容是否出现在候选项中?如果没有,就需要检查索引构建、过滤机制或搜索设计。如果出现了但排名靠后,则需审视融合处理或重新排序机制。如果排名良好但系统仍忽略该答案,问题就出在内容生成或提示词组合上。将各个阶段分开处理,可以避免团队试图仅通过修改提示词来解决所有问题。
操作流程
向量存储应当与任何生产级数据服务一样遵循严格的规范。日常检查应关注数据导入失败情况、刷新任务积压、卡在待处理或隔离状态的文档、缺失的必填元数据以及从索引创建到实际可用之间的延迟。每周审查则需针对多种查询类型检测检索质量,包括对话式问题、纯代码、产品名称、政策查询、其他语言的搜索以及模糊的请求。
对于分块方式、嵌入模型、元数据架构或访问策略的任何更改,都应首先在测试环境中进行验证。评估集需要包含真实用户的查询、已知答案的案例、访问控制测试,以及用于检测租户信息泄露或过时内容的查询。
目标并非获取更多文档,而是在恰当的时间将正确的、经过审核的证据传递给合适的用户。向量存储并非聊天机器人背后的被动数据库,因为它能决定哪些证据可以被用来形成答案。如果过时的文档仍保持活跃状态,租户过滤功能就变得可有可无;在语义匹配中标识符会消失,或者元数据无法表达业务规则,那么无论模型多么强大,系统都会不可靠。
相关阅读
- 利用ChromaDB与嵌入技术构建企业多智能体平台的语义检索系统 —— 将企业多智能体平台转向真正的语义检索:基于词义的分块处理、ChromaDB中的余弦距离、测试层以及下一个RetrievalAgent步骤。