Skip to content

BestRAG - Hybrid RAG Storage & Retrieval Cheatsheet

BestRAG - Hybrid RAG Storage & Retrieval Cheatsheet

BestRAG (Best Retrieval Augmented Generation) is a Python library for building hybrid RAG pipelines. It combines dense, sparse, and late-interaction embeddings for storing and searching documents efficiently, using Qdrant as the vector store and FastEmbed for the embeddings. The idea: store each chunk once with multiple representations, then retrieve with fused relevance so you get both the semantic recall of dense vectors and the exact-term precision of sparse (BM25-style) search.

Installation

MethodCommand
pippip install bestrag
RequirementsA Qdrant instance (local Docker or Qdrant Cloud)
EmbeddingsUses FastEmbed under the hood
Verifypython -c "import bestrag; print('ok')"

Why Hybrid

Retrieval typeStrong atWeak at
Dense (vector)Meaning, paraphraseExact IDs, numbers, rare terms
Sparse (BM25)Exact terms, identifiersSynonyms, paraphrase
Late interactionFine-grained token matchingCost
Fused (hybrid)Best of dense + sparse

BestRAG stores all representations so a single query benefits from all of them.

Basic Usage

from bestrag import BestRAG

rag = BestRAG(
    url="http://localhost:6333",     # Qdrant
    api_key="...",                   # if using Qdrant Cloud
    collection_name="docs",
)

# Ingest documents (embeds dense + sparse + late-interaction, upserts to Qdrant)
rag.store_pdf("handbook.pdf")
rag.store_text("Nick prefers concise answers.", metadata={"source": "prefs"})

# Retrieve with fused hybrid relevance
results = rag.search("what does the refund policy say?", limit=5)
for r in results:
    print(r.score, r.text)
MethodDescription
BestRAG(url, collection_name, ...)Connect to Qdrant, pick a collection
store_pdf(path)Parse + chunk + embed + upsert a PDF
store_text(text, metadata=...)Ingest raw text
search(query, limit=k)Hybrid (fused) retrieval
delete(...)Remove documents

What Happens on Ingest

StepDetail
ParseExtract text (e.g. from PDF)
ChunkSplit into passages
EmbedDense + sparse + late-interaction vectors per chunk
UpsertStore all vectors + payload in Qdrant
StepDetail
Embed queryDense + sparse (+ late interaction)
Query QdrantRetrieve candidates per representation
FuseCombine rankings (RRF-style) into one list
ReturnTop-k passages with scores + metadata

Feeding Results to an LLM

# Retrieve, then build a grounded prompt
hits = rag.search(user_question, limit=5)
context = "\n\n".join(h.text for h in hits)
prompt = f"Answer using only this context:\n{context}\n\nQ: {user_question}"
# → send prompt to your LLM

Tuning

LeverEffect
Chunk size/overlapRetrieval granularity
Dense modelSemantic quality (via FastEmbed)
Sparse modelExact-term matching (BM25)
limit (k)Recall vs prompt size
Metadata filtersRestrict search scope / access control

BestRAG vs Rolling Your Own

AspectBestRAGManual (LangChain/LlamaIndex)
Hybrid setupBuilt-in (dense+sparse+LI)Manual wiring
StoreQdrant, opinionatedAny, flexible
ControlSimpler, fewer knobsFull control
Best forFast hybrid RAG startCustom pipelines

Built on FastEmbed and Qdrant; reach for LangChain or LlamaIndex when you need full pipeline control.

Resources