Reciprocal Rank Fusion : améliorer son RAG
Le RRF est une technique de fusion de classements qui permet d'agréger les résultats de plusieurs systèmes de recherche en un classement unique et cohérent. Son principe est élégant : plutôt que de manipuler des scores bruts difficilement comparables entre systèmes, il s'appuie uniquement sur les rangs des documents dans chaque liste de résultats. Cette approche simple mais efficace s'est imposée comme une référence dans les architectures RAG modernes.

La qualité d'un système RAG repose en grande partie sur sa capacité à récupérer les documents les plus pertinents pour répondre à une question. Or, dans la pratique, un seul algorithme de recherche montre rapidement ses limites : la recherche sémantique excelle pour capturer le sens global d'une requête, tandis que la recherche lexicale (BM25) brille lorsqu'il s'agit de retrouver des termes précis ou des noms propres. Comment combiner le meilleur des deux mondes ? C'est précisément ce que permet le Reciprocal Rank Fusion (RRF).
Le RRF est une technique de fusion de classements qui permet d'agréger les résultats de plusieurs systèmes de recherche en un classement unique et cohérent. Son principe est élégant : plutôt que de manipuler des scores bruts difficilement comparables entre systèmes, il s'appuie uniquement sur les rangs des documents dans chaque liste de résultats. Cette approche simple mais efficace s'est imposée comme une référence dans les architectures RAG modernes.
Dans cet article, nous allons explorer le fonctionnement du Reciprocal Rank Fusion, comprendre pourquoi il surpasse les approches naïves de fusion, et découvrir comment l'implémenter concrètement pour améliorer significativement la qualité de vos systèmes RAG.
Le problème de la recherche hybride
Les systèmes RAG performants s'appuient généralement sur plusieurs méthodes de recherche complémentaires. La recherche dense (ou sémantique) utilise des embeddings vectoriels pour capturer la similarité de sens entre la requête et les documents. La recherche sparse (typiquement BM25) s'appuie sur la correspondance lexicale et excelle pour les requêtes contenant des termes techniques, des acronymes ou des entités nommées.
Chaque approche a ses forces et ses faiblesses :
- Recherche sémantique : comprend les paraphrases et le contexte, mais peut manquer des correspondances exactes importantes
- Recherche lexicale (BM25) : précise sur les termes exacts, mais insensible aux synonymes et au sens global
- Recherche par mots-clés : rapide et interprétable, mais limitée en compréhension contextuelle
L'idée naturelle est de combiner ces approches dans une recherche hybride. Mais comment fusionner des listes de résultats provenant de systèmes qui utilisent des métriques de score complètement différentes ? Un score cosine de 0.85 en recherche vectorielle n'a aucune équivalence directe avec un score BM25 de 12.3.
| Approche de fusion | Principe | Problème |
|---|---|---|
| Moyenne des scores | Combiner les scores bruts | Échelles incompatibles |
| Normalisation min-max | Ramener les scores entre 0 et 1 | Sensible aux outliers |
| Normalisation Z-score | Standardiser par écart-type | Hypothèses de distribution |
| Reciprocal Rank Fusion | Utiliser uniquement les rangs | Aucun — robuste et simple |
Les tentatives de normalisation des scores se heurtent à des difficultés fondamentales : les distributions de scores varient selon les requêtes, les collections de documents, et même au fil du temps. Le RRF contourne élégamment ce problème en ignorant complètement les scores pour ne considérer que la position des documents dans chaque classement.
Comment fonctionne le Reciprocal Rank Fusion
Le Reciprocal Rank Fusion repose sur une formule remarquablement simple. Pour chaque document, on calcule un score agrégé en sommant l'inverse de son rang dans chaque liste de résultats, avec une constante d'amortissement :
RRF_score(d) = Σ 1 / (k + rang(d))
Où k est une constante (généralement fixée à 60) et rang(d) représente la position du document dans une liste donnée. Si un document n'apparaît pas dans une liste, il n'y contribue simplement pas au score.

