高级 RAG:混合检索与 Qdrant 向量库
高级 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 准确率不够高,试试混合检索。