当前位置: 首页 > news >正文

09-关键词与向量结合-Hybrid-Search混合检索实战

关键词检索与向量检索结合:Hybrid Search(混合检索)实战

系列:从零构建企业 RAG 知识库(第 9 篇)

1. 为什么两种检索互补

向量检索擅长同义表达和语义相关;关键词检索擅长精确编号、产品名、错误码和罕见术语。

“无法登录系统” ↔ “认证失败” 向量检索可能更强 “ERR-1042” ↔ 文档中的 ERR-1042 关键词检索通常更可靠

Hybrid Search 同时获取两路候选,再融合排名。它不是把两个分数直接相加,因为 BM25 与余弦分数的量纲不同。

2. 一个简化 BM25 实现

fromcollectionsimportCounterfromdataclassesimportdataclassfrommathimportlogimportredeftokenize(text:str)->list[str]:"""教学分词;生产中文检索应使用经过评测的分析器。"""returnre.findall(r"[a-z0-9_-]+|[\u4e00-\u9fff]",text.lower())@dataclass(frozen=True)classSearchDocument:document_id:strtenant_id:strtext:strvector:tuple[float,...]defbm25_scores(query:str,documents:list[SearchDocument],k1:float=1.5,b:float=0.75,)->dict[str,float]:ifnotdocuments:return{}tokenized={doc.document_id:tokenize(doc.text)fordocindocuments}avg_length=sum(map(len,tokenized.values()))/len(documents)query_terms=set(tokenize(query))scores={doc.document_id:0.0fordocindocuments}forterminquery_terms:containing=sum(termintokensfortokensintokenized.values())idf=log(1+(len(documents)-containing+0.5)/(containing+0.5))fordocumentindocuments:tokens=tokenized[document.document_id]frequency=Counter(tokens)[term]iffrequency==0:continuelength_factor=1-b+b*len(tokens)/max(avg_length,1)scores[document.document_id]+=idf*(frequency*(k1+1)/(frequency+k1*length_factor))returnscores

这是教学实现,未覆盖生产搜索引擎的分词、字段权重和优化。

3. 向量排名

frommathimportsqrtdefcosine(left:tuple[float,...],right:tuple[float,...])->float:ifnotleftorlen(left)!=len(right):raiseValueError("向量维度不一致")denominator=sqrt(sum(x*xforxinleft))*sqrt(sum(x*xforxinright))return0.0ifdenominator==0elsesum(x*yforx,yinzip(left,right))/denominatordefvector_ranking(query_vector:tuple[float,...],documents:list[SearchDocument],)->list[str]:return[item.document_idforiteminsorted(documents,key=lambdadoc:(-cosine(query_vector,doc.vector),doc.document_id,),)]

4. 使用 RRF 融合排名

Reciprocal Rank Fusion(倒数排名融合)只使用名次,不要求两路分数同尺度:

defreciprocal_rank_fusion(rankings:list[list[str]],rank_constant:int=60,)->list[tuple[str,float]]:ifrank_constant<=0:raiseValueError("rank_constant 必须大于 0")scores:dict[str,float]={}forrankinginrankings:forrank,document_idinenumerate(ranking,start=1):scores[document_id]=scores.get(document_id,0.0)+(1.0/(rank_constant+rank))returnsorted(scores.items(),key=lambdaitem:(-item[1],item[0]))

60是常见示例参数,不是必须值,应通过查询集调优。

5. 完整的权限内混合检索

defhybrid_search(query:str,query_vector:tuple[float,...],documents:list[SearchDocument],tenant_id:str,allowed_documents:frozenset[str],top_k:int=5,)->list[SearchDocument]:# 两路检索使用完全相同的授权候选集合candidates=[docfordocindocumentsifdoc.tenant_id==tenant_idanddoc.document_idinallowed_documents]ifnotcandidates:return[]lexical_scores=bm25_scores(query,candidates)lexical_rank=[keyforkey,scoreinsorted(lexical_scores.items(),key=lambdaitem:(-item[1],item[0]),)ifscore>0]semantic_rank=vector_ranking(query_vector,candidates)fused_ids=[document_idfordocument_id,_inreciprocal_rank_fusion([lexical_rank,semantic_rank])[:top_k]]document_map={doc.document_id:docfordocincandidates}return[document_map[document_id]fordocument_idinfused_ids]

6. 可复验测试

