Stop Settling for Mediocre RAG: A Practical Guide to Reranking with BGE and Cohere

AI tutorial - IT technology blog
AI tutorial - IT technology blog

The Precision Gap in Vector Search

Ever built a RAG system only to have the AI confidently quote the wrong part of your documentation? It is a common headache. Even if you use a high-quality model like OpenAI’s text-embedding-3-small, vector databases often struggle with precision. They might return the top 10 documents, but the actual answer is often buried at rank #7, or missing entirely because the mathematical “similarity” didn’t align with the semantic meaning.

Standard vector search relies on Bi-Encoders. These models turn documents and queries into vectors independently. This approach is lightning-fast—searching millions of documents in under 10ms—but it lacks nuance. In production environments, relying solely on vector similarity is a recipe for “hallucinations” triggered by noisy or distractor context.

The Two-Stage Retrieval Strategy

To fix accuracy without sacrificing speed, we use a two-stage pipeline. Think of it as a wide-net search followed by a deep-dive inspection:

  1. Retrieval (Stage 1): Use your vector database to quickly grab the top 50–100 potential candidates.
  2. Reranking (Stage 2): Use a Cross-Encoder (Reranker) to re-score those candidates. The Reranker looks at the query and the document simultaneously to understand deep relationships that simple distance math misses.

Rerankers are computationally heavier than vector searches. However, since you only run them on a small subset of documents (like the top 50), the total latency remains manageable—usually adding only 100-200ms to the total request time.

Bi-Encoders vs. Cross-Encoders: What’s the Difference?

Bi-Encoders treat the query and the document as two separate ships passing in the night. The similarity is just the cosine distance between two points in a high-dimensional space. The model doesn’t actually “read” the query and document together.

Cross-Encoders, such as the BGE-Reranker, take the query and the document as a single input pair. They use the full attention mechanism of a Transformer to weigh every word in the query against every word in the document. This generates a precise relevance score, typically between 0 and 1, which is far more reliable for selecting the final context for your LLM.

Option 1: Running BGE-Reranker Locally

The BGE (Beijing Academy of Artificial Intelligence) Reranker is a powerhouse in the open-source world. It is an excellent choice if you have your own GPU resources and want to avoid per-token API costs. The v2-m3 version is particularly popular for its balance of speed and performance.

1. Setup

pip install flash-attn
pip install -U FlagEmbedding

2. Implementation

This snippet demonstrates how to re-sort documents retrieved from your database. The model requires roughly 2-4GB of VRAM for efficient inference.

from FlagEmbedding import FlagReranker

# Initialize the reranker
reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True) 

query = "How do I optimize a RAG system for production?"

# These candidates usually come from a vector search (e.g., Pinecone or Milvus)
retrieved_documents = [
    "To optimize RAG, you should consider fine-tuning your embedding model.",
    "The weather in San Francisco is usually foggy in the morning.",
    "Reranking is a key technique to improve context relevance in RAG pipelines.",
    "Python is a popular language for data science and AI development."
]

# Score the pairs
pairs = [[query, doc] for doc in retrieved_documents]
scores = reranker.compute_score(pairs)

# Sort by score (highest relevance first)
reranked_results = sorted(zip(retrieved_documents, scores), key=lambda x: x[1], reverse=True)

for doc, score in reranked_results:
    print(f"Score: {score:.4f} | Document: {doc}")

Option 2: Using the Cohere Rerank API

If you prefer not to manage infrastructure, Cohere offers a managed Rerank API. It is widely considered the gold standard for production RAG because it is easy to scale and requires zero maintenance. It integrates seamlessly with frameworks like LangChain or LlamaIndex.

1. Install the Client

pip install cohere

2. Implementation

Using Cohere’s rerank-english-v3.0 model allows you to process documents in bulk with a single API call.

import cohere

co = cohere.Client("YOUR_COHERE_API_KEY")

query = "What are the benefits of using a cross-encoder?"
docs = [
    "Cross-encoders are more accurate because they perform full-attention over query-document pairs.",
    "Bi-encoders are faster but less precise for complex semantic matching.",
    "Deep learning models require significant compute resources.",
    "The benefits of exercise include improved cardiovascular health."
]

response = co.rerank(
    model="rerank-english-v3.0",
    query=query,
    documents=docs,
    top_n=3
)

for result in response.results:
    print(f"Rank: {result.index} | Score: {result.relevance_score:.4f}")
    print(f"Content: {docs[result.index]}\n")

Strategic Implementation

When designing RAG architectures, I recommend a “100-to-5” strategy. Fetch 100 documents via vector search, rerank them to find the top 5, and only send those 5 to your LLM (like GPT-4o). This approach solves the “lost in the middle” problem where LLMs ignore context hidden in long lists of documents.

Choosing Your Tool

  • BGE-Reranker: Choose this for high-privacy requirements or when you have idle GPU capacity. It is “free” in terms of licensing but carries hosting costs.
  • Cohere Rerank API: Choose this for speed to market. It handles tokenization and model updates for you, allowing you to focus on the application logic rather than VRAM management.

Final Thoughts

Adding a reranking step is the single most effective way to turn a RAG hobby project into a production-ready tool. By using models like BGE or Cohere, you ensure the LLM sees the best possible data. Accuracy in RAG isn’t just about the volume of data you have; it’s about the quality of the data you choose to show your model.

Share: