资讯动态

《别只用向量搜索:BM25 + FAISS 打造工业级 RAG 检索系统》

发布时间:2026/8/14 7:54:23 来源:尧图企业网站定制
LlamaAI本地部署实战专栏第7篇上一篇我们已经实现了一个基础 RAG 系统但很快会遇到一个非常现实的问题知识库里明明存在答案为什么AI还是找不到本篇我们从底层检索原理出发把简单的“向量搜索”升级成BM25 FAISS 混合检索最后再介绍 Reranker让本地RAG真正进入工程化阶段。一、上一篇的RAG为什么还不够上一篇我们实现了PDF ↓ 文本切片 ↓ Embedding ↓ FAISS ↓ 相似度搜索 ↓ Llama看起来已经完整。但实际使用时可能出现用户问CUDA 12.6 如何安装知识库里面明明存在CUDA Toolkit 12.6 Installation Guide但是FAISS返回CUDA环境变量配置方法 GPU驱动安装方法 CUDA Runtime介绍而不是最需要的CUDA Toolkit 12.6安装步骤为什么因为向量相似 ≠ 关键词完全匹配。这就是本篇要解决的问题。二、RAG检索到底在做什么首先重新理解RAG。用户输入CUDA 12.6如何安装系统实际上需要完成问题 ↓ 检索 ↓ 找到相关文档 ↓ 交给LLM ↓ 生成答案因此RAG最终效果很大程度取决于检索质量。如果检索阶段拿错了资料错误资料 ↓ LLM ↓ 错误答案即使你的Llama模型非常强也很难凭空解决。三、为什么单纯FAISS会出现问题FAISS本质上是向量相似度搜索工具。假设问题 CUDA 12.6如何安装经过Embedding[0.21, 0.83, 0.17, ...]知识库文档A → [0.20, 0.81, 0.19, ...] 文档B → [0.72, 0.14, 0.82, ...] 文档C → [0.23, 0.80, 0.18, ...]FAISS计算距离Query ↓ Vector Search ↓ Top-K它关注的是语义空间中的距离。而不是“CUDA 12.6”这个关键词有没有出现。四、什么是BM25BM25是一种经典的信息检索算法。它不是Embedding。也不是神经网络。它主要考虑关键词是否出现关键词出现频率文档长度关键词稀有程度例如查询CUDA 12.6 安装文档CUDA 12.6 Installation GuideBM25会发现CUDA √ 12.6 √ 安装 语义相关因此给它较高的相关性分数。五、BM25和FAISS有什么区别可以简单理解FAISS“这两个文本意思像不像”BM25“这几个关键词是不是出现在这篇文档里”例如用户RTX 4090 显存多少知识库A RTX 4090拥有24GB显存。 B GPU显存管理技术。 C CUDA编程模型介绍。BM25非常擅长找到RTX 4090 24GB 显存而向量搜索则可能返回GPU显存管理 GPU架构 CUDA显存两者各有优势。六、为什么要做混合检索现在我们把两种方法结合用户问题 | --------------------- | | BM25 FAISS | | 关键词检索 语义检索 | | ----------- --------- | 结果融合 | Top-K | Reranker | Llama这就是Hybrid Search混合检索七、BM25安装Python环境pip install rank-bm25 jieba中文文本建议进行分词。例如import jieba text CUDA是一种GPU计算平台 tokens list(jieba.cut(text)) print(tokens)可能得到[CUDA, 是, 一种, GPU, 计算, 平台]八、建立BM25索引假设我们已经有chunks [ CUDA是一种GPU计算平台, RTX 4090拥有24GB显存, Transformer是一种神经网络架构, FAISS可以进行向量相似度搜索 ]首先分词import jieba tokenized_chunks [ list(jieba.cut(chunk)) for chunk in chunks ]然后from rank_bm25 import BM25Okapi bm25 BM25Okapi( tokenized_chunks )BM25索引建立完成。九、BM25检索用户query RTX 4090显存多少分词query_tokens list( jieba.cut(query) )搜索scores bm25.get_scores( query_tokens )得到文档A0.3 文档B8.7 文档C0.1 文档D0.2显然文档B最相关。十、FAISS检索之前我们已经建立了FAISSdistance, ids index.search( question_vector, 3 )例如FAISS结果 chunk_8 chunk_2 chunk_15现在BM25 chunk_2 chunk_7 chunk_21 FAISS chunk_8 chunk_2 chunk_15可以发现chunk_2同时被两种算法找到。这通常意味着它很可能是高相关结果。十一、最简单的结果融合一种简单方法BM25分数 FAISS分数 最终分数例如Document A BM25 8.2 FAISS 0.85可以Final Score α × BM25 β × FAISS例如α 0.5 β 0.5但是这里存在一个问题BM25和向量距离的数值范围并不相同。因此直接相加并不理想。十二、RRF更实用的融合方法实际工程中可以使用Reciprocal Rank Fusion简称RRF核心思想不直接比较两个算法的原始分数。而比较排名。公式RRF(d) Σ 1 / (k rank(d))例如BM25 A → 第1 B → 第2 C → 第3 FAISS B → 第1 A → 第2 D → 第3那么A BM25 Rank 1 FAISS Rank 2 B BM25 Rank 2 FAISS Rank 1最终A和B都会获得较高分数。十三、实现RRFPythondef rrf_score(results, k60): scores {} for result in results: for rank, doc_id in enumerate( result, start1 ): scores[doc_id] ( scores.get(doc_id, 0) 1 / (k rank) ) return scores使用bm25_results [ 2, 7, 21 ] faiss_results [ 8, 2, 15 ] scores rrf_score( [ bm25_results, faiss_results ] )排序sorted( scores.items(), keylambda x: x[1], reverseTrue )结果可能2 8 7 15 21这样chunk_2被两个检索器同时发现自然排在前面。十四、为什么还需要Reranker到这里BM25 FAISS ↓ Top-K已经比单独FAISS强很多。但还有一个问题Top-K不一定全部真正相关。例如用户CUDA如何配置环境变量检索返回Top 10里面可能真正相关3个 一般相关4个 无关3个如果把10个全部交给LLM10个Chunk ↓ Prompt ↓ Llama会导致Context变长推理速度下降噪声增加模型更容易受到无关内容干扰所以需要Reranker重新排序。十五、Reranker是什么Reranker对Query和候选文档进行更精细的相关性判断。流程用户问题 | BM25 FAISS | Top 20 | Reranker | Top 5 | Llama也就是说第一阶段快速搜索。第二阶段精确判断。十六、为什么不能直接让Llama排序当然可以。例如Query CUDA如何安装 Document A Document B Document C ...然后让Llama请按照相关性排序。但是这样成本较高。因为每次检索 ↓ 调用LLM ↓ 大量Token计算Reranker则专门解决Query-Document相关性判断。因此速度和成本更加合适。十七、完整工业级RAG架构现在我们的架构升级成用户问题 | ---------------------- | | BM25 FAISS | | Top-K Top-K | | ---------RRF---------- | Top-20 | Reranker | Top-5 | Prompt | llama-server | Llama | 答案这已经是非常典型的Hybrid RAG Pipeline十八、实际项目中的代码结构建议把项目组织成rag-project/ │ ├── data/ │ └── documents/ │ ├── models/ │ └── embedding/ │ ├── vectorstore/ │ └── faiss.index │ ├── bm25/ │ └── index.pkl │ ├── ingest.py ├── retriever.py ├── reranker.py ├── llm.py └── main.py职责ingest.py ↓ 处理文档 retriever.py ↓ BM25 FAISS reranker.py ↓ 重排序 llm.py ↓ 调用llama-server main.py ↓ 整体流程这比把所有代码写在一个Python文件里更适合后续扩展。十九、完整查询流程假设用户RTX 4060运行7B模型需要多少显存第一步Query第二步BM25找到包含 RTX 4060 7B 显存 的文档第三步FAISS找到语义相似 GPU显存需求 模型量化 Q4模型第四步RRF融合两个结果第五步RerankerTop 20 ↓ Top 5第六步构建Prompt请根据以下资料回答问题。 资料1 ...... 资料2 ...... 资料3 ...... 问题 RTX 4060运行7B模型需要多少显存第七步Prompt ↓ llama-server ↓ 本地Llama ↓ 答案二十、为什么混合RAG通常比单一检索更加可靠可以从三个维度理解。FAISS擅长语义搜索例如“显卡内存” ≈ “GPU显存”BM25擅长精确关键词例如RTX 4060 CUDA 12.6 Q4_K_M这些技术名词非常重要。Reranker擅长精细相关性判断因此BM25 FAISS Reranker形成三级检索体系第一层 快速召回 第二层 混合融合 第三层 精确排序二十一、RAG性能优化的核心参数真正做RAG时不要只盯着模型。下面这些参数同样重要Chunk Size例如500 1000 1500 2000过小上下文不完整过大噪声增加Chunk Overlap例如50 100 200用于减少切片边界造成的信息丢失。Top-K例如Top 3 Top 5 Top 10 Top 20一般可以召回Top 20 ↓ Reranker ↓ Top 5二十二、一个非常重要的工程经验很多人做RAGEmbedding模型换一个 ↓ 向量数据库换一个 ↓ LLM换一个但效果还是不好。实际上RAG效果的瓶颈经常不是LLM而是检索。一个强模型错误资料 ↓ 强LLM ↓ 错误答案一个普通模型正确资料 ↓ 普通LLM ↓ 高质量答案因此先把检索做好再谈模型。二十三、最终RAG架构到这里我们的本地AI已经变成用户 | Query | ------------------- | | BM25 FAISS | | Top-K Top-K | | ------- RRF ------- | Top 20 | Reranker | Top 5 | Prompt | llama-server | GGUF模型 | CUDA GPU | 答案这已经不再是一个简单的PDF LLM而是一个完整的本地Hybrid RAG系统。二十四、本篇总结这一篇我们解决了基础RAG最重要的问题如何提高检索准确率核心技术路线FAISS ↓ 语义搜索 BM25 ↓ 关键词搜索 RRF ↓ 结果融合 Reranker ↓ 精确排序 Llama ↓ 生成答案最终形成BM25 FAISS ↓ Hybrid Search ↓ RRF ↓ Reranker ↓ Llama.cpp下一篇预告《本地Llama Agent开发让大模型学会调用工具》到这里我们的AI已经可以理解问题 搜索知识 生成答案。但是它仍然只能“说”。下一步我们让它真正做事情。下一篇将实现什么是AI AgentFunction Calling原理Tool Calling文件操作工具Python工具搜索工具Agent循环本地Llama RAG Tools构建第一个本地AI Agent最终实现用户 ↓ Llama ↓ 判断需要什么工具 ↓ 调用工具 ↓ 获得结果 ↓ 继续思考 ↓ 生成最终答案这将是整个专栏从“本地大模型”迈向“本地智能体”的关键一篇。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价