
Reranking: The Cheapest Quality Win in RAG
Reranking is the most cost-effective way to boost RAG accuracy. Learn how to implement cross-encoders like Cohere and BGE for better retrieval results.
In Retrieval-Augmented Generation (RAG), the most common failure mode is not that the model cannot answer, but that it cannot find the right context. Developers often respond by increasing the dimensionality of their embeddings or tweaking the vector database index. However, the most significant leap in retrieval accuracy comes from a structural change in the pipeline: introducing a reranking stage.
This article is Part 6 of the RAG from Zero to Production series.
Reranking is the highest return-on-investment optimization available to RAG systems today. It delivers a disproportionate boost in relevance while adding minimal computational overhead. The core insight is simple: use a cheap, fast retriever to cast a wide net, then use a precise, expensive cross-encoder to filter the results.
The Two-Stage Retrieval Problem
Standard RAG pipelines typically rely on bi-encoders (also known as dual encoders). In this architecture, the query and the document are encoded into separate vectors independently. The relevance score is calculated via a dot product or cosine similarity between these two vectors.
This approach is computationally efficient because you can pre-compute document vectors and store them in a vector index (like FAISS or Pinecone). However, it suffers from a fundamental limitation: representation mismatch. The query and the document are encoded in isolation.
The model cannot see how specific words in the query interact with specific words in the document during the encoding phase. It relies on the embedding space to implicitly capture these interactions, which often fails for nuanced semantic matches. Research such as Sentence-BERT (Reimers and Gurevych, 2019) highlights that while bi-encoders are efficient, they lack the cross-attention mechanisms needed for fine-grained relevance scoring.
For example, if a query asks for "the capital of France" and the document says "Paris is a city in France," a bi-encoder might miss the link if the embedding space doesn't strongly align "capital" with "Paris." A cross-encoder, by contrast, sees both texts simultaneously.
How Cross-Encoders Work
The solution is the cross-encoder. Unlike bi-encoders, cross-encoders take both the query and the candidate document as a single input sequence. They use a Transformer model (like BERT or its variants) to process the combined text.
The Mechanism of Interaction
- Concatenation: The query and document are joined, typically with a special separator token (like
[SEP]). - Attention: The Transformer's self-attention mechanism allows every token in the query to attend to every token in the document, and vice versa.
- CLS Token: The output of the special
[CLS]token at the beginning of the sequence serves as a pooled representation of the entire interaction. - Classification Head: This
[CLS]vector is passed through a linear layer to produce a single relevance score (usually between 0 and 1).
This architecture allows the model to learn complex, non-linear relationships. It can detect synonyms, paraphrasing, and negative constraints that bi-encoders miss. For instance, it can understand that "not the capital" excludes Paris, whereas a bi-encoder might still assign a high similarity score based on word overlap.
The Cost Trade-off
The downside is obvious: cross-encoders are slow. If you have 10,000 documents, encoding all pairs (query × document) is computationally prohibitive. This is why we use a two-stage retrieval strategy:
- Stage 1 (Recall): Use a fast bi-encoder to retrieve the top-k candidates (e.g., K=50 or 100) from the vector database. This step is cheap and fast.
- Stage 2 (Precision): Run only these K candidates through the cross-encoder. Since K is small, the cost is manageable.
This hybrid approach gives you the best of both worlds: the recall of vector search and the precision of deep semantic understanding.
Implementing Reranking: Cohere and BGE
Two popular tools for reranking are Cohere’s Rerank API and the open-source BGE (BAAI General Embedding) Reranker. The BGE reranker is widely used for its performance and open accessibility. Both leverage cross-encoder architectures but differ in deployment and ease of use.
Option 1: Cohere Rerank (API-Based)
Cohere provides a managed service that abstracts away the infrastructure. You send the query and a list of documents, and it returns them sorted by relevance. This is ideal for production systems where operational overhead matters.
import cohere
co = cohere.Client('YOUR_API_KEY')
response = co.rerank(
model='rerank-english-v2.0',
query='What is the capital of France?',
documents=[
"Paris is a city in France.",
"The Eiffel Tower is located in Paris.",
"Berlin is the capital of Germany."
],
top_n=2
)
for i, result in enumerate(response.results):
print(f"Rank {i+1}: Score {result.relevance_score:.4f} - {result.document}")Cohere’s model is optimized for speed and accuracy, making it a strong default choice. However, it introduces network latency and depends on an external provider.
Option 2: BGE Reranker (Open Source)
For systems requiring data privacy or lower latency via local inference, BGE (by BAAI) offers excellent open-source models. The BGE-reranker-base model is widely used and performs competitively with commercial alternatives.
Using the sentence_transformers library:
from sentence_transformers import CrossEncoder
model = CrossEncoder('BAAI/bge-reranker-base')
pairs = [
("What is the capital of France?", "Paris is a city in France."),
("What is the capital of France?", "Berlin is the capital of Germany.")
]
scores = model.predict(pairs)
for pair, score in zip(pairs, scores):
print(f"Score: {score:.4f} - {pair[1]}")BGE’s reranker is lightweight and can be deployed on CPU or GPU. It integrates seamlessly with frameworks like LangChain, allowing you to plug it into existing retrieval chains without changing the overall architecture.
Integrating Reranking into Your RAG Pipeline
To implement RAG optimization, insert a reranker step between the retriever and the LLM.
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import OpenAIEmbeddings
# 1. Setup vector store
vectorstore = FAISS.from_texts(["Paris is a city in France.", "Berlin is the capital of Germany."], OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
# 2. Setup reranker
reranker = CohereRerank(top_n=3, model="rerank-english-v2.0")
# 3. Create compression retriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=retriever
)
# 4. Retrieve and rerank
docs = compression_retriever.invoke("What is the capital of France?")
print([doc.page_content for doc in docs])The ContextualCompressionRetriever automatically fetches 10 documents, passes them to the reranker, and returns only the top 3. This reduces the context window sent to the LLM, lowering token costs and improving generation quality by focusing on the most relevant information.
Conclusion
Reranking is not just an optimization; it is a necessity for high-quality RAG systems. By separating the cheap, broad recall of bi-encoders from the precise, expensive evaluation of cross-encoders, you achieve a significant jump in retrieval accuracy without proportional increases in cost. Whether you choose Cohere for ease of use or BGE for control, integrating a reranker is the single most effective step you can take to improve your RAG system’s reliability.
Related posts
What RAG Actually Solves (and What It Doesn't)
An examination of Retrieval Augmented Generation (RAG), clarifying how it reduces hallucination through grounding while identifying its architectural limitations.
Caching Strategies for RAG Pipelines
Explore effective caching strategies for RAG pipelines, including embedding and retrieval caches, to improve hit rates and reduce latency, while managing invalidation effectively.
RAG Hallucination Detection with Groundedness Scoring
Explore methods for detecting hallucinations in RAG systems using groundedness scoring and natural language inference to improve faithfulness.