若搜索简单实现,尤其是向量搜索时,可能会出现扩展性差的情况,需要大量计算资源,增加系统延迟。向量检索(即语义搜索)最简单的方式称为k近邻搜索,每次搜索所需的计算量线性增长:

如果想让检索器在大规模场景下表现良好,需要更好的方法。
1 近似最近邻 (ANN) 算法
近似最近邻 (Approximate Nearest Neighbor,ANN) 算法,在海量高维向量数据中,寻找与查询向量"最相似"的数据点时,精确查找速度太慢。ANN是一种通过牺牲极小精度的代价,换取搜索速度大幅提升的算法。
作用: 它是向量检索的核心引擎,让系统能在毫秒级从百万甚至亿级数据中找到相似内容。常见的算法有NSW, HNSW,IVF, Faiss 等。
该NSW算法创建一种名为"近邻图"的数据结构,从一个节点跳转到另一个节点来遍历邻近图:
- 首先,计算每个向量与其他所有向量之间的距离。
- 其次,在这个近邻图内部为每个文档添加一个节点
- 最后,为每个文档创建一条边,以及它最接近的其他一些文档,形成了类似网络的结构。

邻近图如何加速搜索:
当收到一个查询时,将其向量化以生成一个查询向量,目标是找到与该查询向量最接近的文档,为了实现这一点,算法会随机选择一个被称为候选向量的入口点作为起点,开始使用算法遍历图,它查看当前候选向量的每个邻节点,并计算其中哪个离查询向量最近,离得最近的那个成为新的候选向量。重复上述操作,这个过程继续直到没有邻近节点比当前候选节点更接近时,返回候选向量。
该方法通过修改可以返回多个最近的邻近节点,但未必能找到在知识图中最优向量,可能有一个更接近提示向量的节点,只是不会被算法找到。
尽管**Navigable Small World(NSW)算法已经比KNN更高效,一种称为分层可导航小世界(Hierarchical Navigable Small World,HNSW)**的细微改进,通过加快搜索的早期阶段进一步提高了性能,HNSW 依赖于分层近邻图的多层结构。
构建多层图结构:
- 第1层中,包含一千个向量,然后按常规计算近邻图。
- 第2层中,随机保留 100个向量,剔除其余所有向量,针对这100个向量生成一个新的近邻图。
- 第3层中,随机保留 10个向量,剔除其余所有向量,再次针对剩余的10个向量生成近邻图。

搜索过程:从顶到底的贪婪遍历
- 首先,从第3层开始搜索,在这一层随机选择一个入口点,然后按正常方式搜索第3层中的最佳候选。
- 然后,从第3层中找到的最佳候选开始,下降到第2层,由于这层的向量更多,可能存在一个更接近查询向量的向量,算法在第2层按正常方式遍历,直到在第2层找到最佳候选。
- 最后,从在第2层找到最佳候选开始,下降到第1层,该层包含知识库中的所有向量,而这一次 找到的最佳候选,正是算法最终返回的。