deftest_rare_error_code_is_recovered()->None:documents=[SearchDocument("semantic","t1","登录认证失败处理",(1.0,0.0)),SearchDocument("exact","t1","错误码 ERR-1042 修复步骤",(0.0,1.0)),SearchDocument("other","t2","ERR-1042 内部秘密",(0.0,1.0)),]result=hybrid_search("ERR-1042",query_vector=(1.0,0.0),documents=documents,tenant_id="t1",allowed_documents=frozenset({"semantic","exact","other"}),top_k=2,)ids=[item.document_idforiteminresult]assert"exact"inidsassert"other"notinids

7. 如何评测混合检索

分别报告关键词、向量和混合三组结果:

  • Recall@K:正确证据是否进入前 K;
  • MRR:第一个正确结果排在多前;
  • NDCG:多个相关等级的排序质量;
  • 零结果率、P95 延迟和检索成本;
  • 按编号查询、自然语言、错别字和多语言切片。

如果混合结果没有优于单路,就不应仅因架构更复杂而上线。

8. 对抗性审查

  • 两路检索必须使用相同权限过滤;
  • 不把两种原始分数直接相加;
  • 关键词索引和向量索引更新应保持版本一致;
  • 对重复 Chunk 去重;
  • 恶意文档可堆砌关键词,需要来源质量和重排;
  • 查询日志不默认保存敏感原文。

9. 总结

混合检索用关键词守住精确匹配,用向量扩展语义召回,再用稳定融合算法组合候选。它提升的是召回候选质量,最终仍需要重排和生成校验。

http://www.jsqmd.com/news/1334355/

相关文章:

  • [2-4-02].第01节:ES初识 - ElasticStack概念
  • 3步掌握SpiffWorkflow:用Python工作流引擎构建企业级业务流程
  • 终极rtl88x2bu驱动安装指南:专业级Linux Wi-Fi适配器解决方案
  • 小程序开发品牌有哪些?2026年企业项目采购中的两类服务观察 - 维双云小凡
  • 单人开小餐馆用什么复合调料:定量出餐操作全流程 - 产品推荐官
  • C语言贪吃蛇项目实战:从链表应用到游戏循环的工程化实现
  • iOS模拟器控制自动化测试:从零基础配置到企业级部署全攻略
  • 如何高效使用MobaXterm中文版:Windows远程管理的终极一体化解决方案
  • 5分钟快速上手BilibiliDown:免费开源B站视频音频下载工具终极指南
  • 【Linux系统安装教程】最新VMware虚拟机手把手教你搞定Linux部署
  • 为了多赚 50 块差价,我被骗走一张 500 元京东 E 卡:三次变现踩坑全复盘 - 京质回收
  • 如何高效备考408:计算机考研数据结构算法完整指南
  • git rebase master
  • 戴森球计划工厂蓝图终极指南:3000+蓝图助你快速建立星际工业帝国
  • 钢厂净水站可视化管理平台方案
  • 一文看懂温州GEO优化公司推荐:从技术底座到落地效果的全景对比 - 资讯报道
  • 2026中医体质辨识仪厂家推荐哪一家:正规实力服务商盘点解析 + 选型避坑全指南FAQ - 商业大观
  • 5个理由告诉你为什么BlenderGIS是地理数据3D可视化的终极解决方案
  • Python编程入门实战:从环境搭建到核心语法精讲
  • PDF补丁丁终极使用指南:如何用免费工具轻松解决所有PDF编辑难题
  • CALM与传统自回归模型:BrierLM分数5.72 vs 6.05的背后
  • 为什么选择本地音频转录:3步完成Buzz安装的完整指南
  • 机床导轨防护罩/数控机床防护罩/机床防护罩生产厂家有哪些?源头工厂联系方式汇总 - 品牌推荐大师
  • 暑假备考考研英语真题怎么规划?巨微真题考研真相带你梳理刷题节奏,合理安排时间 - 资讯报道
  • 面试追问背后的逻辑与应对策略
  • 2026年中医经络检测仪厂家靠谱性深度盘点:行业选型标准、避坑指南及正规服务商全解析 - 行业观察网
  • Windows CMD与批处理脚本实战指南:从基础命令到自动化脚本编写
  • 拆解 anysearch 重构智能体信息获取链路的底层逻辑 - 资讯综合
  • 构建用户情绪识别系统:从反馈收集到智能分析的技术实践
  • 3步永久免费激活IDM:无需破解的智能脚本终极指南