首页 / 文章

无需重新索引即可切换RAG嵌入模型:rebase机制如何运作

无需重新索引即可切换RAG嵌入模型:rebasis通过一个小型适配器将新的查询向量映射到旧索引中,并告知何时进行桥接操作并无意义。

发布者:REACTAPP.TOP阅读约 18 分钟4078 词

来源: Changing the Embedding Model in a RAG System Without Deleting the Index: Why and How I Built rebasis

在检索增强生成系统中升级嵌入模型看似是件平常事,但当现有的向量索引成为障碍时就会出现问题。一款名为rebasis的开源Python工具正是为解决这一特定问题而设计的。它会训练一个小型适配器,将查询向量从新的嵌入模型转换到旧索引已能理解的向量空间中。这样一来,就可以推迟完整的重新索引工作,或者在监控下逐步进行。

该工具在统一的评估协议下尝试多种映射方式(居中正交普罗克鲁斯特斯变换、仿射变换、低秩网络以及小残差网络)。它不仅报告对齐质量,还会评估新模型在相关语料库上的实际提升程度,以及改进后的系统是否优于保持原有状态。通过配对自举法得到的置信区间、多种检索指标、编码设置的特征指纹、可复现的审计记录以及防崩溃的迁移流程,使得升级成为一个可量化的决策,而非凭直觉行事。

讨论的主题包括RAG、嵌入漂移、向量数据库、向后兼容性、模型迁移、检索评估以及近似最近邻搜索。

为何嵌入模型会陷入僵局

构建RAG系统需要的不仅仅是语言模型和向量数据库,还包括在索引创建当日所使用的嵌入模型的坐标系统。无论文档数量是数千份还是数百万份,都需要被分割、编码并存储到索引中。 sooner or later,总会出现更快、更好或更合适的嵌入模型,而问题就在这时出现了:新模型生成的查询向量对基于旧模型构建的索引而言毫无意义。

常见的建议是“直接重新索引所有内容”。从技术上讲这是正确的,但往往成本高昂。庞大的个人知识库、内部文档集、代码库或智能体的长期记忆都需要重新分割和重新嵌入,这不仅耗费时间与计算资源,还会占用API预算,并带来运营风险。因此,许多系统在已有更优模型存在的情况下仍会长期使用过时的模型。

rebasis的诞生就是为了打破这种锁定效应。它的目标在于让本地RAG系统能够在不删除现有向量索引的情况下更换嵌入模型。

转换查询而非索引

不同的嵌入模型无法生成可比较的向量空间。用这两种模型分别对同一句话进行编码,虽然维度可能有所不同,但问题远不止于此:每个轴的含义、空间中心位置、缩放方式以及语义邻域的排列方式都可能发生变化。将新模型生成的查询向量直接发送到旧版索引中,得到的结果往往毫无意义。有些向量数据库甚至会直接拒绝此类查询,因为其维度与数据库中的数据不匹配。

该工具的解决方案是一个小型学习适配器。它接收来自新模型的查询向量,并将其映射到现有索引所使用的空间中。为了学习这种映射关系,旧模型和新模型会对相同的文本进行编码,从而生成成对的向量。如果这两个空间之间的关系足够可学习,新的查询向量就能被转换成对旧索引有意义的内容。

其实际意义重大:新模型可以立即用于处理查询,而索引中的文档向量则保持不变。与应用程序的集成也被刻意设计得较为简单。首先进行导入:

from rebasis import Bridge

接着加载适配器并将其置于查询路径中:

bridge = Bridge.load("adapters/minilm-to-bge.rbs")query_vector = new_model.encode(["how do I deploy to production?"])
query_vector = bridge.to_index_space(query_vector)
results = collection.query(query_embeddings=query_vector, n_results=10)

Bridge是位于RAG应用高负载路径上的薄层结构。当适配器加载时,它会验证模型身份、编码配置、维度以及适配器文件的完整性。之后,每次查询仅需执行矩阵运算即可。日志记录、词典构建以及重复验证等操作被刻意排除在该路径之外,因为微小的便利不应成为每次请求都要付出的代价。此外也无需GPU,因为在当前规模下,设备间数据传输的成本往往高于矩阵乘法运算的成本。