HNSW的优点:
- 比KNN显著更快。
- 每层向量数量呈指数级减少(例如1000一>100-10),使其近似为对数增长。
- 支持扩展至数十亿个向量。
近似最近邻一一要点总结:
- 在大规模数据下,ANN比KNN快得多。
- 查找近似文档,但无法保证最佳匹配。
- 依赖于邻近图,构建计算成本高但可预先计算。
2 向量数据库技术(Vector Database)
标准关系型数据库在语义搜索方面表现不佳,在语义搜索中 它们的性能更接近效率极低的KNN算法。在生产环境的 RAG系统中,通常会从专门数据库(向量数据库)中存储和检索向量。向量数据库是从头开始设计的数据库,用于存储高维向量数据,并实现面向向量的算法。
向量数据库针对构建近邻图等任务进行了优化,驱动HNSW 搜索、计算向量距离等任务,因此具有良好的可扩展性,并且在大多数基于向量的应用中运行速度显著更快,尤其是在构建RAG系统时。
典型的向量数据库操作:
- 数据库设置
- 加载文档
- 为关键词搜索创建稀疏向量
- 为语义搜索创建密集向量
- 创建HNSW索引以支持ANN算法
- 开始搜索
完整工作流:
配置数据库------>加载和索引数据------>执行搜索
3 文本分块技术
简单来说,分块是将较长文本拆分为小文本块的实践,从知识库中拆成较小的文本块,原因有三:
- 许多嵌入模型对能够嵌入向量的文本量有限制。
- 分块可以提高检索器的搜索、相关性指标。
- 确保你仅将最相关的文本从文档中发送给LLM。
如果知识库中存在1000本书,不分块处理存在的问题:
- 将整本书的意义压缩成单一向量,无法清晰地表示特定主题、章节或页面,在所有内容上创建"平均"表示,导致搜索相关性差。
- 检索整本书,快速填充LLM上下文窗口。
因此,通常要把书分块为更小的片段,例如页面、段落或句子级,最终知识库中可能包含的是100万段落,而不是1000本书,但向量数据库可以轻松扩展规模来存储并搜索这些向量。
分块时首要考虑的是分块大小的选择,如果分块太大时,则无法用单个向量捕捉细微含义,并且它们会迅速填满大型语言模型的上下文窗口。如果分块太小时,向量将失去所有上下文,周围句子和段落,再次降低了搜索相关性。
3.1 固定大小分块(Fixed Size Chunking)
最简单的方法是使用固定大小分块策略,一开始就要确定每个分块大小一致,无法保证分块之间的分割会发生在合适的位置,分块往往会落在单词中间,或者会将段落中一段连贯内容分割成两部分。

3.2 重叠分块(Overlapping Chunking)
通常通过允许分块重叠来解决(例如:分块长度可以为 250个字符,但会与前后分块重叠 25个字符。),通常这种重叠以分块整体的百分比来表示。

重叠分块减少了词语脱离上下文被截断的情况,分块中间的词语两侧都有上下文,分块边缘的词语会出现在两个分块中,增加了它们与相关上下文一同出现的可能性,增加更多重叠通常会对搜索相关性产生积极影响,但这是以向数据库添加更多向量带有冗余信息的向量为代价的。
3.3 递归字符分割(Recursive Character Splitting)
它的思路是选择一个特定的字符来进行分割,例如可以选择换行符(逗号、句号)来进行分割,但可能出现非常大的块或者非常小的块。
不同类型的文档可以采用不同的拆分方式。
4 查询语句解析
4.1 查询重写(Query Rewriting)
最简单且目前应用最广的解决混乱提示的方案是在将查询提交给检索器之前,使用LLM重写该查询

对查询重写器的提示进行迭代,效果显著且虽然用大模型去处理提示词会多花点钱,但这样做带来的好处非常大,完全对得起这笔开销。
4.2 命名实体识别(Named Entity Recognition,NER)
Named Entity Recognition(NER,命名实体识别) ,一种用于识别查询中信息类别的技术,简单来说就是让计算机像人一样,从一堆文字中"认出"那些有特定意义的关键名词。该信息可用于指导检索器的向量搜索或者过程中的元数据过滤。

4.3 假设性文档嵌入(Hypothetical Document Embeddings ,HyDE)
Hypothetical Document Embeddings (HyDE,假设性文档嵌入) 通过生成一个假设文档优化搜索查询,就是搜索过程的理想结果。

通常检索器需要将提示词与文档相匹配,因此在某种程度上,检索器正在匹配不同的文本。
通过生成一个假设文档,检索器现在正在比较更相似的文本(一个假设的理想文档),以及知识库中实际包含的文档。
在实际应用中HyDE确实能提供性能提,但是需要以搜索过程中增加的延迟为代价,以及运行生成假设文档的大型语言模型所需的计算资源。
5 交叉编码器与ColBERT模型
**双向编码器(Bi-Encoder)**是指文档和查询是分别嵌入的,它意味着所有的文档都可以提前完成向量化,而在接收到用户的提问后,只需要对提问本身进行向量化处理,从而大幅提升了搜索速度。如果你愿意舍弃一些搜索速度,就能获得更高质量的搜索结果。

