检索增强生成 RAG 先检索资料,再让模型基于资料回答。企业知识库的常见故障是:制度已更新,回答仍引用旧条款;只改动了一个章节,却检索到新旧片段拼成的“混合制度”;源文件已删除,缓存答案仍然存在。解决这类问题需要可验证的版本发布流程。本文提出一套工程设计,并明确平台原生保证与应用层需要补足的边界;示例均为构造场景,没有声称实际运行实验。
先区分接收、搜索可见与业务激活
一次文档更新至少有三个时刻:管道接收变更、派生索引能够检索到变更、业务允许将该版本作为回答依据。三者可能接近,但不能因为接口返回成功就视为同一时刻。Qdrant 文档说明,默认或 wait=false 返回的 acknowledged 仅表示收到操作;wait=true 则等待操作完成并使向量可搜索。[1] 这一等待机制仍不能替应用证明整篇文档的所有片段和其他索引都已准备齐全。
Elasticsearch 的 refresh 参数控制变更何时对搜索可见,refresh=wait_for 等待刷新,而 refresh=true 会主动刷新并增加索引处理成本。[2] 两个平台的具体语义不同,应分别核对部署版本、复制和读一致性设置。不能把某个接口的等待参数扩展成跨系统事务保证。
本文把“激活”定义为应用层允许检索器使用某个文档版本的决定。激活需要同时满足内容完整、检索路径可见和访问策略有效。对于允许短期旧版本继续服务的文档,准备新版本时可以保持旧版本;对于已撤销或明确失效的资料,应先禁止使用,不能为了可用性继续引用失效内容。
用版本清单描述整篇文档,而不是只记录向量数量
建议为每篇文档建立稳定 documentId,并为一次源修订生成不可变 revisionId。每个片段的标识由文档、修订和片段位置组成,同时记录源内容指纹、解析器版本、分块规则版本、嵌入模型标识和访问策略版本。修订标识可以是不可排序的唯一值,但另需可靠的源顺序用于判断新旧;不要把到达时间当作源版本。
文档版本清单保存预期片段标识集合、数量、内容指纹、源地址、有效期与各索引处理状态。只检查“写入了 20 个向量”不足以证明完整,因为可能重复写入某些片段而遗漏其他片段。应比对标识集合和指纹,并检查解析是否把表格、附件或重要段落遗漏。合法的空文档也需要明确的状态,避免与解析失败混淆。
清单应以当前解析结果为依据,而不是凭历史数量估计。若同一制度从 20 段变成 18 段,旧修订的两个残留片段必须被版本过滤排除。每片段携带修订标识,使答案能够追溯到完整源版本,也使后续清理不必依赖模糊的文本匹配。
准备—验收—激活:把切换做成可恢复的协议
第一步是准备。将新修订写入独立的片段命名空间或带修订标识的记录,不原地覆盖正在服务的旧片段。使用确定性片段标识,使重复提交同一内容能够收敛;同一修订标识对应不同内容时应报冲突。此时新数据存在于存储中,但检索器不能因此自动采用它。
第二步是验收。核对清单与实际片段集合,确认需要使用的关键词和向量路径都可见,检查访问元数据,并运行覆盖修改条款的查询。探针查询只能证明被检查路径,不能证明全部节点和所有查询都一致;完整性还应依靠清单对账与平台一致性语义。失败时保留待处理状态,旧版本是否继续服务取决于业务失效规则。
第三步是激活。权威元数据存储保存 documentId 对应的 activeRevision。使用事务或条件更新,在切换时再次检查当前源顺序、删除状态和访问策略,避免旧任务覆盖较新的激活结果。更新失败就重新读取状态,不能无条件重试覆盖。跨多个文档必须共同生效的制度包,可以用一个发布代次统一选择版本;单文档指针不能提供整个制度包的一致快照。
切换后再清理旧修订。旧数据保留便于排查和回滚,却增加存储成本,且必须继续受访问控制。回滚同样属于业务激活,要检查旧内容是否仍有效,不能把技术可恢复误当成业务允许恢复。高吞吐场景可批量准备和验收,再减少指针切换频次,以控制刷新和协调成本。
检索器必须执行版本门控,并处理查询中的切换
检索流程应在把证据交给模型之前,核对每个候选片段是否属于允许的修订、是否已删除、访问策略是否匹配。可在检索前过滤时,应尽早缩小范围;若平台不能直接表达动态版本映射,可先取候选,再通过权威版本清单筛选并补充检索。后置过滤会减少有效召回,必须限制补检次数,记录证据不足,不能让旧片段回填凑数。
一条查询可能跨越激活时刻。可以让请求绑定一个明确的发布代次,从头到尾使用同一组有效修订;也可以在组装上下文前再次核对并重新检索。前者需要保留版本快照,后者增加延迟和重试。无论选择哪种,都应避免将同一文档的两个修订混入同一答案。请求快照不能覆盖后来发生的访问撤销,撤销需要单独的强制检查。
版本与权限是相互关联的条件。权限感知的企业 RAG 已说明身份、证据与访问范围如何绑定;这里补充的是更新期间如何保持同一版本的完整性。若权威版本或撤销服务不可用,高风险知识应拒绝生成或转人工,普通资料是否允许带截止时间的降级,应由明确策略决定。
删除先形成拒绝规则,再异步清理副本
源文件不存在不代表索引中的资料已经不存在。Azure AI Search 的存储索引器文档区分变更检测与删除检测,要求从首次运行就配置删除策略;使用原生软删除时,索引器必须在软删除保留窗口内处理对象。[3] 这些是该索引器的适用条件,而不是所有 RAG 平台都会自动提供的能力。
本文建议先在权威状态中记录删除或撤销,并建立带源顺序的删除高水位,即该文档已被处理的最新删除版本。检索入口据此禁止旧修订,随后清理向量、关键词索引、片段原文、派生摘要及相关缓存。清理任务需要逐项回执和重试状态;查询不可见与物理副本清理完成是两个独立验收结果。
高水位防止旧更新迟到后复活文档,但只有源版本可比较时才有效。同一来源可采用受控递增修订或其他明确顺序,不能直接比较不同系统的时间戳或日志位置。高水位保留期要覆盖允许回放的历史范围;历史太旧、顺序不可判定或源已换代时,应隔离任务并重建基线,而不是猜测新旧。
恢复被删除资料必须是源端明确的新动作,并经过权限和版本验收,不能因为重试队列里还有旧上传任务就重新激活。对于已经发出的答案,技术上无法撤回读者已经获得的文字,因此需要精确定义撤销承诺是阻断后续证据使用,还是还包含特定存储副本的清理。
答案缓存和会话上下文也属于派生数据
缓存键至少需要覆盖查询语义、租户、访问范围及所依赖的版本信息。缓存条目应保存证据依赖集合,命中后检查这些依赖是否仍有效。只把模型版本放进缓存键,无法发现制度更新;只按查询文字共享缓存,还可能混淆不同用户的访问范围。
依赖很多时,可按发布代次使一批缓存整体失效,代价是命中率下降和重新生成成本上升;精确按文档失效则需要维护反向依赖。缓存命中不得绕过撤销门控。对于已装入长会话的旧资料,应在下一次生成前重新检查依赖,必要时移除对应上下文或重新建立会话。仅删除向量并不能清除模型已接收的文本。
检查时也要覆盖查询结果缓存、重排结果和预生成摘要。若一个摘要综合了多篇文档,必须能够追溯其依赖,或者采用更保守的整批失效。日志与备份的保留、清理和恢复规则应另行记录,不能把在线检索拒绝等同于所有历史副本已经消失。
构造故障推演:一个漏片段如何变成混合答案
以下为构造示例。文档 D7 的 V4 有 12 个片段,新修订 V5 有 11 个片段,并改写了维修审批条件。向量路径只完成了 10 个新片段,关键词路径仍保留 V4。若应用一收到写入回执就标记更新完成,向量检索可能召回新说明,关键词检索则召回旧审批条款,最终答案把两者混在一起。
按上述协议,V5 清单验收发现缺少一个片段且另一检索路径未就绪,激活保持 V4;若 V4 已失效,则暂时不给出该制度的确定答案。补齐 V5 后,确认片段集合、路径可见与策略一致,再条件切换 activeRevision。这里的 12、11、10 只是说明故障的示例数量,不是性能结果。
再设 V6 是删除事件,V5 的延迟上传随后到达。删除高水位应阻止 V5 激活,清理过程即使未完成也不允许它进入新回答。若一条查询在删除前已取到 V5,生成前的撤销检查应拦截后续使用。系统还应记录检查与输出之间剩余的竞态窗口,并按承诺采用请求取消或更紧的协调;不能声称一次检查提供了绝对瞬时撤销。
用四类指标和故障测试证明更新成立
新鲜度延迟定义为源端变更提交到新修订完整激活的时间,可分别记录接收、解析、索引可见和验收阶段,并报告分位数及最长失败积压。源端没有变化时,最后一篇文档年龄大并不一定表示管道故障,应结合心跳与源进度。目标值由业务时效决定,没有通用的“几秒必达”标准。
修订完整率的分母是应激活的修订,分子是清单、索引和策略验收全部通过的修订;混版违规次数统计单次回答证据中同一文档出现不允许组合的修订。删除生效延迟从权威删除提交到服务入口稳定拒绝旧证据,物理清理完成时间单独记录。计数为零只能说明测试覆盖内未发现违规,不能证明未来绝不会发生。
验收用例应覆盖漏片段、重复写入、两条更新乱序、删除后旧任务回放、缓存命中旧答案、权限变更与内容更新同时发生,以及激活前后进程退出。每个用例固定源版本、期望可用证据和失败行为,既检查检索结果,也检查最终回答的引用修订。上线交付应保留版本清单、激活回执、删除清理账本和可重跑的测试输入,使“知识库已更新”成为可核对的状态。
