1. 混合搜索系统概述在信息检索领域混合搜索系统正逐渐成为提升搜索质量的主流方案。这个项目实现了一个结合BM25算法和密集向量检索的混合搜索系统专门针对医疗咨询场景中的症状描述与治疗方案匹配问题。我最近在实际工作中发现单一检索方法往往存在明显短板。传统关键词检索如BM25擅长处理精确匹配但对语义相似但用词不同的查询效果不佳而基于深度学习的向量检索能捕捉语义关系却可能忽略关键词的重要性。这个项目通过加权融合两种方法在医疗问答场景中实现了更精准的结果召回。系统处理的数据结构很明确每条数据包含instruction症状描述和output解释或方案。例如输入嘴唇肿起来了怎么办系统需要从知识库中找到最相关的医疗建议。这种需求在在线医疗咨询、智能分诊等场景中非常普遍。2. 系统设计与核心组件2.1 数据处理流程系统首先加载JSON格式的训练数据每条数据包含两个关键字段instruction患者的症状描述如持续头痛三天output对应的医疗建议如建议服用布洛芬并观察with open(../Data/train.json, r, encodingutf-8) as f: data [json.loads(line) for line in f.readlines()] instructions [entry[instruction] for entry in data] outputs [entry[output] for entry in data]实际应用中建议对原始数据进行清洗和标准化处理比如统一症状描述中的医学术语将发烧和发热归一化这对提升检索效果至关重要。2.2 BM25检索模块实现BM25是基于词频统计的传统检索算法本项目使用rank_bm25库实现from rank_bm25 import BM25Okapi import jieba def bm25_search(query): # 中文分词处理 tokenized_corpus [jieba.lcut(doc) for doc in instructions] bm25 BM25Okapi(tokenized_corpus) # 查询处理与评分 tokenized_query jieba.lcut(query) bm25_scores bm25.get_scores(tokenized_query) # 分数归一化处理 bm25_scores np.array(bm25_scores) bm25_scores_normalized (bm25_scores - bm25_scores.min()) / (bm25_scores.max() - bm25_scores.min()) return bm25_scores_normalized关键细节说明必须对中文进行分词处理jieba分词效果直接影响检索质量BM25Okapi会计算每个词项的逆文档频率(IDF)和文档内词频(TF)归一化处理确保不同查询间的分数可比性2.3 向量检索模块设计向量检索使用ChromaDB向量数据库和阿里通义千问的embedding模型class MyVectorDBConnector: def __init__(self, collection_name): self.client chromadb.Client(Settings(allow_resetTrue)) self.collection self.client.get_or_create_collection(collection_name) self.api_client get_normal_client() # 自定义API客户端 def get_embeddings_batch(self, texts, modelALI_TONGYI_EMBEDDING_V4, batch_size10): all_embeddings [] for i in range(0, len(texts), batch_size): batch texts[i:i batch_size] data self.api_client.embeddings.create(inputbatch, modelmodel).data all_embeddings.extend([x.embedding for x in data]) return all_embeddings实际使用中发现几个关键点批量处理文本时需要注意API的速率限制batch_size10是个经验值不同embedding模型对医疗文本的编码效果差异很大需要测试选择ChromaDB的collection命名要有明确业务含义方便后续维护3. 混合搜索实现细节3.1 分数融合策略核心融合算法采用线性加权def hybrid_search(query, top_k3, bm25_weight0.5): bm25_scores bm25_search(query) vector_scores vector_search(query) # 加权融合 combined_scores bm25_weight * bm25_scores (1-bm25_weight) * vector_scores # 结果排序 top_index combined_scores.argsort()[::-1][:top_k] return [outputs[i] for i in top_index]权重选择经验bm25_weight0.5是常用起点对术语规范的领域如医学可适当提高向量权重可通过A/B测试确定最佳权重3.2 向量距离计算项目使用欧氏距离衡量向量相似度query_embedding np.array(vector_db.get_embeddings_batch([query])) doc_embeddings np.array(vector_db.get_embeddings_batch(instructions)) # 计算欧氏距离并转换为相似度分数 vector_scores np.linalg.norm(query_embedding - doc_embeddings, axis1) vector_scores_normalized 1 - (vector_scores - vector_scores.min()) / (vector_scores.max() - vector_scores.min())实际测试发现对医疗文本余弦相似度有时比欧氏距离效果更好建议两种方法都尝试4. 性能优化与实践经验4.1 检索效率优化索引预热系统启动时预加载BM25索引和向量数据结果缓存对高频查询实现结果缓存批量处理向量计算采用批处理减少API调用# 初始化时预加载数据 vector_db MyVectorDBConnector(medical_knowledge) vector_db.add_documents(instructions, outputs)4.2 医疗场景特殊处理同义词扩展构建医疗同义词库如心梗心肌梗塞症状标准化将口语化描述转为医学术语结果排序优化危急症状优先排序4.3 常见问题排查分词不一致症状BM25检索结果不稳定解决统一使用医疗领域分词词典向量质量差症状语义相近的查询结果差异大解决尝试不同embedding模型或微调权重选择困难症状混合效果不如单一方法解决基于测试集进行网格搜索调参5. 扩展应用与改进方向这个混合搜索框架可应用于多个领域法律咨询法条与案例检索电商客服商品问题与解决方案匹配教育问答学习问题与知识点关联值得尝试的改进方向动态权重调整根据查询特点自动调整BM25/向量权重多模态检索结合图片症状描述等反馈学习根据用户点击优化排序我在实际部署中发现系统对长尾查询罕见症状的处理仍需加强。最近尝试用Rerank模型对初步结果进行重排序准确率提升了约15%。另一个实用技巧是对医疗结果添加可信度评分帮助用户判断信息可靠性。