Avancé 14 minOptimisation

Ajouter un reranker à son pipeline

Les embeddings font de la recherche approximative : rapide, scalable, mais avec du bruit dans les premiers résultats. Un reranker — un cross-encoder plus précis — réordonne les 20 premiers candidats pour en faire remonter 5 vraiment pertinents. +15 à +25 % de recall sur la plupart des corpus. Ce guide explique pourquoi, et comment l'ajouter en 30 lignes.

Par Mohamed Meguedmi·Màj 2026-01-30·Testé sur Windows, macOS, Linux

#Pourquoi un reranker

Un embedding produit un vecteur par document, indépendamment de la question. La distance est symétrique et globale. C'est approximatif par nature — deux passages sur le même sujet général peuvent être proches même si un seul répond vraiment à la question posée.

Un reranker regarde le couple (question, passage) ensemble, comme un humain : "ce passage répond-il à cette question ?". Il est 10-100x plus lent, mais beaucoup plus précis sur ce jugement local.

i
La métaphore
Embedding = bibliothécaire qui vous donne les 20 livres du bon rayon. Reranker = expert qui lit les 20 et classe ceux qui répondent vraiment à votre question précise.

#Comment ça marche

Bi-encoder (embedding)
Encode la question et chaque document séparément. Distance cosinus. Rapide, parallélisable.
Cross-encoder (reranker)
Encode (question || document) ensemble dans un seul passage du transformer. Sort un score de pertinence. Précis, coûteux.

On combine les deux : embedding pour récupérer 20-50 candidats plausibles parmi des millions, reranker pour affiner le top 5.

#Modèles 2026

⭐ BAAI/bge-reranker-v2-m3
Multilingue, excellent français. 560 Mo. Le choix par défaut.
BAAI/bge-reranker-v2-gemma
Plus gros (2 Go) et plus précis pour des cas exigeants. Attention VRAM.
mixedbread-ai/mxbai-rerank-large-v1
Apache 2.0, bon en EN, décent en FR. Alternative si licence bge ne convient pas.
cohere/rerank-multilingual-v3.0
Cloud uniquement, excellent. Non applicable pour 100 % local.

#La nouvelle pipeline

Avant / après
AVANT :
  Question → Embedding → ChromaDB (top-5) → LLM

APRÈS :
  Question → Embedding → ChromaDB (top-20)
                      → Reranker (top-5) → LLM

On récupère large, puis on ordonne finement.

#Implémentation

Avec sentence-transformers
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-v2-m3", max_length=512)

def retrieve_and_rerank(question: str, k_retrieve=20, k_final=5):
    # 1. Récupération via embedding (ChromaDB, Qdrant, etc.)
    candidates = embedding_search(question, top_k=k_retrieve)
    # candidates = [(text, metadata), ...]

    # 2. Scoring par le cross-encoder
    pairs = [[question, text] for text, _ in candidates]
    scores = reranker.predict(pairs, batch_size=16)

    # 3. Tri par score décroissant, garder les k_final
    ranked = sorted(zip(candidates, scores), key=lambda x: -x[1])
    return [c for c, s in ranked[:k_final]]
Avec LlamaIndex (plus simple)
from llama_index.core.postprocessor import SentenceTransformerRerank

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

query_engine = index.as_query_engine(
    similarity_top_k=20,
    node_postprocessors=[reranker],
)

#Coût et optimisations

Latence
bge-reranker-v2-m3 sur GPU : ~50 ms pour 20 candidats. Sur CPU : 500-800 ms. À prendre en compte pour un chat interactif.
VRAM
~1,2 Go en inférence. Cohabite avec un Mistral 7B sur 8 Go de VRAM sans souci.
Batch size
16-32 est optimal. Au-delà, gains marginaux. En-dessous, latence par couple.
max_length
512 par défaut. Pour des chunks longs (800+ tokens), passez à 1024 ou 2048 — attention à la VRAM.
Skip le reranker sous certains seuils
Si le top-1 embedding a un score cosinus > 0.85, probablement inutile de reranker — c'est déjà très pertinent. Condition sur le score pour économiser la latence.

#Mesurer le gain

Protocole A/B simple : même jeu de 50 questions, mesurer recall@5 avec et sans reranker.

Pseudo-code
recall_sans = evaluer(pipeline_sans_reranker, questions, reponses_cibles)
recall_avec = evaluer(pipeline_avec_reranker, questions, reponses_cibles)

print(f"Sans reranker : {recall_sans:.2%}")
print(f"Avec reranker : {recall_avec:.2%}")
print(f"Gain        : +{(recall_avec - recall_sans) * 100:.1f} points")
!
Gain variable
Sur corpus très propre (wiki structuré), le gain peut être de +5 % seulement. Sur corpus bruité (mails, notes mal structurées), on voit +25 %. Testez sur votre corpus avant de conclure.
Ce guide vous a aidé ?

Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.