本文将从工程视角系统梳理 RAG 技术体系,帮助你建立清晰的项目落地认知。
RAG 检索的本质
许多文章将 RAG 检索简化为“速度 vs 精度”的二选一问题,但这种描述过于片面。在真实的人工智能生产系统中,检索阶段至少需要平衡以下 4 项核心指标:
- 平衡召回率 (Recall)
- 准确率 (Precision)
- 查询延迟 (Latency)
- 资源成本 (Cost)
换句话说,RAG 检索是一个典型的多目标优化问题,而不仅仅是在速度和精度之间做简单的权衡。只有同时满足上述“4个核心”要求,检索系统才能在生产环境中稳健运行。
3 大核心模型:能力边界与真实定位
Bi-Encoder:高效召回的基础设施
核心机制: Bi-Encoder 使用同一个编码器分别对查询(Query)和文档(Document)进行编码,生成独立的向量,再计算它们的余弦相似度或点积作为相关性分数。例如,在 Python 中可以使用 SentenceTransformer 模块批量生成文档向量,并保存在向量数据库/中间件/技术栈(如 FAISS、Milvus)中。查询时,只需要对用户的问题编码一次,再做近似最近邻(ANN)检索。这种方法支持预计算文档 Embedding,极大提升了系统的吞吐量和响应速度。
优势: Bi-Encoder 支持百万级甚至更大规模的文档检索,响应速度极快(通常为毫秒级),且向量可以离线预计算并复用。因此,它几乎是所有大规模语义检索系统的基础设施,能够实现高吞吐的语义召回,快速将候选集缩小到 Top-K 的规模。
局限: 由于查询和文档之间没有进行逐词(token)级别的交互,相关性判断只能粗略地依靠主题或整体语义相似度。当遇到逻辑推理、否定表达、数字与专有名词精确匹配等复杂约束时,Bi-Encoder 往往难以区分真伪相关文档。这导致其召回可能不够全面,同时对查询中的关键词或实体(如错误码、ID等)不够敏感。因此,Bi-Encoder 在 RAG 系统中的本质角色是“召回引擎”,负责快速回收潜在相关的候选文档,但不能保证最终的答案排序质量。
Cross-Encoder:最强排序器(但不是检索器)
核心机制: Cross-Encoder 将查询和文档串联后作为一个整体输入,经过一个 Transformer 编码器进行处理。模型从 [CLS] Query [SEP] Document [SEP] 的输出中直接预测相关性分数。由于模型在前向过程中让查询与文档的所有 token 完全交互,它能够学习到非常细致的上下文匹配关系。
优势: Cross-Encoder 可以捕捉查询和文档之间的深层语义交互,对逻辑、否定、条件等复杂约束的匹配能力极强。例如,查询中出现的否定词“not”可以与文档中同义或相反的表达直接对应,从而大大提高排序结果的准确率。在捕捉答案意图和评估答案相关性方面,它也远超 Bi-Encoder。
局限: Cross-Encoder 无法单独预计算文档表示,因此每次检索都需要对每个候选文档进行一次完整的前向推理计算。这种设计的复杂度是 O(N),当候选集规模较大时,计算量和延迟会急剧增加。所以,Cross-Encoder 本身并不适合作为大规模检索器,它只能用于对小规模候选集进行精细排序,其本质定位是“候选重排序模型”。
Late Interaction(ColBERT):精细召回增强器
核心机制: Late Interaction(以 ColBERT 为代表)在编码查询和文档后,会保留每个 token 的向量,而不是聚合成单个句向量。然后使用 MaxSim 等机制进行延迟匹配。具体来说,为查询的每个 token 向量与文档所有 token 向量计算相似度,并为每个查询词取最大值,最后将这些最大值累加作为整体相关性分数。这种设计既保留了 Bi-Encoder 的预编码优势(文档向量可离线计算),又部分恢复了 token 级别的细粒度匹配能力。
优势: 相比 Bi-Encoder,Late Interaction 模型在细粒度匹配上更强,可以捕捉到查询中特定词汇与文档中特定位置的精确语义对应,因此检索精度显著提高。相比 Cross-Encoder,它仍可以离线构建文档索引,查询时只需编码一次查询向量,效率更高。对于长文档的多词匹配任务,Late Interaction 格外有效。
真实问题(工程视角): 由于需要为文档中的每个 token 都保存向量,索引体积会膨胀很多,内存和存储成本较高;而且检索时的复杂度也高于纯向量检索(通常延迟是 Bi-Encoder 的数倍)。构建索引时也需要专门的框架支持(当前市面上的大多数向量数据库并不直接支持 ColBERT 这类索引)。因此,Late Interaction 更像是一种“精细召回增强”方案,用于在特定场景下提高召回质量,而非通用的最佳选择。
现代 RAG 主流技术
现代 RAG 系统普遍采用混合检索策略:同时结合稀疏检索(如 BM25)和稠密检索(语义向量)来进行候选召回。这是因为 Bi-Encoder 等稠密模型虽然擅长捕捉语义,但对精确词匹配(如错误码、专有名词、数字)不够敏感。BM25 可以很好地补充这一弱点,它擅长检索包含相同关键词的文档。工业界常见的做法是分别用 BM25 和 Dense 模型检索各自的 Top-K 结果,然后合并去重,再送入后续处理环节。这种方法既提高了整体召回率,也确保不遗漏任何可能相关的候选。
混合检索的核心意义在于,Bi-Encoder 的语义召回和 BM25 的关键词检索能够相辅相成,使系统既能捕捉到同义语义匹配,又不漏掉包含核心关键词的文档。
- 典型流程:先用 BM25 检索得到关键字匹配结果 Top-K,再用稠密检索得到语义匹配结果 Top-K,两者合并去重后进入下一阶段。
多阶段检索(Multi-stage): 现代 RAG 几乎都采用多级管道架构。一个经典的三阶段流程如下:
- 粗召回(Recall): 使用 BM25、Dense 或混合检索快速取出数千个候选文档(例如 Top-1000)。这一阶段追求高召回率,确保重要文档不被漏掉。
- 精筛过滤(Filter): 使用开销较低的模型(例如仅用稠密相似度)对第一阶段的候选结果进行快速筛选,只保留质量较高的前几十到一百个候选。
- 最终重排序(Rerank): 对上述精简后的候选集使用 Cross-Encoder(或其他更强的重排序器)进行逐对打分,只保留最优的 Top-5~10 个结果。
这种架构的核心思想是“先用便宜的模型粗排,再用昂贵的模型精排”。例如,可以先对上千篇文档进行简单的向量检索,再仅对最相关的几十篇使用 Cross-Encoder 逐一打分。最终,将最优的几个文档块输入生成模型。这样的多阶段设计,能同时兼顾检索的召回率和排序精度。
Query 优化
检索效果往往受查询(Query)质量制约,因此查询优化是 RAG 工程中的重要一环。常见的优化方法包括:
- 查询改写(Query Rewrite): 将用户原始、模糊的问题改写为更明确、结构化的形式,帮助检索系统更准确地理解意图。例如,通过对话上下文压缩或使用语言模型进行改写。改写后的查询能显著提高检索命中率。
- 多查询扩展(Multi-Query / Query Expansion): 自动生成原始查询的多个变体,从不同角度表达原意,从而扩大召回面。Spring AI 等实践表明,多查询扩展可以有效提升召回率。系统将原始问题扩展为 3~5 个相关查询,再整合各查询的检索结果。
- 上下文增强查询(Context-aware Query): 在对话场景中,根据历史上下文补全代词或指代模糊的对象,避免误检和漏检。
- 其他方法如查询翻译、同义词扩展等。
实践表明,查询优化带来的性能提升有时可能超过换用更复杂的模型。在资源有限的情况下,一个恰当的查询改写或多角度检索,往往是性价比更高的优化手段。
Chunk 策略(决定上限)
文档分块(Chunking)策略直接决定了检索系统的能力上限。在建立索引时,需要将长文档切成合适长度的“知识块”,关键参数包括块大小(如 256、512 tokens)、块之间的重叠部分,以及是按语义边界切分(按段落/句子)还是简单按固定大小切分。
- 块大小: 较小的块(如几十个词)能提高召回率,因为更多细粒度内容进入索引,但可能割裂语义上下文;较大的块(几百个词)保留了更多上下文信息,但检索时容易变得“笼统”,且如果文档长度超过模型输入限制,仍需拆分。
- 重叠与切分方式: 可以让相邻块之间存在一定的重叠(sliding window),以减少关键信息被切分到两个块边缘而丢失的风险。对于有结构的文档(如带标题的文章),应优先按段落或章节划分;对无结构文本,则采用固定长度或句子级切分。
- 经验建议: 行业实践表明,一般使用较小的块长度(如100~512 tokens)能够提升检索性能。过大的块会增加信息丢失的风险,过小的块又可能丧失必要上下文。最优策略往往需要在目标语料和具体应用场景上进行 A/B 测试和调优。
总之,Chunk 策略同时影响召回率和上下文利用率。块越小,召回面越广,但丢失的上下文线索可能越多。合适的切分和重叠设置,是平衡速度与效果的关键。
核心模型对比
| 维度 |
Bi-Encoder |
Cross-Encoder |
Late-Interaction (ColBERT) |
| 本质角色 |
候选召回引擎 |
候选重排序器 |
精细召回增强 |
| 交互方式 |
无交互(Query/Doc 独立编码) |
完全交互(Query+Doc 联合编码) |
局部交互(MaxSim 局部匹配) |
| 检索速度 |
极快(数毫秒级) |
慢(每文档都需推理) |
较快(比 Cross 快) |
| 排序精度 |
较低 |
最高 |
较高 |
| 召回能力 |
高(大规模覆盖) |
不用于召回 |
很高(细粒度增强召回) |
| 资源成本 |
低(只需向量存储/库) |
高(计算开销大) |
中等偏高(存储/计算均高) |
从上表可以看出:Bi-Encoder 作为“召回引擎”以低成本和极高的吞吐著称,但精度一般;Cross-Encoder 作为“重排序器”能保证最高的准确率,却因每个候选都需编码计算而速度慢、成本高;Late-Interaction 模型介于两者之间,既有接近交叉编码器的精度,也有比纯 Bi-Encoder 更高的效率,但代价是更高的存储和计算资源。
RAG 选型
不同应用场景下的 RAG 方案选型也不尽相同:
- 通用企业级 RAG: 推荐使用混合召回 + Cross-Encoder 重排序的方案。即 BM25 + Dense 同时做召回(确保高召回率),再用 Cross-Encoder 对候选集做精排(确保排序精度)。这种方案兼顾了召回率和准确度,是工业界的主流做法。
- 高精度场景(法律/医疗等): 由于对准确性要求极高,除了使用 Hybrid 混合检索外,也可加入 Late-Interaction 模型来进一步提升召回上限;最后再由 Cross-Encoder 进行最终重排。这样可以获得更丰富的候选集,不漏掉任何关键文档,同时保证检索结果的严谨性。
- 轻量系统 / Demo: 如果对延迟敏感或资源受限,可以仅用稠密检索(Bi-Encoder)快速上线,先实现基本功能,后续再逐步引入重排序器。对于小规模问答或 FAQ 场景,简易的 Bi-Encoder 检索配合 LLM 生成往往已能满足需求。
最终结论
综上所述:
- Bi-Encoder 专注于规模化召回,通过高效向量检索快速收集相关文档。
- Cross-Encoder 解决了候选排序问题,通过联合编码查询与文档实现最精确的相关性打分。
- Late Interaction (ColBERT) 则增强了召回的细粒度匹配能力,在 Bi 和 Cross 之间提供了更高精度的召回选项。
真正的工业级 RAG 解决方案往往是多种技术的组合。典型的做法是先用 Bi-Encoder(及 BM25 等)进行粗召回,再用 Cross-Encoder 精排;必要时还可以加入 ColBERT 来提升召回上限。正如前文总结,Embedding 模型检索速度快但匹配浅显,Cross-Encoder 匹配深入却开销巨大,因此两阶段混合检索架构已成为行业常态。通过这种设计,RAG 系统才能在大规模知识库上同时实现高召回、高精度,并兼顾成本与延迟需求。
如果你在企业级RAG实施中遇到更多架构或选型难题,欢迎在云栈社区的技术论坛与同行们交流探讨。