典型的检索增强生成(RAG)通常涉及将文档分块并直接将这些分块嵌入到向量存储中。对于简单情况,这很有效,但在处理大型、多样化数据集且有高性能要求的生产环境中,需要更精巧的索引方法。单纯依赖基础分块嵌入可能导致检索关联度不足、上下文碎片化或搜索效率低下。精进的索引策略旨在以提升检索质量和速度的方式存储和组织信息,这会直接影响RAG系统的表现和精确度。这些策略常涉及索引复杂性、存储成本、查询延迟和检索精确度之间的权衡。了解这些技术能让您根据数据特性和应用需求,调整RAG管道的索引层。多向量索引多向量索引不为每个文档分块分配一个单一向量,而是为同一内容使用多个向量。这使得可以捕获和查询信息的不同“视角”或摘要。常见方法:摘要 + 完整分块: 为分块的简洁摘要和完整分块文本分别创建向量并索引。匹配高层级摘要的查询可以检索到详细分块。较小的子分块 + 父分块: 将较大的“父”分块分解为更小、更集中的“子”分块。索引子分块的向量,但为了更宽泛的上下文,可能检索父分块(与父文档检索相关,下一节会谈到)。多个嵌入模型: 使用针对不同方面(例如,一个用于语义相似性,另一个用于类似关键词匹配)优化的不同嵌入模型,并存储相应的向量。查询路由逻辑随后可以决定针对哪个或哪些向量。问题: 生成分块可能回答的潜在问题,嵌入这些问题,并将它们与分块的向量关联起来。这有助于匹配表达为问题的用户查询。digraph G { rankdir=LR; node [shape=box, style=rounded, fontname="Arial", fontsize=10, margin=0.2]; edge [fontname="Arial", fontsize=9]; subgraph cluster_chunk { label = "文档分块"; bgcolor="#e9ecef"; chunk [label="原始文本\n(例如,关于某个\n特定功能的段落)"]; } subgraph cluster_vectors { label = "关联向量"; bgcolor="#a5d8ff"; vec_full [label="向量(完整文本)", shape=cylinder, style=filled, fillcolor="#74c0fc"]; vec_summary [label="向量(摘要)", shape=cylinder, style=filled, fillcolor="#74c0fc"]; vec_hypo_q [label="向量(问题)", shape=cylinder, style=filled, fillcolor="#74c0fc"]; } chunk -> vec_full [label="嵌入完整文本"]; chunk -> vec_summary [label="摘要与嵌入"]; chunk -> vec_hypo_q [label="生成问题与嵌入"]; }单个文档分块可以关联多个向量,这些向量来源于其内容、摘要或相关问题。益处: 适应不同类型的查询(宽泛与具体),可能提升关联度。 考量: 存储需求增加,索引管道复杂性增加,可能需要更精密的查询逻辑。父文档检索分块过程本身常带来一个问题。小分块能产生精确的嵌入,利于相似性匹配,但常缺乏足够上下文供LLM综合生成全面回复。相反,大分块虽提供上下文,但可能稀释具体信息,使嵌入不够精确。父文档检索(有时称作“从小到大”检索)通过索引更小、更细致的分块,并将其与更大的父文档(或更大的上下文窗口)关联起来,来应对此问题。过程:分块: 文档被分成更小的子分块(为嵌入优化)和更大的父分块(提供上下文)。通常,父分块就是原始文档,或者包含多个子分块的较大片段。索引: 仅为小子分块创建并索引嵌入。每个子分块的索引条目都包含对其父文档的引用(例如,ID、元数据)。检索:使用查询对子分块嵌入执行相似性搜索。找出匹配度最高的子分块。不直接返回小分块,而是检索其关联的父文档(或更大的上下文窗口)。将这些更大、上下文丰富的文件传递给LLM。digraph G { rankdir=TB; node [shape=box, style=rounded, fontname="Arial", fontsize=10, margin=0.2]; edge [fontname="Arial", fontsize=9]; subgraph cluster_doc { label = "原始文档"; bgcolor="#e9ecef"; doc [label="大型文档片段"]; } subgraph cluster_children { label = "子分块 (已索引)"; bgcolor="#b2f2bb"; c1 [label="分块 1 (嵌入)", shape=note, style=filled, fillcolor="#8ce99a"]; c2 [label="分块 2 (嵌入)", shape=note, style=filled, fillcolor="#8ce99a"]; c3 [label="分块 3 (嵌入)", shape=note, style=filled, fillcolor="#8ce99a"]; } query [label="用户查询", shape=ellipse, style=filled, fillcolor="#ffec99"]; vector_store [label="向量存储\n(子分块嵌入)", shape=cylinder, style=filled, fillcolor="#a5d8ff"]; llm [label="大语言模型", shape=component, style=filled, fillcolor="#bac8ff"]; doc -> c1 [style=dashed, arrowhead=none]; doc -> c2 [style=dashed, arrowhead=none]; doc -> c3 [style=dashed, arrowhead=none]; query -> vector_store [label="相似性搜索"]; vector_store -> c2 [label="找到匹配"]; c2 -> doc [label="检索父级"]; doc -> llm [label="提供上下文"]; }父文档检索是针对小分块嵌入进行搜索,但返回与最佳匹配相关联的更大父文档。益处: 结合了小分块嵌入的精确性与LLM所需的丰富上下文。 考量: 在索引期间需要仔细映射子分块和父分块。如果父分块过大,可能检索到过大的文档。LangChain提供了像ParentDocumentRetriever这样的实现来简化此过程。元数据过滤向量相似性搜索能找到嵌入空间中语义接近的文档,但关联度通常还取决于与文档相关的结构化属性或元数据(例如,创建日期、来源、作者、类别、用户权限)。运用元数据可以实现更有针对性和高效的检索:预过滤: 在执行向量搜索之前应用元数据过滤器。这能显著缩小候选范围,使向量搜索更快,并可能更具关联度,尤其是在大型数据集中。例如,在运行语义搜索之前,先过滤出过去一年内创建的文档。后过滤: 先执行向量搜索以获取语义相似的候选,然后应用元数据过滤器来细化结果。这确保了语义关联度的优先性,同时仍允许根据特定属性进行过滤。digraph G { rankdir=LR; node [shape=box, style=rounded, fontname="Arial", fontsize=10, margin=0.2]; edge [fontname="Arial", fontsize=9]; query [label="用户查询\n+ 元数据过滤器\n(例如,类别='API')", shape=ellipse, style=filled, fillcolor="#ffec99"]; all_docs [label="完整文档集\n(向量 + 元数据)", shape=cylinder, style=filled, fillcolor="#ced4da"]; filtered_docs [label="已过滤子集\n(类别='API')", shape=cylinder, style=filled, fillcolor="#a5d8ff"]; vector_search [label="向量相似性\n搜索", shape=cds]; results [label="最终结果", shape=ellipse, style=filled, fillcolor="#b2f2bb"]; subgraph cluster_pre { label = "预过滤"; bgcolor="#e9ecef"; query -> all_docs [label="应用元数据过滤器"]; all_docs -> filtered_docs; filtered_docs -> vector_search [label="搜索子集"]; vector_search -> results; } }预过滤利用元数据在向量相似性计算之前缩小搜索范围。益处: 提升搜索效率,允许基于结构化数据强制执行访问控制或关联度,通过提早移除不相关的候选来增强精确度。 考量: 需要定义清晰且持续填充的元数据字段。预过滤的效果取决于过滤器的选择性和向量存储对结合向量搜索进行高效元数据过滤的支持。许多现代向量数据库都提供优化的元数据过滤功能。将元数据过滤与稠密向量搜索以及可能的稀疏关键词搜索(如BM25)结合,构成了混合搜索的依据,这是下一节将介绍的强大技术。这些精进的索引策略为构建高度关联、上下文感知且高效的RAG系统提供了条件,这些系统能够应对生产要求。选择和组合这些策略在很大程度上取决于您的具体数据、查询模式和性能目标。