LlamaIndex RAG Retrieval: A Three‑Stage Pipeline (Pre‑, During‑, and Post‑Retrieval)

The article breaks down LlamaIndex RAG into three production stages—pre‑retrieval (metadata filtering, document constraints, query transformation), during retrieval (vector‑store ANN/hybrid/MMR, query modes, embedding consistency, extended retrievers) and post‑retrieval (filtering, reranking, context expansion, layout and recency handling)—and provides concrete code snippets, component choices, and practical recommendations for each stage.

AI Engineer Programming
AI Engineer Programming
AI Engineer Programming
LlamaIndex RAG Retrieval: A Three‑Stage Pipeline (Pre‑, During‑, and Post‑Retrieval)

Production Core Principles

1) Push vector‑store‑compatible operations down to the vector DB (metadata pre‑filtering, hybrid search, MMR).

2) Perform fine‑grained re‑ranking after retrieval, not before the LLM (Rerank is preferred over HyDE by default).

3) Respect API boundaries : the PostProcessor only takes effect in the QueryEngine chain.

4) Remember that the article is a generic analysis ; production solutions must also consider storage location (local vs. external vector store), data scale, and distributed environments.

Pre‑Retrieval (Before the First Vector‑Store Call)

Metadata Pre‑Filtering

Component: MetadataFilters +

MetadataFilter
from llama_index.core.vector_stores.types import MetadataFilters, MetadataFilter

filters = MetadataFilters(
    filters=[
        MetadataFilter(key="type", value="人物"),
        MetadataFilter(key="chapter", value=3, operator=">="),
    ],
    condition="and",
)

retriever = vector_index.as_retriever(
    similarity_top_k=10,
    filters=filters,
)

Principle: filter conditions are pushed down to Pinecone/Qdrant/etc., shrinking the candidate set during ANN search.

Use metadata for business dimensions (tenant, doc type, permission, language).

Standardise filter fields at ingest (enumerated values, unified naming).

Avoid high‑cardinality dynamic fields (e.g., user‑defined tags) that can invalidate the index.

Document / Node Range Constraints

Component: doc_ids, node_ids (parameter of VectorIndexRetriever)

retriever = vector_index.as_retriever(
    similarity_top_k=10,
    doc_ids=["doc_001", "doc_002"],  # limit to specific documents
)

Scenario: the user has selected a document, the conversation context is locked to a reference document, and multi‑turn dialogue narrows the search scope.

Recommendation: combine doc_ids with metadata filters for the most efficient narrowing.

Query Transform (HyDE)

Component: TransformQueryEngine +

BaseQueryTransform
# query_str stays unchanged (used for final LLM answer)
# custom_embedding_strs become [hypothetical_doc, original_query]
# which changes the retrieval embedding
hypothetical_doc = llm.predict(hyde_prompt, context_str=query_str)

Advantages: shortens semantic distance between query and documents; helps short or colloquial queries.

Disadvantages: adds one extra LLM call per query; hallucinated hypothetical documents may bias retrieval; marginal gains diminish after hybrid + rerank.

Recommendation: keep HyDE disabled by default; enable only after empirical validation on specific query types (short, ambiguous).

Routing and Multi‑Retriever Selection (Pre‑Retrieval Orchestration)

Components: RouterRetriever / RouterQueryEngine: LLM or rule decides which retriever to use. QueryFusionRetriever: parallel multiple retrievers + Reciprocal Rank Fusion (RRF). VectorIndexAutoRetriever: experimental LLM‑generated metadata filters; use with caution in production.

Example of QueryFusionRetriever configuration:

QueryFusionRetriever(
    retrievers=[dense_retriever, bm25_retriever],
    mode="reciprocal_rerank",  # production default RRF
    num_queries=1,               # disable LLM query expansion in production
    similarity_top_k=10,
)

Recommendation: use a single vector store with native hybrid if possible; employ QueryFusionRetriever only for multi‑source scenarios (vector + SQL + knowledge graph). Setting num_queries>1 is reserved for offline/high‑value use cases.

During Retrieval (Vector Store Execution)

Core Parameters

retriever = vector_index.as_retriever(
    similarity_top_k=30,               # number of candidates returned
    vector_store_query_mode="default",# query mode (see table below)
    alpha=0.5,                         # hybrid weight (dense × α, sparse × (1‑α))
    sparse_top_k=40,                    # for stores that support sparse vectors
    filters=metadata_filters,           # push‑down filtering
    embed_model=Settings.embed_model,   # query embedding model
)

The internal VectorStoreQuery built by LlamaIndex contains the fields shown above.

Query Modes (VectorStoreQueryMode)

DEFAULT

: pure dense ANN search – the most common default. HYBRID: dense + sparse fusion – used by Pinecone, Weaviate, Pinecone (dot‑product). SPARSE: pure BM25/sparse search – keyword exact matching. MMR: Maximum Marginal Relevance – adds diversity, not deduplication. TEXT_SEARCH: full‑text search – depends on vector‑store capabilities. SEMANTIC_HYBRID: semantic + keyword mix – supported by some stores.

Pinecone Hybrid Example

Index metric = dotproduct Both write and query use add_sparse_vector=True Data must contain

sparse_values
alpha

controls dense × α and sparse × (1‑α)

In LlamaIndex, sparse_top_k is ineffective for Pinecone; use the store‑level top_k instead.

Similarity Top‑K vs. Hybrid Top‑K

Recommendation: use a wide recall (top‑k 20‑50) during retrieval, then re‑rank a small subset (e.g., top‑5).

similarity_top_k = 20~50   # wide recall
    ↓
