You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Langchain检索器过滤问题:BM25在EnsembleRetriever中如何维持过滤规则

LangChain检索器过滤及EnsembleRetriever兼容问题

LangChain中部分检索器(比如FAISS向量检索器)支持filter参数,但BM25Retriever默认不支持原生过滤逻辑,所以你当前的代码里只有FAISS检索器应用了topic="sport"的过滤,BM25检索器仍会返回所有文档,导致组合后的EnsembleRetriever整体过滤规则失效。

要让BM25检索器也维持过滤规则,有两种可行方案:

方案1:预过滤文档后初始化BM25Retriever

先从原始文档集中筛选出符合过滤条件的文档,再用这些文档构建BM25Retriever,这样BM25检索的范围本身就限定在目标文档内:

documents = [Document(page_content='The Celtics are my favourite team.', metadata={"topic":"sport"}),
     Document(page_content='The Boston Celtics won the game by 20 points', metadata={"topic":"sport"}),
     Document(page_content='This is just a random text.', metadata={"topic":"unknown"})]

# 预过滤出topic为sport的文档
filtered_docs = [doc for doc in documents if doc.metadata.get("topic") == "sport"]

# embeddings 为任意LangChain嵌入模型
db = FAISS.from_documents(documents, embeddings) 
question = "Who is my favourite team?"

# 用过滤后的文档初始化BM25Retriever
retriever = BM25Retriever.from_documents(filtered_docs)
faiss_retriever = db.as_retriever(search_kwargs={'filter': dict(topic="sport"), 'k': 4, 'fetch_k': 8})
er = EnsembleRetriever(retrievers=[retriever, faiss_retriever], weights=[0.3, 0.7])
results = er.get_relevant_documents(question)

方案2:自定义带过滤功能的BM25Retriever子类

继承原BM25Retriever类,重写检索方法,在检索前先对文档应用过滤规则:

from langchain.retrievers import BM25Retriever

class FilterableBM25Retriever(BM25Retriever):
    def __init__(self, *args, filter_dict=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.filter_dict = filter_dict or {}

    def get_relevant_documents(self, query, **kwargs):
        # 先过滤文档
        filtered_docs = []
        for doc in self.documents:
            match = True
            for key, value in self.filter_dict.items():
                if doc.metadata.get(key) != value:
                    match = False
                    break
            if match:
                filtered_docs.append(doc)
        # 临时替换原文档为过滤后的文档
        original_docs = self.documents
        self.documents = filtered_docs
        # 执行BM25检索
        results = super().get_relevant_documents(query, **kwargs)
        # 恢复原文档
        self.documents = original_docs
        return results

# 使用自定义检索器
documents = [Document(page_content='The Celtics are my favourite team.', metadata={"topic":"sport"}),
     Document(page_content='The Boston Celtics won the game by 20 points', metadata={"topic":"sport"}),
     Document(page_content='This is just a random text.', metadata={"topic":"unknown"})]

# embeddings 为任意LangChain嵌入模型
db = FAISS.from_documents(documents, embeddings) 
question = "Who is my favourite team?"

# 初始化带过滤的BM25Retriever
retriever = FilterableBM25Retriever.from_documents(documents, filter_dict={"topic":"sport"})
faiss_retriever = db.as_retriever(search_kwargs={'filter': dict(topic="sport"), 'k': 4, 'fetch_k': 8})
er = EnsembleRetriever(retrievers=[retriever, faiss_retriever], weights=[0.3, 0.7])
results = er.get_relevant_documents(question)

两种方案都能确保BM25检索器只返回符合过滤条件的文档,和FAISS检索器的结果统一后,EnsembleRetriever就能维持整体的过滤规则。

内容的提问来源于stack exchange,提问作者tcotts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 05:16:28