默认适配器背后的数学原理

将旧的嵌入模型称为 f_old,新的模型称为 f_new,取由这两个模型编码的 n 份文档。这样就会得到两个数据矩阵,分别位于不同的空间中。目标是学习一个函数,将新空间中的向量映射到旧空间中,从一般形式来看,训练目标是最小化映射后的新向量与旧向量之间的弗罗贝尼乌斯范数距离。

默认方法是居中正交普罗克鲁斯特斯变换。首先会减去两个矩阵各列的均值。对于维度相同的空间,其约束条件是变换矩阵必须为类似旋转的正交矩阵。通过对居中后的矩阵乘积进行奇异值分解,最优的正交矩阵具有封闭形式,可由左右奇异向量相乘得到。随后通过对查询数据进行居中处理(使用新空间的均值)、旋转,再叠加旧空间的均值来实现变换。这就是自20世纪60年代以来就被研究的经典普罗克鲁斯特斯问题。

该解决方案不涉及任何迭代优化,因此无需设置学习率或迭代次数。相同的输入数据总是会产生相同的变换结果。

在拟合之前以及应用适配器之后,向量都会被进行长度归一化处理,因此余弦相似度实际上就转化为内积。进行居中处理很重要,因为嵌入空间具有各向异性,并且都包含一个共同的均值分量。去除该均值分量可以避免变换需要表示那些单纯旋转无法表达的平移效果。如果某对模型需要更高的自由度,那么就可以采用仿射变换、低秩变换或残差变换等替代方法。

由此可得出一个在实际应用中非常重要的结论:训练成本取决于匹配对的数量,而非语料库的规模。即便索引中包含数十万条记录,仅凭几千对具有代表性的数据也能拟合出适配器。而全矩阵变换每次查询的运算量约为两个维度大小的乘积,所需的参数内存也与之相当。通过秩-r分解,查询成本可降至大致为维度之和的r倍。以具体数值为例,一个768×768的float32矩阵大约占用2.36 MB内存,这与它所节省的重新构建索引所需的内存相比简直微不足道。

为何单一变换方法不够用

两个嵌入空间之间的关系通常接近旋转关系,但并非所有模型对都是如此。因此,rebasis并不认为存在一种算法能在所有情况下都适用。它以正交Procrustes变换为起点,这是一种用于最佳对齐两组匹配点集的封闭形式方法。然而,真实空间中可能存在均值偏移、各维度尺度差异以及非线性成分。

使用--method auto时,该工具会在相同的数据划分和相同的预处理条件下尝试多种候选算法,然后对它们进行比较:

  • 中心化及传统版本的Procrustes变换。
  • 带脊线正则化的线性映射。
  • 低秩仿射映射。
  • 考虑各维度尺度的Procrustes变换。
  • 如果可用PyTorch,则使用小型残差多层感知器。

CSLS并非被强制用于映射过程,它同样作为候选者参与竞争。这样设计的原因是出于实际考虑:在高维空间中,它能够缓解弱适配器的“中心性”问题,但可能会破坏原本已经很稳定的对齐结果。目标并非列出大量算法名称,而是通过在保留数据上的测试选出最优者。当多个候选者处于同一不确定性区间时,该工具会更倾向于选择参数更少、成本更低的那个。

训练数据与评估数据始终严格保持分离,这并非仅仅是惯例——该工具会在运行时检查两者之间是否存在重叠。即便根据适配器所学的样本为其打分,得到的数值虽然看似 impressive,却无法证明任何实质意义。

非对称嵌入模型也得到了专门的研究。例如在E5系列中,query:和passage:前缀意味着相同文本会根据其角色以不同方式编码,其他模型则使用查询或文档指令来实现相同目的。如果将适配器适配到文档编码的向量对上,再将其应用到查询编码的向量上,就会造成典型的训练与推理不匹配问题。正因如此,rebasis中的编码配置文件所包含的信息远不止模型名称:维度、归一化处理、池化操作、查询和文档前缀以及任何嵌套维度都会被记录下来。基于错误配置文件构建的适配器会在加载时被拒绝,而不会悄无声息地输出糟糕的结果。

