最近在搭一个简单的RAG问答系统,底层用的BM25做检索,但发现一个问题:用户搜“苹果手机怎么恢复数据”,结果top-3里居然有“苹果的营养价值”这种完全不相关的内容。我知道BM25是基于关键词匹配的,但“苹果”这个词在两个上下文里含义完全不同,难道分词器没做词义消歧?还是说需要加一层语义召回(比如向量检索)才能解决?我现在是纯关键词召回,没接入embedding,想问下有没有更轻量的办法先过滤掉这种歧义?比如自定义停用词表或者扩展同义词?或者干脆把BM25换成Elasticsearch的混合检索?希望有踩过坑的朋友指点一下,谢谢。
RAG系统用BM25召回,为什么查“苹果手机”却返回“水果营养”?
全部回复
共 166 条遇到过一模一样的坑,BM25对一词多义是真的无能为力,因为它压根不看语境。轻量点的办法其实可以先试试图谱或词典做实体链接,把“苹果手机”这类词在索引前就改写标注,比硬搞同义词表靠谱些。但说实话,纯靠规则补丁会越打越碎,你后面要真想解决歧义,还是得上向量召回,哪怕只用个轻量的embedding模型做二三路召回再做重排序也够。另外ES的混合检索只是把两个向量强行融合,核心问题没变,别指望它自动消歧。
BM25本来就不管语义,本质是词频统计,苹果手机和苹果在它眼里就是一个token,想靠它区分语境确实难。自定义停用词表治标不治本,因为用户query里“苹果”可能真指水果,也可能指品牌,规则很难覆盖。更轻量的办法是给文档加个类型标签,检索前先做一层意图粗分类,比如根据query里有没有“手机”“恢复数据”这类词直接过滤掉食品类内容。向量检索肯定更稳,但如果你暂时不想上,也可以试试给BM25加个加权字段,把标题匹配的权重调高,通常标题里“苹果手机”出现时比正文里孤立的水果词更可能是目标。
BM25本来就这德行,纯靠词频不管语义,想轻量点可以先给“苹果”加个品类词典做上下文过滤,比硬上向量快。
或者干脆试试es带boosting的query,把“手机”这种词权重调高,稍微能救回来点。
我也踩过这坑,BM25本身就没法解决一词多义,分词器再强也搞不定“苹果”到底是水果还是品牌。最轻量的办法是先加一层规则或词典做query意图判断,比如检测到“手机”“恢复”“数据”这类词就强制把水果类文档降权。想彻底点还是得上向量召回做混合排序,ES的hybrid search确实能缓解,但调参和成本也得考虑。
这问题太常见了,BM25本来就不管语义,分词器也救不了你。我之前也踩过这坑,加同义词表只能缓解,比如把“苹果手机”整体作为一个词,但维护起来很累。轻量方案可以试试query扩展加规则过滤,比如检测到“手机”“数据”这类词就加权排斥“营养”类文档。真想根治还是得上混合检索,Elasticsearch的rank_feature或者直接向量召回,哪怕用个小模型也比纯BM25强。
我之前也踩过这个坑,BM25对多义词确实没啥好办法,分词器只管切词不管语义。轻量方案可以试试给“苹果”加个上下文窗口,比如查“手机”时把“水果”相关的文档先降权,不过维护起来挺麻烦。后来我直接上了ES的混合检索,BM25加向量召回,歧义问题基本就没了,成本也没想象中高。如果你暂时不想接embedding,先搞个领域同义词表把“苹果手机”映射成“iPhone”也能救急。