尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

RAG进阶:混合检索技术详解与工程实践

RAG进阶:混合检索技术详解与工程实践 1. 项目概述为什么混合检索是RAG进阶的必经之路如果你已经用RAG检索增强生成做过几个项目大概率会遇到一个头疼的问题明明向量检索看起来挺准的为什么回答还是会出现关键信息遗漏或者把不相关的文档片段也塞了进来我刚开始做RAG系统时也迷信过单一向量检索的“魔法”直到在一个企业知识库项目里栽了跟头。用户问一个包含特定产品型号和故障代码的组合问题系统要么只找到了型号相关的通用文档要么找到了故障代码但对应的是另一个产品最终生成的答案驴唇不对马嘴。那次教训让我明白想让RAG真正“智能”起来靠单一检索路径是远远不够的必须引入更强大的武器——混合检索。混合检索顾名思义就是把多种检索技术“混”在一起用。在Advanced RAG的语境下它特指将基于语义的向量检索和基于字面匹配的关键词检索如BM25、Elasticsearch的全文搜索结合起来有时还会加入元数据过滤、图检索等更多路径。它的核心目标很简单在“召回”阶段尽可能把可能相关的文档都找出来宁可多找也绝不漏掉。因为后续还有“重排”阶段来精挑细选但如果在召回阶段就漏了关键信息那后面再怎么排也无力回天。这就像你让助手去图书馆找资料如果只告诉他“找和人工智能伦理相关的书”语义他可能会错过一本名叫《AI伦理原则与实践》的经典著作因为书名没有直接出现“人工智能”这个词。但如果你同时告诉他“把书名或目录里含有‘伦理’和‘AI’的书也找出来”关键词那么找到这本经典著作的概率就大大增加了。混合检索干的正是这个事它让检索系统既理解你的“意图”也不放过任何“字面”上的线索。对于正在从基础RAG向Advanced RAG进阶的开发者、算法工程师或项目负责人来说掌握混合检索是构建高可用、高准确RAG系统的核心技能。它直接决定了你RAG系统知识召回的天花板。接下来我将结合实战经验拆解混合检索的设计思路、具体实现、调优技巧以及那些容易踩坑的细节。2. 混合检索的核心设计思路与方案选型为什么是向量检索和关键词检索的混合这背后是对信息检索本质的深刻理解。向量检索如通过OpenAI的text-embedding-ada-002或开源模型bge-large-zh擅长捕捉语义相似性。比如“如何养护盆栽绿萝”和“让室内爬藤植物保持活力的方法”在语义上是接近的即使它们没有共享任何关键词。然而它的弱点是对专有名词、特定术语、数字和缩写不敏感。“Python 3.11的新特性”和“Python最新版本功能”可能向量相似但“Python 3.11”这个精确版本号信息可能在向量化过程中被稀释。关键词检索如BM25则恰恰相反它基于精确的词频和文档频率进行匹配对术语、型号、代码、人名等精确匹配的场景非常强大。搜索“iPhone 15 Pro Max”它能精准命中包含这个完整字符串的文档。但它的缺点是无法理解同义词和语义泛化。“手机”和“智能手机”在它看来可能是完全不同的词。因此混合检索的设计思路是优势互补并行召回。不是二选一而是让两个“专家”同时工作各自拿出自己认为最相关的候选文档列表最后再通过一个策略将结果融合。这里就引出了几个关键的方案选型2.1 融合策略选型早期融合 vs. 晚期融合这是混合检索架构的第一个决策点。早期融合是指在检索前就将两种信号合并。最常见的方式是稀疏-稠密混合嵌入例如将BM25的词频权重与向量相似度分数在特征层面进行结合或者使用像ColBERT这样的模型它本质上是一种可学习的、基于上下文的词向量匹配兼具了语义和词法信息。早期融合的优点是系统更紧凑一次检索就能得到结果。但缺点也很明显灵活性差调整权重复杂且严重依赖融合模型的质量。晚期融合也是目前工业界更主流的选择则是让向量检索和关键词检索独立运行各自产生一个排序列表例如各返回前k个结果然后再用一个重排序器对合并后的候选集进行重新打分和排序。这种方式的优势非常突出模块化两个检索器可以独立优化、升级甚至替换。比如你可以把关键词检索从BM25换成Elasticsearch的复杂查询而不影响向量检索部分。灵活性高融合策略可以很简单如加权求和也可以很复杂如用机器学习模型学习最优融合方式。可解释性强你可以清楚地看到是向量检索贡献了哪些结果关键词检索贡献了哪些结果便于调试和分析。在绝大多数实战场景中尤其是资源相对丰富、对效果有追求的项目我强烈推荐从晚期融合架构起步。它为你后续的迭代优化提供了最大的操作空间。2.2 检索器选型用什么工具实现确定了晚期融合的架构接下来就要为两个“专家”挑选趁手的工具。对于向量检索器选择很多纯向量数据库如Pinecone、Weaviate、Qdrant、Milvus。它们专为向量搜索优化性能高功能专一通常提供云服务上手快。适合快速原型验证和云原生部署。支持向量的全文搜索引擎如Elasticsearch8.x版本后原生支持或OpenSearch。它们的优势在于“一站式”解决既能做强大的关键词检索这是它的老本行又能做向量检索。如果你的系统已经用了ES做日志或搜索引入它会减少技术栈复杂度。但向量搜索性能可能不如专用的向量数据库极致。嵌入式库如FAISSFacebook AI Similarity Search。这是一个库需要你自己管理存储和服务化。它的优点是极其高效和灵活适合对性能和成本有极致要求且有能力进行工程化封装的团队。我的经验是对于大多数应用从Elasticsearch或Pinecone/Qdrant这类云服务开始是个平衡的选择。如果团队熟悉ES生态用ES可以统一技术栈如果追求极简开发和运维云向量数据库是更优解。对于关键词检索器选择相对集中BM25及其变种这是经典算法在rank_bm25这样的Python库中很容易实现。它轻量、无需训练、效果稳定是很好的基线。Elasticsearch/Lucene这是生产级的全文搜索引擎。它不仅能实现BM25还支持复杂的布尔查询、短语匹配、模糊搜索、同义词扩展等。如果你的文档结构复杂有标题、作者、标签等字段需要利用元数据进行过滤那么ES几乎是必选。一个常见的实战模式是使用Elasticsearch同时承担关键词检索和向量检索的角色利用其dense_vector字段类型。这样数据只需存储一份两种检索都通过同一个查询接口完成简化了系统架构。2.3 重排序器选型如何决定最终顺序当向量检索和关键词检索各自返回了Top K个结果后你会得到一个可能包含重复文档的、更大的候选集比如总共2K个。重排序器的任务就是对这个候选集进行精排选出最终返回给大语言模型LLM的Top N个最相关文档。重排序也有不同层次的选择简单加权分数融合这是最直接的方法。将向量检索的相似度分数如余弦相似度和关键词检索的分数如BM25得分进行归一化例如使用Min-Max归一化或转换为百分位数然后按一个预设权重如0.7向量分 0.3关键词分加权求和。这种方法简单粗暴但权重的设定需要大量实验调优且假设两种分数的分布和尺度是可比的这并不总是成立。交叉编码器这是目前效果最好的方法之一。交叉编码器如cross-encoder/ms-marco-MiniLM-L-6-v2将查询和候选文档同时输入模型让模型直接判断它们之间的相关性得分。它比用于向量检索的双编码器查询和文档分别编码考虑到了更多的交互信息因此精度高得多。但缺点是计算开销大因为它需要对每个查询候选文档对进行一次前向传播不适合在首次海量召回时使用却非常适合对少量如50-100个精挑细选后的候选进行重排。学习排序模型在大规模生产系统中可以收集用户点击、反馈等数据训练一个Learning to Rank模型如LambdaMART来学习更复杂的融合和排序特征。这属于高阶玩法需要数据积累和机器学习工程能力。对于绝大多数项目我的建议是在混合检索的初期采用“简单加权融合”进行快速验证在效果优化阶段务必引入“交叉编码器”进行重排序。这能带来显著的精度提升。你可以先用混合检索召回100个文档然后用一个轻量级的交叉编码器对这100个文档重排选出前10个给LLM。3. 混合检索的详细实现与配置要点理论说完了我们来看具体怎么干。我将以一个使用Elasticsearch作为存储和检索后端LangChain作为编排框架的典型场景为例拆解实现步骤。这里假设你已经有了切分好的文档块chunks并存储到了ES中。3.1 环境与数据准备首先你的ES索引映射需要同时支持稀疏和稠密表示。以下是一个示例的索引映射PUT /my_rag_index { mappings: { properties: { text: { type: text }, // 用于关键词检索的字段 embedding: { type: dense_vector, // 用于向量检索的字段 dims: 1536, // 根据你的嵌入模型维度调整例如OpenAI text-embedding-3-small是1536 index: true, similarity: cosine // 相似度度量方式常用cosine或l2_norm }, metadata: { properties: { source: { type: keyword }, page: { type: integer } } } } } }在灌入数据时你需要为每个文档块做两件事将原始文本填入text字段。使用嵌入模型如text-embedding-ada-002将文本转化为向量填入embedding字段。3.2 独立检索器的实现在LangChain中你可以分别定义两个检索器。关键词检索器使用ES的全文搜索from langchain.vectorstores import ElasticsearchStore from langchain.embeddings import OpenAIEmbeddings # 假设你已经有了一个ElasticsearchStore实例 vectorstore # 我们可以利用它的client来构建一个关键词检索器 from langchain.retrievers import ElasticSearchBM25Retriever # 方法一使用LangChain的BM25Retriever (如果索引是纯文本) # bm25_retriever ElasticSearchBM25Retriever(clientelasticsearch_client, index_namemy_rag_index) # 方法二更推荐直接使用Elasticsearch的复合查询可以结合关键词和元数据过滤 from langchain.schema import Document from elasticsearch import Elasticsearch es_client Elasticsearch(http://localhost:9200) def keyword_retrieve(query: str, k: int 10): 使用Elasticsearch进行关键词检索 search_body { query: { bool: { must: [ { match: { text: { # 搜索text字段 query: query, boost: 1.0 # 可以调整权重 } } } ] # 可以在这里添加filter例如 filter: [{term: {metadata.source: 用户手册.pdf}}] } }, size: k } response es_client.search(indexmy_rag_index, bodysearch_body) docs [] for hit in response[hits][hits]: doc Document( page_contenthit[_source][text], metadatahit[_source].get(metadata, {}) ) # 为了后续融合我们可以把ES返回的分数也存下来 doc.metadata[_score_keyword] hit[_score] docs.append(doc) return docs向量检索器from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import ElasticsearchStore embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 初始化时ElasticsearchStore已经配置了embedding字段 vectorstore ElasticsearchStore( es_urlhttp://localhost:9200, index_namemy_rag_index, embeddingembeddings, strategyElasticsearchStore.ApproxRetrievalStrategy() # 使用近似最近邻搜索 ) def vector_retrieve(query: str, k: int 10): 使用向量相似度检索 # 这个方法会执行向量搜索 docs_and_scores vectorstore.similarity_search_with_score(query, kk) docs [] for doc, score in docs_and_scores: # LangChain返回的score是距离对于cosine相似度可能需要转换1-距离或直接使用 # 这里我们存储原始分数注意与关键词检索的分数可能尺度不同 doc.metadata[_score_vector] float(score) docs.append(doc) return docs3.3 融合与重排序的实现现在我们有了两个检索器可以开始实现混合检索的核心逻辑了。步骤一并行召回import asyncio from typing import List async def hybrid_retrieve_parallel(query: str, k: int 10): 并行执行关键词和向量检索 loop asyncio.get_event_loop() # 并行执行两个检索任务 keyword_task loop.run_in_executor(None, keyword_retrieve, query, k) vector_task loop.run_in_executor(None, vector_retrieve, query, k) keyword_docs, vector_docs await asyncio.gather(keyword_task, vector_task) return keyword_docs, vector_docs步骤二结果去重与合并检索结果中很可能有重复的文档即同一段文本既被关键词检索到也被向量检索到。我们需要基于文档内容或一个唯一ID进行去重。def fuse_results(keyword_docs: List[Document], vector_docs: List[Document]): 融合结果基于文档内容去重 seen_contents set() fused_docs [] # 定义一个函数来获取文档的唯一标识这里用页面内容前200字符的哈希简单示例 def get_doc_id(doc): # 生产环境中建议使用更稳定的ID如元数据中的唯一标识 import hashlib return hashlib.md5(doc.page_content[:200].encode()).hexdigest() all_docs keyword_docs vector_docs for doc in all_docs: doc_id get_doc_id(doc) if doc_id not in seen_contents: seen_contents.add(doc_id) fused_docs.append(doc) # 如果是重复文档可以选择合并分数例如取最大值或平均值这里简单去重 return fused_docs步骤三分数归一化与加权融合简单策略这是晚期融合的一种简单实现。由于关键词检索BM25和向量检索余弦距离的分数范围和分布不同直接加权求和没有意义必须先归一化。def normalize_scores(docs: List[Document], score_key: str): 将某种分数归一化到[0,1]区间 scores [doc.metadata.get(score_key, 0) for doc in docs] if not scores: return docs min_s, max_s min(scores), max(scores) # 防止除零 score_range max_s - min_s if score_range 0: for doc in docs: doc.metadata[f_normalized_{score_key}] 1.0 else: for doc in docs: raw doc.metadata.get(score_key, 0) doc.metadata[f_normalized_{score_key}] (raw - min_s) / score_range return docs def weighted_reciprocal_rank_fusion(docs: List[Document], k60, weight_keyword0.4, weight_vector0.6): 使用加权倒数排名融合Weighted RRF进行融合排序。 这是一种更鲁棒的融合方法不依赖于分数的绝对数值只依赖于排名。 from collections import defaultdict # 初始化文档得分字典 doc_scores defaultdict(float) # 假设docs中每个文档都带有其来源的排名信息。 # 我们需要重构分别得到关键词检索和向量检索的排名列表。 # 这里为了演示我们假设传入的docs是融合后的且每个文档有_rank_keyword和_rank_vector元数据。 # 在实际中你需要分别从keyword_docs和vector_docs中获取排名。 # 模拟数据实际应从两个独立列表中获取排名 # keyword_ranking {get_doc_id(doc): idx for idx, doc in enumerate(keyword_docs)} # vector_ranking {get_doc_id(doc): idx for idx, doc in enumerate(vector_docs)} # 简化演示我们给每个文档一个模拟的融合分数并排序 for doc in docs: # 模拟分数计算如果文档有来自两个检索器的分数则加权求和 norm_k doc.metadata.get(_normalized_score_keyword, 0) norm_v doc.metadata.get(_normalized_score_vector, 0) fused_score weight_keyword * norm_k weight_vector * norm_v doc.metadata[_fused_score_simple] fused_score # 按融合分数排序 sorted_docs sorted(docs, keylambda x: x.metadata.get(_fused_score_simple, 0), reverseTrue) return sorted_docs[:k] # 返回前k个步骤四引入交叉编码器重排序这是效果提升的关键一步。我们使用sentence-transformers库中的交叉编码器。from sentence_transformers import CrossEncoder # 加载一个轻量级的交叉编码器模型 cross_encoder_model CrossEncoder(cross-encoder/ms-marco-MiniLM-L-6-v2) def rerank_with_cross_encoder(query: str, candidate_docs: List[Document], top_n: int 10): 使用交叉编码器对候选文档进行重排序 if not candidate_docs: return [] # 准备模型输入[(query, doc_text), ...] model_inputs [(query, doc.page_content) for doc in candidate_docs] # 预测相关性分数 scores cross_encoder_model.predict(model_inputs) # 将分数关联到文档 for doc, score in zip(candidate_docs, scores): doc.metadata[_cross_encoder_score] float(score) # 根据交叉编码器分数排序 reranked_docs sorted(candidate_docs, keylambda x: x.metadata[_cross_encoder_score], reverseTrue) return reranked_docs[:top_n]最终组装async def advanced_hybrid_retrieval(query: str, final_k: int 10): 完整的混合检索流程 # 1. 并行召回 keyword_docs, vector_docs await hybrid_retrieve_parallel(query, k30) # 每路召回多一些 # 2. 归一化分数为简单融合策略准备 keyword_docs normalize_scores(keyword_docs, _score_keyword) vector_docs normalize_scores(vector_docs, _score_vector) # 3. 去重合并 all_candidates fuse_results(keyword_docs, vector_docs) # 4. 可选简单加权融合进行初筛减少后续重排计算量 # 例如从100个候选里先用加权分选出50个 # top_candidates weighted_reciprocal_rank_fusion(all_candidates, k50) # 这里为了演示我们直接使用所有候选进行重排 top_candidates all_candidates[:50] # 限制数量以控制重排开销 # 5. 交叉编码器重排序 final_docs rerank_with_cross_encoder(query, top_candidates, top_nfinal_k) return final_docs4. 参数调优、监控与常见问题排查混合检索系统搭建起来只是第一步让它发挥出最佳效果需要精细的调优和持续的监控。4.1 关键参数调优指南召回数量K这是最重要的参数之一。向量检索和关键词检索各自召回的K值多大合适我的经验是起始点可以设为最终需要文档数如10的5-10倍。即每路召回50-100个。太少了可能漏掉关键文档太多了会增加重排序的计算开销和噪声。需要通过验证集上的“召回率”来调整逐步增加K观察召回率系统找到的标准答案文档比例是否显著提升直到增长平缓。融合权重在简单加权融合或RRF中向量检索和关键词检索的权重如何设置这没有银弹取决于你的数据术语密集型数据如技术手册、法律条文、产品规格书关键词检索权重要提高如0.6-0.8。语义描述性数据如客服对话、分析报告、创意文案向量检索权重要提高如0.7-0.9。通用型数据可以从0.5:0.5开始然后基于一个小的测试集包含不同类型的问题进行网格搜索选择综合指标如MRR平均倒数排名最高的权重。重排序模型选择交叉编码器模型越大效果通常越好但耗时越长。需要在精度和延迟之间权衡。对于高并发在线服务MiniLM-L-6这类小型模型是很好的起点。如果对精度要求极高且延迟预算充足可以考虑更大的模型如roberta-large。务必在本地缓存重排序模型避免每次请求都从网络加载。文本分块策略这虽然不属于混合检索本身但直接影响检索效果。对于混合检索分块策略需要兼顾两种检索方式向量检索偏好语义完整的块如按段落或小节。关键词检索需要块内有足够的关键词密度过大的块可能稀释关键词权重。 一个折中的策略是使用重叠分块如块大小512词重叠100词。这样既能保证块的语义完整性又能让关键信息有更高概率出现在块的中心位置有利于两种检索。4.2 效果监控与评估指标不能只靠感觉必须建立量化评估体系。离线评估召回率K在K个召回结果中至少包含一个相关文档的概率。这是评估混合检索“找全”能力的关键。平均精度衡量返回结果列表的总体质量。NDCGK考虑排序位置的评估指标对重排序效果特别敏感。 构建一个包含大量“问题-相关文档”对的测试集定期如每周运行评估流水线跟踪指标变化。在线监控检索延迟分别监控关键词检索、向量检索、重排序各阶段的耗时P95/P99。延迟突增可能意味着索引膨胀、模型加载问题或资源瓶颈。缓存命中率如果对常见查询或嵌入做了缓存监控命中率。业务指标最终目标是提升下游LLM回答的质量。可以监控答案相关性评分通过人工或模型评估、用户反馈点赞/点踩率等。如果混合检索上线后这些指标没有提升就需要回查检索环节。4.3 常见问题与排查实录在我实施混合检索的过程中踩过不少坑这里分享几个典型的问题一混合检索后效果反而比单一向量检索差。排查首先检查是不是分数归一化出了问题。如果向量检索用的是余弦相似度值域[-1,1]或[0,1]而关键词检索用的是BM25分数无上限的正值直接加权求和会导致一方完全主导。必须进行归一化。其次检查权重设置是否极端。如果给了关键词检索0.9的权重而你的数据恰恰是语义主导的效果自然会差。最后检查候选文档去重逻辑。如果去重算法有bug导致大量重复文档占据前排也会拉低效果。问题二重排序阶段速度太慢成为性能瓶颈。排查交叉编码器推理是计算密集型的。首先限制重排序的候选文档数量。不要对几百个文档做重排先用简单的融合策略筛选到50-100个以内。其次考虑模型量化。使用onnxruntime或TensorRT对交叉编码器模型进行量化加速。第三批处理。如果服务QPS高将多个查询的重排序请求批量处理能极大提升GPU利用率。第四硬件加速。确保推理服务运行在GPU上。问题三对于包含数字和代码的问题检索效果依然不佳。排查即使混合检索对纯数字序列如版本号“v2.1.5.7”或代码片段的处理也可能不理想。这是因为标准的分词器可能会把数字和点号分开。解决方案在构建索引时为这些特殊字段如版本号字段、代码字段建立独立的子字段并使用不同的分析器如keyword分析器保证不被分词。在查询时对用户问题中的数字、代码模式进行正则表达式提取然后将其作为“必须匹配”的过滤条件filter或高权重的term查询加入到关键词检索的查询语句中。这相当于为混合检索增加了第三条“精确匹配”的路径。问题四系统响应延迟高不符合线上要求。优化方向并行化确保关键词检索和向量检索是真正并发的而不是串行。异步化整个检索流程从接收请求到返回结果应使用异步框架如asyncio编写避免阻塞。缓存查询缓存对完全相同的用户查询直接缓存最终的检索结果。嵌入缓存对常见的查询文本和文档块的嵌入向量进行缓存。因为嵌入模型推理是检索流程中主要的耗时环节之一。索引优化对于向量索引使用HNSW等近似算法并调整其参数如ef_construction和ef_search在精度和速度之间取得平衡。对于ES确保为向量字段设置了合适的索引类型。5. 超越基础混合检索的进阶模式与未来思考当你熟练掌握了上述“向量关键词重排”的标准混合检索流程后可以探索一些更高级的模式以应对更复杂的场景。5.1 多向量检索混合我们之前讨论的混合是稀疏检索和稠密检索的混合。但在稠密检索内部也可以“混合”。即使用多个不同的嵌入模型对同一文档进行编码存储多个向量。查询时用同一个问题在这些不同的向量空间中分别搜索然后融合结果。为什么这么做不同的嵌入模型有不同的“偏好”。有的模型在通用语义上表现好有的在特定领域如生物医学、法律微调过有的在多语言上能力强。多向量混合可以捕捉更全面的语义信息。如何实现在索引中为同一文档块存储多个向量字段如embedding_openai、embedding_bge、embedding_jina。查询时并行搜索这些字段然后使用RRF或学习排序模型进行融合。这增加了存储和计算成本但可能带来显著的精度提升尤其是在领域特定的任务中。5.2 引入图检索与元数据路由对于高度结构化、关联性强的知识如知识图谱、产品目录、API文档单纯的文本检索可能不够。可以引入图检索。场景用户问“与TensorFlow兼容的GPU加速库有哪些”。传统的文本检索可能找到介绍TensorFlow的文档和介绍GPU加速的文档。但图检索可以沿着“TensorFlow” - “支持” - “库” - “具有属性GPU加速”这样的路径精准找到答案。实现使用图数据库如Neo4j存储实体和关系。在混合检索流程中先对用户查询进行实体识别提取出关键实体如“TensorFlow”、“GPU”然后用这些实体在图数据库中进行遍历查询找到相关联的实体或子图再将这些子图转化为文本描述加入到候选文档集中进行后续的重排序。此外元数据路由也是一种强大的模式。在检索前先根据用户问题或上下文决定使用哪条或哪几条检索路径以及它们的权重。例如如果问题中充满了产品型号和代码可以调高关键词检索的权重甚至只使用关键词检索加元数据过滤。这需要一套简单的分类器或规则引擎来实现路由决策。5.3 Agentic RAG 中的混合检索在智能体Agent驱动的RAG中混合检索的角色更加动态。一个复杂的Agent可能会将一个复杂问题拆解成多个子问题“规划”然后针对每个子问题发起检索。此时混合检索的策略可以更加灵活子问题自适应对于“总结”类的子问题偏向向量检索对于“查找确切数值”类的子问题偏向关键词检索。迭代检索如果第一次检索的结果不理想例如LLM判断信息不足Agent可以基于已有信息改写查询再次发起检索。第二次检索时可以调整混合策略比如如果第一次向量检索结果差第二次就提高关键词检索的权重。实现这种动态混合需要让检索模块暴露更多的可调参数如权重、检索器选择并由上层的Agent或一个专门的“检索策略模块”来根据当前上下文进行控制。混合检索不是RAG优化的终点而是一个强大的基石。它解决了召回阶段的核心矛盾。在实际项目中我最大的体会是没有最好的固定策略只有最适合当前数据和业务场景的策略。从简单的加权融合开始建立评估基线然后逐步引入重排序、多路召回、动态路由等更复杂的技术同时紧密监控性能和效果指标这是一个持续迭代和优化的过程。当你把混合检索调校顺畅后你会发现RAG系统的回答质量会有一个质的飞跃因为它真正做到了“既见树木也见森林”。
返回列表