这与早期研究的关联

实现不同版本之间的嵌入兼容性是一个长期存在的问题。向后兼容训练在训练新模型时对其加以限制,使其表示结果能与旧版本保持可比性。而向前兼容训练则采取相反方式,在训练旧模型时预先准备相关辅助信息,以便后续升级更加顺利。这两种方法都适用于那些从设计阶段就开始掌控模型整个生命周期的大型检索系统。

rebasis用于解决另一种情况:索引已经存在,旧模型和新模型是分别训练的,且任何人都不允许干预各自的训练过程。因此它属于一种事后兼容层。该技术借鉴了正交普罗克鲁斯特斯变换、低秩变换以及较新的Drift-Adapter系列方法,其独特贡献在于工程实现——将这些理念整合为一个本地工具,同时还具备测量功能、适配器选择功能、决策理论支持、对存储方式的抽象处理、安全迁移功能,以及用于实现可重复审计的工作流程。

CSLS源自跨语言嵌入对齐领域的文献。它考虑了查询项与目标项的局部邻域密度,并对成为过多查询项最近邻的“枢纽”向量施加惩罚。简而言之,它为某对数据计算的得分是两侧余弦相似度的两倍减去各自的密度项。据该项目基于真实语料库的实验显示,该方法有助于提升弱映射的质量,但有时会损害强映射的效果,因此需要对其进行评估而非盲目应用。

一种有时会提示你不要使用的工具

在项目初期,“能否在这两个空间之间建立桥梁?”这个问题的答案本身并不正确。更有意义的是以下三个问题:

  1. 这种新的嵌入模型在特定数据上真的更优吗?
  2. 适配器能保留完整重新索引后的多少质量?
  3. 使用桥接方法是否比直接使用当前模型更好?

正因如此,关键命令被设定为probe而非fit。它将采样、嵌入、真实值构建、候选项匹配、指标计算以及最终决策整合为一个统一的测量流程,且不会对现有索引进行任何写入操作。

一个核心衡量指标是ARR,即调整后的召回率保留率:它表示经过调整后的搜索质量与新模型带来的完整重新索引质量之间的比例。仅靠较高的ARR并不足以说明问题。如果新模型相比旧模型仅有微弱提升,那么适配器的实际作用就十分有限;而如果新模型取得了显著进步,但适配器无法传递这一优势,那么进行完整重新索引可能是更好的选择。

因此,这一决定取决于盈亏平衡标准:

bridge_advantage = ARR × upgrade_gain

把逻辑写出来会更清晰。设 Ra 为经过调整的系统的 Recall@k 值,Rn 为使用新模型完全重新建立索引的系统的对应值,Ro 为当前旧系统的对应值。那么 ARR 就是调整后系统相比旧系统的提升幅度除以完全重新索引后系统相比旧系统的提升幅度,而升级带来的收益则是 Rn 与 Ro 的比值。将两者相乘后,Rn 项会相互抵消,最终剩下 Ra 除以 Ro:即调整后的系统与用户不采取任何行动这一实际替代方案之间的直接比较。

每个指标都对应一个简单的问题。ARR用于衡量理想重索引中有多少被保留下来;升级收益则用于评估新模型相比旧模型提升了多少。两者的乘积则用于判断当前进行的过渡是否真的能推动事物向前发展。数值高于1表示过渡优于继续使用现有模型,低于1则表示不然。当测量结果过于接近临界值时,该工具无法给出确定结论,只会将结果标记为临界状态,并建议使用更大规模的样本进行测试。

在拥有真实的查询日志以及经人工筛选出的相关文档ID的前提下,probe能够准确衡量新模型在该数据集上的实际提升效果。如果没有这样的日志,可以使用预留的文档作为查询样本,或者通过基于关键词的合成查询来获得大致的评估结果。每个结果都会标注其证据等级,因此输出结果不仅包含分数,还说明了得出该分数的依据。

多项指标而非单一数字

