首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用 BM25 与向量混合检索提升 RAG 召回

用 BM25 与向量混合检索提升 RAG 召回

原创
作者头像
小凡geo用户12683298
发布于 2026-09-07 13:12:37
发布于 2026-09-07 13:12:37
1540
举报

python

代码语言:javascript
复制
# 依赖:pip install rank_bm25==0.2.2 sentence-transformers==2.7.0 numpy==1.26.4
# 纯向量检索对关键词精确匹配(如专有名词、型号、编号)不敏感,容易漏掉含关键字的片段。
# BM25 基于词频统计,擅长精确关键词匹配;二者互补。混合检索先分别召回再加权融合,召回完整度通常优于单路。
import numpy as np
from rank_bm25 import BM25Okapi
from sentence_transformers import SentenceTransformer

docs = [
    "产品A型号 X-200 支持私有化部署,适用于金融场景。",
    "产品B型号 Y-500 仅提供 SaaS,适合中小团队。",
    "RAG 系统先用向量检索召回片段,再让大模型生成答案。",
    "金融场景对数据合规要求高,私有化部署更受青睐。",
]
tokenized = [d.split() for d in docs]
bm25 = BM25Okapi(tokenized)
embedder = SentenceTransformer("BAAI/bge-small-zh")
doc_vecs = embedder.encode(docs, normalize_embeddings=True)

def hybrid_search(query: str, k: int = 2, alpha: float = 0.5):
    # BM25 路径:按词匹配打分
    bm25_scores = np.array(bm25.get_scores(query.split()))
    # 向量路径:语义相似度
    qv = embedder.encode([query], normalize_embeddings=True)[0]
    vec_scores = doc_vecs @ qv
    # 各自归一化后加权融合
    bm25_n = (bm25_scores - bm25_scores.min()) / (bm25_scores.max() - bm25_scores.min() + 1e-9)
    vec_n = (vec_scores - vec_scores.min()) / (vec_scores.max() - vec_scores.min() + 1e-9)
    fused = alpha * vec_n + (1 - alpha) * bm25_n
    return [docs[i] for i in np.argsort(-fused)[:k]]

if __name__ == "__main__":
    print(hybrid_search("金融场景 私有化部署 哪个型号"))

真实输出

text

代码语言:javascript
复制
['产品A型号 X-200 支持私有化部署,适用于金融场景。', '金融场景对数据合规要求高,私有化部署更受青睐。']

关键参数与边界:①alpha 为向量 / BM25 权重,默认 0.5,关键词密集场景调高 BM25 权重(alpha 降到 0.3);②BM25 需先分词,中文建议接 jieba 切词提升匹配;③两路各自归一化再融合,避免量纲差异压垮一路;④仅对向量召回 top 候选做 BM25 重排亦可(先向量取 top-50 再 BM25 精排),省算力;⑤对纯语义、无关键词的问题,BM25 增益有限,alpha 可上调。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • python
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档