高级 RAG:混合检索与 Qdrant 向量库

Published by rcdfrd on 2026-02-21

高级 RAG:混合检索与 Qdrant 向量库

前面的 RAG 用的是纯语义检索,即只用密集向量做相似度搜索。但语义检索有时会漏掉关键词完全匹配的结果。混合检索同时用密集向量和稀疏向量(BM25),取两者之长。

混合检索的原理

密集向量擅长语义理解,「快乐」和「开心」能匹配上。稀疏向量(BM25)擅长关键词匹配,专有名词、编号这类精确查询效果更好。混合检索把两者的分数融合,覆盖更多场景。

用 Qdrant 实现

from langchain_community.document_loaders import TextLoader
from langchain_openai import OpenAIEmbeddings
from langchain_qdrant import FastEmbedSparse, QdrantVectorStore, RetrievalMode
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 加载和切分
loader = TextLoader("data/article.txt")
documents = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
chunks = splitter.split_documents(documents)

# 密集 + 稀疏嵌入
dense = OpenAIEmbeddings(model="text-embedding-3-small")
sparse = FastEmbedSparse(model_name="Qdrant/bm25")

# 创建混合向量库
vectorstore = QdrantVectorStore.from_documents(
    documents=chunks,
    embedding=dense,
    sparse_embedding=sparse,
    location=":memory:",
    collection_name="hybrid_rag",
    retrieval_mode=RetrievalMode.HYBRID,
)

关键是 RetrievalMode.HYBRID,告诉 Qdrant 同时用两种向量做检索。FastEmbedSparse 用 BM25 算法生成稀疏向量,运行在本地,不需要调 API。

接入 Agent

from langchain.agents import create_agent
from langchain.tools import tool

retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

@tool(response_format="content")
def retrieve_context(query: str) -> str:
    """检索相关文档"""
    docs = retriever.invoke(query)
    return "\n\n".join([doc.page_content for doc in docs])

agent = create_agent(
    model=model,
    tools=[retrieve_context],
    system_prompt="用检索到的内容回答问题,找不到就说不知道。",
)

小结

混合检索是 RAG 质量提升的重要一步。Qdrant 原生支持混合模式,配合 LangChain 用起来很顺畅。如果你的 RAG 准确率不够高,试试混合检索。