Recall@k是主要的决策依据,但检索质量并非仅用一个数值来衡量。一次probe测试会生成多个相互补充的指标:

  • MRR@k显示第一个相关结果出现的位置高低。
  • nDCG@k同时考虑结果的相关性等级与排名位置。
  • Top-k重叠度反映调整后的结果集在多大程度上保留了原始结果集的特征。
  • Spearman相关性衡量共享结果的内部排序程度下降的情况。
  • Kolmogorov-Smirnov距离用于衡量校准对相似度分数分布的影响程度。
  • Tail ARR 用于衡量最稀疏簇的质量与全局平均值的差异,从而揭示出对某些区域影响更严重的偏差。
  • 这些差异非常重要。两个系统可能会以不同的顺序返回相同的文档,召回率无法察觉这一点,而 nDCG 能够识别。同样,虽然排名看起来正常,但分数分布的形态若发生足够大的变化,就可能导致基于硬截断值的过滤机制失效。如果基于召回率和基于 nDCG 的平衡结果存在差异,rebase 会报告这一差异,而不会悄悄用其中一个指标替代另一个。

    不确定性应体现在结果中

    通过对样本测得的ARR仅为点估计值,因此该工具依据Efron方法,通过2,000次自举重采样得出95%的置信区间。在T1证据等级下,ARR是两个均值的比值。若分别对分子和分母进行重采样,会破坏它们之间的统计依赖关系,因此配对比值自举法会为两者使用相同的查询索引。该置信区间为所得分布的第2.5百分位数与第97.5百分位数之间的范围。

    配对处理方式能够保留真实的相关性:对适配器而言难度较高的查询,通常对预言机来说也同样困难。当置信区间跨越决策阈值时,该结果不会被视为已确定。人们不会将小数位错当成科学上的确定性,而是将测量的精确度本身作为决策的依据。种子值、采样策略以及指标版本都会被记录在审计日志中,以便能够复现该置信区间。

    该项目称测量结果直接决定了其发展方向。根据其发布的报告,他们在11个语料库、398,010份文档以及10,346条真实用户查询上,对比了旧模型、简单的模型替换、改进后的检索方式以及完整的重新索引方案。研究采用了人工相关性评估,并使用ranx对主要结果进行独立评分,而非仅依赖该工具自身的评估指标。根据这些数据,简单模型替换仅能保留完整重新索引约12.5%的质量,而改进后的检索方式则能保留约71%的质量,其信息恢复效果是简单模型替换的约6.4倍。

    更值得注意的结果是,这种桥接方法并非每次都有效。在所测试的62组模型与语料对中,仅有12组的应用真正有价值。在62个案例中,决策规则有61次给出了正确方向,其中包括在规则确定之前未曾见过的相关语料中的33个案例中的32次。一个工具只有在其给出诚实的答案时——比如“在此重新索引”或“您无需此升级”,以及“请使用我”时,才能赢得用户的信任。

    从始至终的命令行工作流程

    rebasis不仅仅是一个库函数,它的命令行界面将模型更新转化为一个易于管理的流程。首先会检查环境以及可用的存储方式和嵌入器:

    # Inspect the environment and available store/embedder support
    rebasis doctor
    

    接下来是实际操作的三个阶段:首先进行测量并选择路径,然后安装适配器,最后在准备就绪时以后台批处理的方式迁移索引。

    # Measure first and choose the right path
    rebasis probe --store chroma:///path/to/db#notes \
      --old sentence-transformers/all-MiniLM-L6-v2 \
      --new BAAI/bge-base-en-v1.5 \
      --queries queries.jsonl --sample 10000 --report report.html# Fit the appropriate adapter
    rebasis fit --store chroma:///path/to/db#notes \
      --old sentence-transformers/all-MiniLM-L6-v2 \
      --new BAAI/bge-base-en-v1.5 \
      --method auto --pairs 4000 \
      --out adapters/minilm-to-bge.rbs# When ready, migrate the index in background batches
    rebasis migrate --adapter adapters/minilm-to-bge.rbs \
      --store chroma:///path/to/db#notes --priority access --limit 5000
    

    生成的 .rbs 适配器包含的内容不仅仅是权重。其清单记录了旧模型与新模型的身份、向量维度、方向以及编码特征指纹。张量以 safetensors 格式存储,同时还会附带得分校准与评估结果。因此,适配器实际上是一份可移植且可审计的记录,说明了生成它的模型与条件,而张量哈希值也可重新计算以验证其完整性。

    分数校准值得重视。某种转换虽然能够保持排序顺序,但仍然会改变绝对相似度分数。那些设定固定阈值的应用程序,比如 相似度 > 0.7,就可能会悄悄忽略某些结果。为了解决这个问题,该工具会使用单调等距校准器,将分数调整回原有的刻度范围,同时不会改变其顺序,同时还会向依赖固定阈值的系统发出警告。

    计算与内存表现

    理论上无需将整个语料库加载到内存中的工具仍可能意外地将其加载进来。在 rebasis 中,语料库迭代器会逐条处理记录,因此迁移过程中的内存峰值约为批次大小与向量维度的乘积。运行时间会随记录数量增加而增长,但用户的语料库永远不会实际存储在 RAM 中。当内存接近 --max-memory 的上限时,批次大小可以缩小,处于检查点状态的作业也会暂停而非被终止。

    用于真值搜索且按样本大小进行查询的相似度矩阵也并非完整构建的。查询是分块处理的,每块执行一次矩阵乘法,提取出前k个结果后便丢弃中间得分矩阵。若对所有结果进行完整排序,每行所需的计算量为S对数S。而使用argpartition方法可使每行的预期选择成本保持在与S成线性关系的水平。对于已归一化的float32向量,余弦搜索仅需一次矩阵乘法,从而能够有效控制内存占用及不同平台在数据类型方面的差异。

    在这个项目中,CPU是主要的计算依据,而非次要的备用方案。GPU虽能大幅加快嵌入生成的速度,但对于单次查询的简单适配操作而言,主机与设备之间的数据传输反而会抵消这一优势。设备等效性测试会比较得分的容忍度、检索到的邻近数据集,尤其是相同数据是否会导致完全一致的最终结果。如果微小的数值差异使得ARR超过0.95这样的阈值,那就不能视为可接受的硬件差异,而应视为产品功能上的缺陷。

    能够抵御中断的迁移

    通过桥接机制,索引无需立即更改;系统可以持续通过适配器运行任意长时间。如果需要永久迁移索引,migrate函数会逐批将记录转移到新空间,在此过程中数据安全性比单纯的速度更为重要。

    每批处理都会首先读取当前的向量数据,这些数据会在被覆盖之前被复制到备用存储中。随后再将转换后的向量写入,同时会读取部分已写入的记录以进行验证。最后,该工具不会仅依赖当前的客户端句柄,而是通过新的连接重新打开存储并再次取样验证,这样才能确保客户端缓存无法掩盖真正存入持久存储的内容。

    迁移引擎基于四个不变原则运行:

    1. 在修改记录之前,备用存储中必须已存在对应的原始 float32 向量。
    2. 每批处理中标记为已完成的任务,其写入后的样本必须在允许的误差范围内可读取。
    3. 任务完成后,仍需通过新的连接重新打开存储并进行验证。
  • 回滚操作必须恢复原始向量,同时不得改变记录数量或数据内容。
  • 这种顺序是崩溃安全机制的核心。如果在影子存储写入之后、主存储写入之前进程崩溃,只会产生一个无害的额外副本。但如果调换这两步的顺序,同样的中断就可能会永久破坏原始向量。

    迁移队列同时充当检查点,因此--resume指令会从上一次处理完成的批次继续执行。该工具能够监控内存压力和电池状态,访问日志则可将最常被查询的记录置于优先位置。如果结果不理想,rollback功能会从影子副本中恢复原始数据。后端系统中通用的接口规范(Chroma、LanceDB、sqlite-vec、Qdrant、FAISS以及内存中的实现)确保了这些操作在各个系统中的含义一致。

    适用于不同技术栈的插件

    本地 RAG 并不依赖单一的向量数据库或嵌入生成服务,因此存储与嵌入功能都通过插件机制来实现。支持的存储引擎包括 Chroma、LanceDB、sqlite-vec、Qdrant 和 FAISS,此外还有一种基于内存的后端。用于生成嵌入向量的工具则有 sentence-transformers、fastembed、Ollama、兼容 OpenAI 的 API、llama.cpp 以及预计算好的向量。

    核心版本设计为无需 PyTorch 即可运行。核心的 probe 功能、Procrustes 变换以及决策逻辑均基于 NumPy、SciPy 和 scikit-learn 实现,而那些重量较大或特定于操作系统的依赖项则仅由有需求的人自行安装。第三方软件包可以通过 rebasis.stores 或 rebasis.embedders 接口来实现集成,而无需修改项目源码。

    隐私、日志记录与可复现性

    按照设计,rebasis不会将任何本地数据发送到任何地方。它没有回传遥测功能,也没有使用量计数器,文档文本和向量永远不会被记录到日志中。由于信息可以从嵌入向量中重建,因此向量被视为与纯文本一样敏感。虽然提供了OpenTelemetry支持作为可选功能,但默认处于关闭状态,且仅向用户自己的收集器导出数据。

    每个决策都可以被记录在只读审计日志中,从而确保其可重现性。日志条目包含模型标识、配置指纹、采样方法、种子值、阈值、指标版本、rebasis版本以及环境详细信息。这些条目通过哈希链相互关联,这样后续的数据损坏或部分修改就会显现出来。rebasis audit replay功能可以重新运行之前的测量,以判断差异是由于软件回归还是语料库变化所致。

    开源打包方案旨在证明什么

    rebasis基于Apache 2.0许可证发布,其明确目标是让各项声明可被核查,同时代码也易于阅读。在代码仓库中,你可以找到关于关键决策的架构决策记录,以及理想场景、真实数据集上的测试结果、性能指标、针对后端系统的契约测试、端到端运行的命令行测试,还有贡献者指南。该测试策略不仅涵盖正常流程,还涉及不同设备间的数值一致性、内存上限、适配器属性、存储契约,以及迁移和回滚操作的持久性测试。

    该持续集成流水线针对 Linux 和 macOS 环境下的 Python 3.12 与 3.13 版本,这两种系统的存储语义存在差异。最低支持的依赖版本有独立的测试流程,同时还有专门的任务来确保 PyTorch 或 OpenTelemetry 等可选组件不会混入核心包中。类型检查使用 mypy --strict,代码质量由 Ruff 负责检测,层边界通过 import-linter 规范,文档链接则在严格模式下由 MkDocs 处理。这一切设计的理念是:开源项目的可信度并非取决于 README 中夸大的声明,而在于能否展示支撑这些声明的测试与指标。

    无需非此即彼的选择即可实现模型更新

    根本问题不在于选择何种技术,而在于更换技术的成本。随着RAG系统的发展,其索引逐渐成为基础设施投资,而选择嵌入模型则变成一个极其难以逆转的决策。重新建立基础架构的理念正是为了削弱这种关联性。

    当出现新模型时,第一步应是评估它在自身数据上的表现是否确实更优。如果确实如此,下一步则是判断是否存在可靠的桥梁能将其与现有索引连接起来。如果该桥梁足够可靠,就可以立即使用新模型。若希望长期保持最佳质量,则可通过分批迁移,并确保有验证机制和回滚手段。而如果桥梁存在缺陷,也应在昂贵的生产测试开始之前发现,而非在测试过程中才察觉。

    这就是该工具所提供的决策空间:首先进行测量,接着建立桥梁,必要时再安全地迁移。它是一款开源工具,旨在增强本地RAG基础设施的稳定性,降低嵌入模型选择的约束,提高模型升级的透明度,同时允许开发者查看、在真实语料库上测试,并参与其开发。

    相关阅读

  • 用纯 Python 实现 RAG:分块、TF-IDF、余弦相似度与提示工程 — 仅借助数学模块构建检索增强生成系统:滑动窗口分块、TF-IDF 向量、余弦相似度排序、实用提示及其局限性。