Rerank top_n = 5          # precise re‑ranking
    ↓
Synthesizer

If similarity_top_k is too small, relevant results are missed.

If too large, rerank becomes slow and noisy. hybrid_top_k applies only to stores that expose a hybrid‑specific parameter.

MMR (Diversity During Retrieval)

retriever = vector_index.as_retriever(
    similarity_top_k=10,
    vector_store_query_mode="mmr",
    vector_store_kwargs={
        "mmr_threshold": 0.5,
        "mmr_prefetch_k": 20,
    },
)

MMR introduces a diversity penalty between similar results, preventing the top‑k from being dominated by near‑duplicate passages. It is not a deduplication or a replacement for rerank.

Recommendation: try MMR for long documents with many repeated sections; default pipeline prefers rerank.

Embedding Model Consistency

The query embedding model must be identical to the one used at ingest; otherwise similarity scores become meaningless and the SimilarityPostprocessor cutoff fails.

Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-zh-v1.5")
vector_index = VectorStoreIndex.from_vector_store(
    vector_store=vector_store,
    embed_model=Settings.embed_model,  # cannot be omitted
)

Extended Retriever Components (During Retrieval)

AutoMergingRetriever

: vector search + docstore parent‑node merge (post‑retrieval stage). RecursiveRetriever: recursive lookup of reference nodes. QueryFusionRetriever: multi‑path retrieval + fusion (same as earlier).

Note: with external vector stores that lack a docstore, AutoMergingRetriever is essentially unusable because parent nodes are missing.

Post‑Retrieval (Application‑Layer Refinement)

Filtering Processors

SimilarityPostprocessor

: drop results below a score threshold. Production tip: calibrate cutoff per vector store (e.g., cosine vs. dot‑product ranges). KeywordNodePostprocessor: include/exclude based on keywords in the original text. Production tip: avoid in Chinese pipelines; prefer metadata + hybrid.

SimilarityPostprocessor(similarity_cutoff=0.62)

Reranking Processors

SentenceTransformerRerank

(local cross‑encoder). Use BAAI/bge-reranker-base for Chinese; bge-reranker-v2-m3 for multilingual long texts. CohereRerank (API). Model: rerank-multilingual-v3.0. LLMRerank (LLM choice‑select). High cost; not default.

from llama_index.core.postprocessor import SentenceTransformerRerank

reranker = SentenceTransformerRerank(
    model="BAAI/bge-reranker-base",
    top_n=5,
)

Context‑Extension Processors

MetadataReplacementPostProcessor

: replace a metadata field (e.g., window) with a larger context window. Works with SentenceWindow use‑case. PrevNextNodePostprocessor / AutoPrevNextNodePostprocessor: add preceding and following nodes (requires a docstore).

# Retrieve small sentences, then send a large window to the LLM
MetadataReplacementPostProcessor(target_metadata_key="window")

Layout Optimisation

LongContextReorder

: mitigates "Lost in the Middle" by alternating high‑score chunks from the beginning and end of the document.

Recency Processors

FixedRecencyPostprocessor

: requires a date metadata field to prefer newer documents. EmbeddingRecencyPostprocessor: deduplicates older, similar embeddings. TimeWeightedPostprocessor: applies time‑decay based on last access.

Security & Compliance

PIINodePostprocessor

: LLM‑based PII redaction. NERPIINodePostprocessor: NER‑based redaction.

Custom Deduplication (Not Built‑In)

When ingesting duplicate documents, implement a custom post‑processor because LlamaIndex does not provide one out‑of‑the‑box.

from llama_index.core.postprocessor.types import BaseNodePostprocessor
from llama_index.core.schema import NodeWithScore, QueryBundle
from typing import List, Optional

class DedupByContentPostprocessor(BaseNodePostprocessor):
    def _postprocess_nodes(
        self,
        nodes: List[NodeWithScore],
        query_bundle: Optional[QueryBundle] = None,
    ) -> List[NodeWithScore]:
        seen = set()
        result = []
        for n in nodes:
            key = n.node.get_content().strip()
            if key not in seen:
                seen.add(key)
                result.append(n)
        return result

Post‑Processor Execution Order

① SimilarityPostprocessor – drop obviously low‑score results (optional)
② DedupByContent (custom) – remove duplicate content (required for duplicate ingest)
③ SentenceTransformerRerank – fine‑grained re‑ranking (strongly recommended)
④ MetadataReplacement – for SentenceWindow scenarios
⑤ LongContextReorder – when feeding many chunks to the LLM

Principles:

Filter / deduplicate first to reduce the input size for rerank.

Rerank before any expansion or replacement (rank sentences, then expand to windows).

Place LongContextReorder at the very end.

Conclusion

LlamaIndex RAG filtering and augmentation form a three‑stage pipeline:

Pre‑Retrieval: decides what to search and where, using metadata pre‑filtering, document constraints, and optional query transformation.

During Retrieval: performs ANN / hybrid / MMR inside the vector store, with wide recall (top‑k 20‑50), consistent embedding models, and optional hybrid‑specific parameters.

Post‑Retrieval: applies application‑layer refinements; rerank provides the highest cost‑performance gain, while deduplication, score filtering, and layout tricks are added as needed.

Each added layer must be justified by measurable marginal value; otherwise, avoid unnecessary parameter bloat.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

RAGretrievalrerankpostprocessorhybrid searchLlamaIndexmetadata filter
AI Engineer Programming
Written by

AI Engineer Programming

In the AI era, defining problems is often more important than solving them; here we explore AI's contradictions, boundaries, and possibilities.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.