Prenons un exemple concret. Imaginons trois documents (A, B, C) classés par deux systèmes :
- Recherche sémantique : A (rang 1), C (rang 2), B (rang 3)
- Recherche BM25 : B (rang 1), A (rang 2), C (rang 3)
Avec k = 60, les scores RRF sont :
- Document A : 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325
- Document B : 1/(60+3) + 1/(60+1) = 0.0159 + 0.0164 = 0.0323
- Document C : 1/(60+2) + 1/(60+3) = 0.0161 + 0.0159 = 0.0320
Le document A, bien classé par les deux systèmes, arrive en tête du classement fusionné.
Cette approche présente plusieurs propriétés intéressantes :
- Robustesse aux outliers : un document classé premier par un seul système ne domine pas automatiquement le classement final
- Équité entre systèmes : chaque système contribue de manière égale, sans nécessiter de pondération manuelle
- Gestion naturelle des documents manquants : un document absent d'une liste n'est pas pénalisé artificiellement
- Invariance aux transformations de scores : seuls les rangs comptent, pas les valeurs absolues
Le paramètre k contrôle l'importance relative des premiers rangs par rapport aux rangs plus bas. Une valeur élevée (comme 60) lisse les différences entre positions proches, tandis qu'une valeur faible accentuerait l'avantage des documents en tête de liste.
À découvrir : notre formation LLM Engineering
Implémentation pratique dans un pipeline RAG
L'intégration du RRF dans un système RAG est relativement directe. Voici une implémentation Python qui illustre le concept :
from collections import defaultdict
def reciprocal_rank_fusion(ranked_lists: list[list[str]], k: int = 60) -> list[tuple[str, float]]:
"""
Fusionne plusieurs listes de documents classés en utilisant RRF.
Args:
ranked_lists: Liste de listes de document IDs, ordonnés par pertinence
k: Constante d'amortissement (défaut: 60)
Returns:
Liste de tuples (doc_id, score_rrf) triés par score décroissant
"""
rrf_scores = defaultdict(float)
for ranked_list in ranked_lists:
for rank, doc_id in enumerate(ranked_list, start=1):
rrf_scores[doc_id] += 1 / (k + rank)
# Trier par score décroissant
sorted_docs = sorted(rrf_scores.items(), key=lambda x: x[1], reverse=True)
return sorted_docs
python
Dans un pipeline RAG complet, l'utilisation ressemble à ceci :
def hybrid_search(query: str, top_k: int = 10) -> list[Document]:
# Recherche sémantique avec embeddings
semantic_results = vector_store.similarity_search(query, k=top_k * 2)
semantic_ids = [doc.id for doc in semantic_results]
# Recherche lexicale avec BM25
bm25_results = bm25_index.search(query, k=top_k * 2)
bm25_ids = [doc.id for doc in bm25_results]
# Fusion RRF
fused_ranking = reciprocal_rank_fusion([semantic_ids, bm25_ids])
# Récupérer les top_k documents fusionnés
top_doc_ids = [doc_id for doc_id, score in fused_ranking[:top_k]]
return [document_store.get(doc_id) for doc_id in top_doc_ids]
python
De nombreux frameworks intègrent déjà le RRF. Avec LangChain, l'EnsembleRetriever propose cette fonctionnalité nativement :
from langchain.retrievers import EnsembleRetriever
ensemble_retriever = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.5, 0.5] # Pondération optionnelle
)
docs = ensemble_retriever.invoke("Ma requête")
python
Les bases de données vectorielles comme Elasticsearch, Weaviate ou Qdrant proposent également des implémentations natives de recherche hybride utilisant le RRF, permettant d'exécuter la fusion directement côté serveur pour de meilleures performances.
| Framework / Outil | Support RRF | Particularité |
|---|---|---|
| LangChain | EnsembleRetriever | Pondération configurable |
| LlamaIndex | QueryFusionRetriever | Intégré au pipeline de query |
| Elasticsearch | RRF dans search API | Fusion côté serveur |
| Weaviate | Hybrid search | BM25 + vectoriel natif |
| Qdrant | Query API fusion | Configurable par requête |
Bonnes pratiques et optimisations
L'efficacité du RRF dans votre système RAG dépend de plusieurs facteurs qu'il convient d'optimiser selon votre cas d'usage.
Choisir les bons systèmes à fusionner est primordial. Le RRF fonctionne d'autant mieux que les systèmes combinés sont complémentaires. Fusionner deux recherches sémantiques utilisant des modèles d'embeddings similaires apportera peu de valeur. En revanche, combiner recherche dense, recherche sparse et éventuellement une recherche par métadonnées (date, auteur, catégorie) permet de couvrir différentes dimensions de pertinence.
Ajuster le paramètre k peut affiner les résultats. La valeur standard de 60 fonctionne bien dans la plupart des cas, mais vous pouvez expérimenter :
- k plus bas (20-40) : favorise davantage les documents en tête de liste
- k plus élevé (80-100) : lisse davantage les différences de rang
Évaluer rigoureusement l'amélioration est essentiel. Utilisez des métriques comme le RAGAS pour mesurer l'impact du RRF sur la qualité de récupération (Context Precision, Context Recall) et sur la pertinence des réponses finales. Dans de nombreux benchmarks, le RRF améliore les performances de 5 à 15% par rapport à une recherche unique.
Gérer la latence mérite attention. Exécuter plusieurs recherches en parallèle puis fusionner les résultats ajoute inévitablement de la latence. Pour les applications temps réel, privilégiez les implémentations côté serveur (Elasticsearch, Weaviate) qui optimisent ce processus. Pour du traitement batch, la latence additionnelle est généralement négligeable.
Conclusion
Le Reciprocal Rank Fusion s'est imposé comme une technique incontournable pour quiconque construit des systèmes RAG de qualité. Sa simplicité conceptuelle — ne considérer que les rangs plutôt que les scores — résout élégamment le problème épineux de la fusion de résultats hétérogènes.
En combinant recherche sémantique et recherche lexicale via RRF, vous obtenez un système qui hérite des forces de chaque approche tout en compensant leurs faiblesses respectives. Les requêtes contenant des termes techniques précis bénéficient de la rigueur de BM25, tandis que les questions formulées naturellement profitent de la compréhension contextuelle des embeddings.
L'adoption du RRF est d'autant plus accessible que les principaux frameworks et bases de données vectorielles l'intègrent nativement. Que vous utilisiez LangChain, LlamaIndex, ou une solution comme Elasticsearch, implémenter une recherche hybride avec fusion RRF ne demande que quelques lignes de configuration.
Pour les équipes qui cherchent à améliorer la pertinence de leur RAG sans refondre leur architecture, le RRF représente souvent le meilleur rapport effort/bénéfice. C'est une optimisation qui, une fois en place, améliore systématiquement la qualité des documents récupérés et, par conséquent, la fiabilité des réponses générées par le LLM.