5.1 交叉编码器(Cross-Encoder)
**交叉编码器(Cross-Encoder)**能够提供比双向编码器更高质量的文档排名,交叉编码器会将文档与查询拼接,然后将组合文本输入到本质上是专用嵌入模型中,因为提问(prompt)和文档(document)都被同时作为输入,这使得模型能够理解两者文本之间深层的上下文交互关系,而这些深层关系是双编码器(bi-encoder)模型可能会漏掉的。
交叉编码器直接输出一个相关性分数通常在0到1之间,该分数可以理解为提示与文档之间正匹配的概率。

交叉编码器将提示拼接在每个文档的前面,每一对"提示-文档"然后输入到交叉编码器,输出提示与文档之间匹配的概率,重复此操作。

优点:
- 与双向编码器相比,交叉编码器几乎总是能提供更好的搜索结果。
- 非常适合提升其他搜索技术的结果。
缺点:
- 在数百万或数十亿文档上扩展性极差。
- 由于它们基于"提示-文档"对运行,无法进行预处理。
- 作为默认搜索技术使用效率太低。
5.2 ColBERT
**Colbert (Contextualized Late Interaction over BERT)**代表基于 BERT 的上下文化延迟交互,是一种专为高效且精准的信息检索而设计的模型。它巧妙地结合了双编码器(快)和交叉编码器(准)的优点。
- 首先,知识库中的每个文档都会被嵌入,不是针对整个文档生成一个语义向量,而是为文档中的每个标记生成一个语义向量。一个包含一千个标记的文档需要转换为一千个密集向量。
- 当提示词输入进来时,它也以相同方式嵌入,从而为提示词中的每个标记生成一个密集向量。
ColBert的核心评分思想是提示词中的每个标记都尝试寻找文档中与其最相似的标记。

Maxsim的作用就是在两个文本(比如"搜索词"和"文档")之间,找出最完美的"一对一"词语匹配,然后把这些最高分加起来(即得到整个文档的相关性分数)。对知识库中的每个文档重复此过程,对所有文档进行评分并检索到最相关的文档
优点:
- 双编码器的可扩展性,但跨编码器的丰富交互较多
- 速度合理,仍可用于实时或近实时场景
缺点:
- 需要大量向量存储,因为每个标记(token)而非每份文档都需要一个密集的向量
总结
- 双向编码器(Bi-encoders):质量尚可,速度极佳,存储量最小,默认语义搜索。
- 交叉编码器(Cross-encoders):质量最佳,速度极慢,存储量最小。计算成本过高,无法单独用于搜索。
- ColBERT:接近跨编码器的质量,速度尚可,显著的向量存储。ColBERT及类似方法正日益受到向量数据库的支持。
6 检索结果重排序技术
重排序的核心目的,就是在初步检索出一批文档或文本块之后,将它们送给大语言模型(LLM)之前,去提升这些检索内容的质量。一旦向量数据库返回结果,重排序开始发挥作用并通过重新打分提升检索质量。

交叉编码器重排序器(Cross-Encoder re-rankers):
- 交叉编码器比双编码器效果更好,但速度更慢
- 只有在初始双编码器过滤后才使用交叉编码器,才能使质量与时间的权衡成为可行。
- 增加轻微延迟,但通常能获得显著更好的结果。
LLM Based Scoring(基于大语言模型的评分),在业内也常被称为 LLM-as-a-Judge(让大模型当裁判)。它的核心思想是:用一个大语言模型(比如 GPT-4)去充当"阅卷老师",自动给另一个模型生成的文本或回答打分。

基于LLM的评分功能强大但成本高昂,与交叉编码器(Cross-Encoder)类似,它在大规模检索中速度过慢,更适合在初步过滤后用于重排序。