[!NOTE] Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.

L’écosystème de classement des recherches en 2026 : BM25, Embeddings, encodeurs croisés, et LLM Reranking

La recherche doit répondre à la fois à l’intention littérale et à l’intention sémantique. Une requête contenant les mots « écouteurs sans fil » doit bien évidemment correspondre à ces termes, mais le classement final peut également dépendre de la qualité du produit, des préférences de l’utilisateur ainsi que de sa disponibilité. Aucune méthode de classement unique ne parvient à gérer efficacement l’ensemble de ces critères.

Cette publication construit la pile étape par étape : la récupération via BM25, le embeddings dense, la fusion par rang réciproque, l’encodage croisé reranking, et enfin le classement par liste LLM. Démonstration fonctionnelle benchmarks à chaque étape du processus de recherche de produits d’Amazon ESCI dataset.

TL;DR : Construisez le système de recherche en étapes mesurées. Commencez par BM25, ajoutez une récupération dense dès qu’elle améliore le taux de rappel pour vos requêtes, ne fusionnez les résultats que si les deux moteurs de récupération présentent des erreurs complémentaires, et réordonnez uniquement l’ensemble des candidats respectant le budget de latence. Dans cette démonstration ESCI de taille ordinateur portable, l’implémentation complète de pipeline a permis d’améliorer le NDCG@10 de 0,585 à 0,717. Ce résultat s’agit d’un exemple concret, et non d’une preuve que chaque stack de production doit intégrer les cinq étapes ou disposer d’un LLM en ligne.


Sélectionner les étapes en fonction du mode de défaillance

La pile de production fonctionne comme un entonnoir, mais le type d’entonnoir approprié dépend de la requête ainsi que de l’interface métier.

Cas d’usageValider
Recherche de produitsBM25 + récupération dense + RRF + encodeur croiséRappel des attributs, substitutions, latence, contraintes métier
Recherche de documentationRecherche hybride + encodage croiséIdentifiants exacts, questions sémantiques, filtres de versionnage
Support de déflectionRecherche hybride + vérification des citationsRécupération et rappel, ancrage, abstention
Marché ou listes d’offresFiltres lexicaux + récupération dense + métier rerankerDisponibilité, fraîcheur, politique, diversité des vendeurs
Petit corpus interneLa ligne de référence BM25, suivie d’un reranker
Recherche juridique ou médicale à haut risqueRecherche axée sur le rappel combinée à une revue par des expertsCouverture, provenance, abstention calibrée

Commencez par utiliser BM25 comme référence de base. Intégrez une récupération dense lorsque le déséquilibre du vocabulaire nuit au taux de rappel. Ajoutez un encodeur croisé lorsque la première page contient les candidats pertinents mais dans le mauvais ordre. N’ajoutez un LLM qu’une fois que vous pouvez supporter la latence et évaluer correctement les décisions de classement.

Comment nous en sommes arrivés là

Il est plus simple de concevoir cette pile comme étant composée de trois couches : la récupération lexicale permet de trouver des termes exacts, la récupération dense comble les lacunes du vocabulaire, et rerankers sert à comparer en détail les candidats les plus pertinents.

BM25 et récupération lexicale

Pendant des décennies, BM25 C’était la valeur par défaut. Il s’agit d’un modèle probabiliste qui évalue les documents en fonction de la fréquence des termes de requête à l’intérieur de ces derniers, normalisée par la longueur du document ainsi que par la fréquence inverse de document (IDF).

BM25 se montre très performant lorsque des termes littéraux reflètent précisément l’intention recherchée : codes d’erreur, références SKU de produits, noms, ainsi que les identifiants API. Sa principale limite réside dans le déséquilibre du vocabulaire. Une requête comme « ordinateur portable pas cher » risque de ne pas retrouver un document décrivant un « notebook économique », si le texte indexé ne propose aucun lien entre ces deux expressions.

Cela dit, BM25 constitue une base solide. Il atteint en moyenne un score de 0,429 pour le nDCG@10 sur l’ensemble des BEIR benchmark’s 18 datasets et Cela reste supérieur à certains modèles neuronaux. dans les tâches de récupération argumentative comme Touche-2020.

Recherche dense et embeddings

Les encodeurs de type BERT ont rendu la retrieval dense praticable. Ils projettent les requêtes et les documents dans un espace vectoriel commun, puis classent les candidats à l’aide d’une fonction de similarité comme la similarité cosinus ou le produit scalaire.

L’architecture du bi-encodeur (ou « deux tours ») traite la requête et le document de manière indépendante à l’aide de tours d’encodage distincts, afin de générer des vecteurs de longueur fixe embeddings. Les vecteurs de documents peuvent être calculés à l’avance et indexés hors ligne, puis récupérés rapidement grâce à des algorithmes d’Approximate Nearest Neighbor (ANN). Ainsi, des termes tels que « ordinateur portable bon marché » et « notebook économique » se retrouvent proches l’un de l’autre dans l’espace vectoriel.

Certains bi-encodeurs emploient une architecture siamoise, comme dans Sentence-BERT, Là où les deux côtés partagent des poids, d’autres architectures emploient des tours de requête et de documents distincts. Le pooling, la taille du vecteur, la fonction de similarité ainsi que l’objectif d’entraînement relèvent de choix de conception du modèle, et non de propriétés inhérentes à tout récupérateur dense.

Ces modèles sont entraînés à l’aide de l’apprentissage contrastif, généralement avec le InfoNCE perte. Pour un lot de paires (requête, document_positif), l’objectif consiste à maximiser cette perte. sim(query, positive_doc) tout en minimisant sim(query, negative_docs). Les négatifs proviennent des positifs d’autres requêtes au sein de la même batch (négatifs intra-batch). Un paramètre de température τ\tau contrôle le degré de netteté de la distribution : des valeurs plus basses incitent le modèle à faire des distinctions plus fines entre les positifs et les négatifs.

Les données d’entraînement ont souvent plus d’importance que la dimension embedding. Les modèles de récupération apprennent à partir de paires requête-document positif ainsi que de négatifs difficiles soigneusement sélectionnés : des documents plausibles mais non pertinents. La section suivante consacrée à l’entraînement montre comment SimANS évite à la fois les négatifs triviaux et les faux négatifs probables.

Le coût principal réside dans le goulot d’étranglement lié à la représentation. Les bi-encodeurs compressent toutes les nuances sémantiques en un vecteur de taille fixe, ce qui entraîne fréquemment une perte des interactions fines entre des termes de requête spécifiques et du contenu de documents particuliers.

Encodeurs croisés et LLMs

Encodificateurs croisés (Nogueira et Cho, 2019) On alimente la requête et le document dans un modèle Transformer en tant que séquence concaténée.[CLS] Query [SEP] Document), de sorte que chaque token de requête peut prendre en compte chaque token de document grâce à une attention autonome complète. Cette interaction approfondie permet de capturer des nuances que l’encodage indépendant manquerait.

LLM reranking fait appel à un modèle piloté pour comparer plusieurs candidats en même temps. RankGPT Il a démontré de très bons résultats zero-shot par liste avec GPT-4 sur les données benchmarks évaluées, mais la stabilité des sorties, le coût computationnel ainsi que l’adaptation au domaine nécessitent encore des tests distincts.

Ces scores ne peuvent pas être calculés à l’avance pour des requêtes arbitraires ; c’est pourquoi reranking est ajouté après la récupération des données. Cette asymétrie de coût est à l’origine de la structure en entonnoir à plusieurs étapes.


Le funil à plusieurs étapes

Exécuter un encodeur croisé coûteux ou LLM sur des millions de documents n’est pas praticable ; c’est pourquoi les architectures de recherche modernes emploient une approche en entonnoir. Chaque étape réduit progressivement l’ensemble des documents candidats, tout en augmentant la complexité du modèle.

Un modèle complexe est trop lent pour évaluer l’ensemble du corpus, tandis qu’un retrouveur peu coûteux manque de précision finale. Le système en entonnoir n’utilise chaque modèle que là où son coût reste raisonnable.

Entonnoir de classement à plusieurs étapes

ÉtapeÉchelle d’entréeObjectif principalMéthodes typiquesMesure de sortie
Recherche de donnéesCorpus ou indexTaux de rappel des candidatsBM25, bi-encodeursRappel au seuil de rejet des candidats
Pré-classementGrand ensemble de candidatsFiltrage bon marchéModèles légers, règlesRappel conservé par milliseconde
Classement completListe de sélectionQualité de premier rangEncodateurs croisés, LLMsNDCG/MRR, latence, coût
MélangeListes finales classées ou emplacements attribuésContraintes et mélangeRègles, classement multi-objectifPolitique, diversité et contraintes métier

La récupération définit la limite supérieure, et reranking l’optimise à l’intérieur de cette limite. Si un document pertinent n’est pas retrouvé lors de la phase de récupération, aucun modèle ultérieur ne pourra le récupérer.


La démonstration : un pipeline en cinq étapes

Afin de concrétiser cela, j’ai développé un stack de tri et de recherche démonstration qui exécute une pipeline en cinq étapes sur le Amazon ESCI Recherche de produits benchmark. Chaque étape est mesurée de manière indépendante, ce qui vous permet de déterminer précisément d’où proviennent les améliorations.

Démonstration de l’architecture Pipeline

Le pipeline :

  1. Recherche sparse BM25 — référence lexicale de base (rank_bm25)
  2. Recherche à l’aide d’un bi-encodeur dense — génération de candidats sémantiques (all-MiniLM-L6-v2)
  3. Fusion hybride RRF — fusion basée sur le rang des résultats dispersés et denses
  4. Encodage croisé reranking — scores de pertinence par paire (ms-marco-MiniLM-L-12-v2)
  5. LLM par liste reranking — comparaison demandée entre la liste finale des candidats (Ollama, API, ou modèle local)

Les étapes 1 à 3 correspondent à l’étape de retrieval du funnel (objectif : maximiser le taux de rappel) ; les étapes 4 à 5 représentent l’étape de full ranking (objectif : maximiser la précision). La démonstration omet les phases de pré-classification et de fusion des résultats. Avec environ 8 500 documents, il est possible d’envoyer directement tous les résultats hybrides à reranking.

Début rapide

git clone https://github.com/slavadubrov/search-ranking-stack.git
cd search-ranking-stack
uv sync

# Download and sample ESCI dataset (~2.5GB download, ~5MB sample)
uv run download-data

# Run the full pipeline (without LLM reranking)
uv run run-all

# Run with LLM reranking via Ollama
uv run run-all --llm-mode ollama

Dataset et échantillonnage : Amazon ESCI

La démonstration utilise les Amazon Shopping Queries Dataset (ESCI) provenant de KDD Cup 2022 — une véritable recherche de produits benchmark dotée d’étiquettes de pertinence graduées en quatre niveaux :

ÉtiquetteGainExemple (Requête : « écouteurs sans fil »)
Exact (E)3Remplit toutes les exigences de la requête.Écouteurs sans fil Sony WH-1000XM5
Remplacer (S)2Alternative fonctionnelleÉcouteurs filaires équipés d’un adaptateur Bluetooth
Complément (C)1Article utile associéÉtui de transport pour écouteurs
Irrelevant (I)0Aucune relation significativeCâble de charge USB

La pertinence graduelle est importante car elle permet d’utiliser le NDCG (Normalized Discounted Cumulative Gain), qui permet de distinguer un classement « parfait » d’un classement « simplement adéquat ». Les métriques binaires traitent les deux de manière équivalente et ne peuvent pas différencier les différents niveaux de pertinence à une même position.

J’ai utilisé la démo. small_version Exemple : environ 500 requêtes, 8 500 produits et 12 000 jugements. Cette base de données est suffisamment petite pour être exécutée sur un ordinateur portable, mais elle reste trop restreinte et trop spécialisée dans un domaine donné pour permettre l’établissement d’un système de classement en environnement de production. Elle peut servir à reproduire les différentes étapes du processus et à analyser les modes de défaillance ; des requêtes représentatives, mises de côté à des fins de test, doivent être utilisées pour prendre des décisions relatives au déploiement.


Recherche de récupération : recherche hybride

La tâche de la couche de récupération est d’optimiser le taux de rappel : il s’agit de déployer le plus large filet possible afin qu’aucun élément pertinent ne puisse échapper.

BM25 : la référence lexicale de base

BM25 évalue les documents en fonction du chevauchement des termes avec la requête, en appliquant une saturation de la fréquence des termes ainsi qu’une normalisation de la longueur du document :

BM25(q,d)=tqIDF(t)tf(t,d)(k1+1)tf(t,d)+k1(1b+bd/avgdl)\text{BM25}(q, d) = \sum_{t \in q} \text{IDF}(t) \cdot \frac{tf(t,d) \cdot (k_1 + 1)}{tf(t,d) + k_1 \cdot (1 - b + b \cdot |d|/\text{avgdl})}

IDF(t)\text{IDF}(t) est la fréquence inverse de document du terme tt ; tf(t,d)tf(t,d) représente la fréquence du terme dans le document dd.|d|LL représente la longueur d’un document, tandis que avgdl\text{avgdl} désigne la longueur moyenne des documents dans le corpus. Deux paramètres sont particulièrement importants : k1k_1 (généralement compris entre 1,2 et 2,0) permet de réguler la saturation du TF — c’est‑à‑dire la vitesse à laquelle les termes répétés cessent d’apporter de la valeur — et bb (généralement égal à 0,75) contrôle la normalisation de la longueur des documents.

L’implémentation est concise. Il s’agit simplement de tokenisation des espaces blancs. rank_bm25:

# src/search_ranking_stack/stages/s01_bm25.py

from rank_bm25 import BM25Okapi

def run_bm25(data: ESCIData, top_k: int = 100):
    doc_ids = list(data.corpus.keys())
    tokenized_corpus = [text.lower().split() for text in data.corpus.values()]

    bm25 = BM25Okapi(tokenized_corpus)

    results = {}
    for query_id, query_text in data.queries.items():
        scores = bm25.get_scores(query_text.lower().split())
        top_indices = np.argsort(scores)[::-1][:top_k]
        results[query_id] = {doc_ids[idx]: float(scores[idx]) for idx in top_indices}

    return results

Le BM25 atteint un Recall@100 de 0,741 — 74 % des produits pertinents apparaissent dans le top 100. Ce n’est pas mal pour une méthode purement lexicale, mais 26 % des éléments pertinents restent invisibles à toutes les étapes ultérieures du traitement.

Recherche à l’aide d’un bi-encodeur dense

Le bi-encodeur projette de manière indépendante les requêtes et les documents dans un espace commun embedding :

# src/search_ranking_stack/stages/s02_dense.py

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

# Encode corpus once, cache to disk
corpus_embeddings = model.encode(
    doc_texts,
    batch_size=128,
    normalize_embeddings=True,  # Cosine sim = dot product
    convert_to_numpy=True,
)

# At query time: encode query, compute dot product
query_embeddings = model.encode(query_texts, normalize_embeddings=True)
similarity_matrix = np.dot(query_embeddings, corpus_embeddings.T)

Avec un embeddings normalisé, la similarité cosinus se réduit à un produit scalaire. La démonstration calcule la matrice complète « requête par corpus », car 8 500 documents tiennent aisément en mémoire ; un corpus en environnement de production utiliserait normalement un index de plus proche voisin approximatif. Dans cet exemple, all-MiniLM-L6-v2 Augmente le Recall@100 de 0,741 à 0,825.

Comment les bi-encodeurs apprennent de bonnes représentations

L’entraînement des bi-encodeurs s’effectue généralement en deux phases. Tout d’abord, le modèle est pré-entraîné sur l’inférence en langage naturel (NLI) et la similarité textuelle sémantique (STS) datasets, qui lui permettent d’acquérir une compréhension sémantique polyvalente — le modèle apprend ainsi que les phrases « un chat est assis sur un tapis » et « un félin se repose sur un tapis » doivent présenter des embeddings similaires. Ensuite, il est affiné à l’aide de données spécifiques à la récupération d’informations telles que MS MARCO, ce qui lui fait comprendre qu’une requête de recherche et son passage pertinent doivent être plus proches l’un de l’autre que la requête et les passages irrelevants.

L’élément clé de la deuxième phase est l’extraction de négatifs fermes. Les négatifs aléatoires (par exemple, un document sur la cuisine associé à une requête concernant des écouteurs) sont extrêmement faciles à distinguer — le modèle n’apprend rien d’eux. À la place, on utilise le modèle actuel lui-même pour identifier des documents qu’il classe en haute position mais qui ne sont en réalité pas pertinents.

Le SimANS L’approche du (Simple Ambiguous Negatives Sampling) formalise ce processus : on classe tous les documents à l’aide du bi-encodeur actuel, puis on exclut les négatifs faciles (classés trop bas – le modèle s’en occupe déjà) ainsi que les faux négatifs potentiels (classés trop haut – ils pourraient en réalité être pertinents mais non étiquetés). Le « milieu difficile » permet ainsi d’obtenir le signal d’apprentissage maximal.

# What a training triplet looks like after hard negative mining
training_triplet = {
    "query": "wireless noise canceling headphones",
    "positive": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones",
    "negative": "Sony headphone replacement ear pads",  # Hard negative: same brand, related product, but wrong intent
}
# The bi-encoder must learn that "ear pads" is NOT what the user wants,
# even though it shares many tokens with the positive document.

La fonction de perte contrastive (InfoNCE) relie ces éléments entre eux. Pour chaque requête qq associée à un document positif d+d^+ ainsi qu’à un ensemble de documents négatifs {d1,,dn}\{d^-_1, \ldots, d^-_n\} :

L=logesim(q,d+)/τesim(q,d+)/τ+i=1nesim(q,di)/τ\mathcal{L} = -\log \frac{e^{\text{sim}(q, d^+) / \tau}}{e^{\text{sim}(q, d^+) / \tau} + \sum_{i=1}^{n} e^{\text{sim}(q, d^-_i) / \tau}}

sim(q,d)\text{sim}(q, d) représente la similarité cosinus entre la requête et le document embeddings, et τ\tau est le paramètre de température (généralement compris entre 0,05 et 0,1) qui détermine la raideur de la distribution — des valeurs plus basses rendent la perte plus sensible aux négatifs marqués. Il s’agit essentiellement d’un entropie croisée softmax: Augmenter la similarité du couple positif par rapport à tous les négatifs. Lorsque τ\tau est faible, même de légères différences de similarité génèrent des gradients importants, ce qui pousse le modèle à faire des distinctions plus fines.

Entraînement du bi-encodeur Pipeline

Serving bi-encodeur embeddings à grande échelle

L’avantage architectural d’un bi-encodeur réside dans la séparation offline/online. Les documents embeddings sont calculés au moment de l’indexation et stockés dans un index vectoriel. Lors de la requête, le système encode cette dernière puis effectue une recherche parmi ces vecteurs stockés. La latence dépend de l’encodeur, du matériel, de l’index, des filtres ainsi que de l’objectif de rappel ; il est donc nécessaire d’analyser en détail chacune de ces deux étapes séparément.

Dans la démonstration, les calculs sont modérés : 8 500 documents × 384 dimensions × 4 octets par nombre flottant = environ 13 MB d’embeddings. À l’échelle de production, ces valeurs deviennent bien plus importantes : 1 milliard de documents avec des embeddings de 768 dimensions nécessitent environ 3 TiB d’espace de stockage. C’est là que la quantification (la compression des nombres flottants de 32 bits en entiers de 8 bits) devient essentielle. quantification de produit (décomposition des vecteurs en sous-espace), ainsi que des index basés sur SSD comme DiskANN Entrez. Le Section de l’indexation par vecteurs denses couvre les algorithmes d’indexation.

Bi-encodeur Serving Pipeline

Pourquoi tester la récupération hybride

Les deux méthodes échouent souvent de manière différente. BM25 convient particulièrement bien aux noms propres, aux références de produits et aux codes d’erreur. La récupération dense permet de surmonter les incohérences lexicales, comme dans le cas de « cheap laptop » par rapport à « budget notebook computer ». L’utilité de la fusion dépend de la fréquence à laquelle de tels cas complémentaires apparaissent dans l’ensemble des requêtes cibles.

Une expérience courante suivante consiste en une recherche hybride : on exécute les deux méthodes de récupération, puis on fusionne leurs listes classées.

Fusion de rangs réciproques (FRR)

BM25 et la récupération dense génèrent des scores ayant des significations et des échelles distinctes. Une combinaison linéaire nécessite donc une calibration et une validation chaque fois que les moteurs de récupération ou le corpus changent.

Recherche hybride à RRF

Fusion de rangs réciproques (Cormack et al., 2009) élimine complètement les scores bruts et ne prend en compte que la position dans le classement :

RRF(d)=rRankings1k+rank(d,r)\text{RRF}(d) = \sum_{r \in \text{Rankings}} \frac{1}{k + \text{rank}(d, r)}

Ici, kk est une constante d’aplanissement ; 60 constitue une valeur de départ courante. Le RRF récompense les éléments qui occupent des positions élevées dans les listes d’entrée, sans comparer leurs scores bruts. Il évite ainsi la calibration de l’échelle des scores, mais les seuils de récupération, les poids et kk nécessitent néanmoins une évaluation.

La mise en œuvre :

# src/search_ranking_stack/stages/s03_hybrid_rrf.py

def reciprocal_rank_fusion(ranked_lists, k=60, top_k=100):
    fused_results = {}

    for query_id in all_query_ids:
        rrf_scores = defaultdict(float)

        for results in ranked_lists:
            sorted_docs = sorted(results[query_id].items(),
                                 key=lambda x: x[1], reverse=True)

            for rank, (doc_id, _score) in enumerate(sorted_docs, start=1):
                rrf_scores[doc_id] += 1.0 / (k + rank)

        sorted_rrf = sorted(rrf_scores.items(),
                            key=lambda x: x[1], reverse=True)[:top_k]
        fused_results[query_id] = dict(sorted_rrf)

    return fused_results

Le RRF hybride atteint un Recall@100 de 0,842 ainsi qu’un NDCG@10 de 0,628 — surpassant ainsi à lui seul les méthodes BM25 (0,585) et Dense (0,611). Il suffit que les documents obtiennent de bons résultats dans une seule méthode pour survivre à la fusion.


Encodage croisé reranking

Avec 100 candidats hybrides par requête, vous pouvez vous permettre d’utiliser un modèle plus coûteux. Le cross-encodeur traite la requête et le document ensemble au sein d’un seul Transformer, en assurant une attention croisée complète entre tous les tokens.

Encodage binaire vs. encodage croisé

Interaction au niveau des tokens

La véritable différence réside dans la matrice d’attention. Dans un bi-encodeur, l’attention est en forme de diagonale bloquée : les tokens de requête ne prêtent attention qu’aux autres tokens de requête, et les tokens de document ne prêtent attention qu’aux autres tokens de document. Les deux représentations ne se rencontrent jamais au niveau des tokens — elles ne s’intersectent que finalement par le biais d’un produit scalaire. Un cross-encodeur calcule la matrice d’attention complète, où chaque token de requête prête attention à chaque token de document, et inversement. C’est cette attention croisée qui permet des interactions profondes au niveau des tokens.

Architecture d’attention du Cross-Encoder

Dans un bi-encodeur, la requête « apple » est encodée avant même que tout document ne soit pris en compte. Un cross-encodeur, quant à lui, prend en charge à la fois la requête et les documents candidats, ce qui lui permet d’exploiter leur relation au niveau des tokens. Cela peut être utile dans des cas tels que :

L’entrée du cross-encoder est formatée comme [CLS] query tokens [SEP] document tokens [SEP]. [CLS] il s’agit d’un token de classification dont l’état caché final est alimenté via une tête linéaire afin de générer un unique score de pertinence. Le segment embeddings permet de distinguer les tokens de requête des tokens de document, et [SEP] marque la frontière entre les segments.

Comment les cross-encodeurs sont entraînés

Les encodeurs croisés peuvent apprendre à partir de (query, document, relevance_label) Exemples d’objectifs de type pointwise, pairwise ou listwise. L’exemple pointwise présenté ci-dessous fait usage d’une seule étiquette de pertinence ; il ne s’agit pas du seul schéma d’entraînement possible.

# Cross-encoder training data format
training_example = {
    "query": "wireless headphones",
    "document": "Sony WH-1000XM5 Wireless Headphones",
    "label": 1.0,  # Relevant
}
# Forward pass: [CLS] hidden state → Linear layer → sigmoid → score
# Loss: binary cross-entropy between predicted score and label

Un classifieur courant applique une transformation aux résultats finaux [CLS] Conversion en score. Les étiquettes binaires peuvent faire l’objet d’une entropie croisée binaire ; la pertinence graduée peut quant à elle être traitée par des pertes de régression, ordinales, par paires ou globales. Il convient de choisir la méthode en se basant sur des métriques de classement testées indépendamment, plutôt que d’affirmer a priori qu’un objectif est universellement supérieur aux autres.

L’exploitation des négatifs durs revêt une importance encore plus grande pour les encodeurs croisés. plutôt que pour les bi-encodeurs. Les cross-encodeurs sont coûteux à entraîner — chaque exemple d’entraînement nécessite un passage complet en avant à travers la séquence concaténée — ce qui fait qu’il est impossible de gaspiller des ressources de calcul sur des exemples négatifs extrêmement faciles à traiter. La solution pratique consiste à utiliser un bi-encodeur pour récupérer les K meilleurs candidats pour chaque requête d’entraînement, puis à sélectionner des négatifs difficiles provenant de plages de classement spécifiques (par exemple, les rangs de 10 à 100). Cela fournit aux cross-encodeurs des exemples où distinguer ce qui est pertinent de ce qui ne l’est pas exige réellement une interaction approfondie entre les tokens.

# src/search_ranking_stack/stages/s04_cross_encoder.py

from sentence_transformers import CrossEncoder

model = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")

def run_cross_encoder(data, hybrid_results, top_k_rerank=50):
    for query_id, query_text in data.queries.items():
        candidates = list(hybrid_results[query_id].items())[:top_k_rerank]

        # Form (query, document) pairs for joint encoding
        pairs = []
        doc_ids = []
        for doc_id, _ in candidates:
            doc_text = data.corpus.get(doc_id, "")[:2048]
            pairs.append([query_text, doc_text])
            doc_ids.append(doc_id)

        # Score all pairs with full cross-attention
        scores = model.predict(pairs, batch_size=64)

        # Rerank by cross-encoder score
        scored_docs = sorted(zip(doc_ids, scores),
                             key=lambda x: x[1], reverse=True)
        reranked_results[query_id] = {
            doc_id: float(score) for doc_id, score in scored_docs
        }

Dans l’exécution de la démonstration enregistrée, ms-marco-MiniLM-L-12-v2 Il réordonne 50 candidats par requête et améliore le NDCG@10 de 0,628 à 0,645. Il convient d’évaluer sa latence sur l’hardware de déploiement, car le modèle, la longueur des séquences, la taille des lots ainsi que runtime influencent tous les résultats.

Le compromis vitesse/qualité

Pourquoi ne pas utiliser des cross-encoders pour tout ? Parce que la pré-computation est impossible. Les bi-encodeurs de documents embeddings sont indépendants de la requête, ce qui permet de les calculer une seule fois puis de les stocker. En revanche, la sortie d’un cross-encoder dépend à la fois de la requête et du document. Le score de pertinence pour des « écouteurs sans fil » associés à un produit Sony provient de l’attention croisée complète entre ces tokens spécifiques. Il n’est donc pas possible de le mettre en cache ou de le réutiliser pour une autre requête.

Un bi-encodeur nécessite une encodage de la requête ainsi qu’une recherche vectorielle sur des documents précalculés embeddings. Un cross-encodeur évalue chaque paire requête-document figurant dans la liste restreinte, le coût d’évaluation augmentant à la fois avec le nombre de candidats et la longueur de la séquence. Le regroupement en lots peut aider, mais évaluer 100 000 candidats reste un point de fonctionnement inadapté ; il convient d’abord de récupérer les données et benchmark de sélectionner la liste restreinte la plus grande répondant aux critères de qualité et de latence.

La règle confirmée par la démonstration est la suivante : le taux de rappel @100 reste constant à 0,842 au cours des deux étapes reranking. Reranking peut réorganiser les résultats, mais il ne permet jamais d’ajouter de nouveaux documents ; c’est le mécanisme de récupération qui fixe ce plafond maximal.


LLM par liste reranking

La phase de démonstration finale fait appel à un LLM pour effectuer des reranking par liste. Au lieu d’évaluer chaque document de manière indépendante, le modèle prend en compte les 10 meilleurs résultats et restitue un ordre correspondant. Inspiré de RankGPT, Le prompt rend explicite la comparaison relative, mais il entraîne également des limites liées au contexte, un biais de position, des échecs de parsing ainsi qu’une variabilité d’un exécution à l’autre.

LLM Reranking Approches

La liste prompt

Le modèle prompt demande au LLM d’examiner la hiérarchie de pertinence ESCI :

# src/search_ranking_stack/stages/s05_llm_rerank.py

def _create_listwise_prompt(query, documents, max_words=200):
    n = len(documents)

    doc_texts = []
    for i, (doc_id, doc_text) in enumerate(documents, start=1):
        words = doc_text.split()[:max_words]
        doc_texts.append(f"[{i}] {' '.join(words)}")

    return (
        f"I will provide you with {n} product listings, each indicated by "
        f"a numerical identifier [1] to [{n}]. Rank the products based on "
        f'their relevance to the search query: "{query}"\n\n'
        "Consider:\n"
        "- Exact matches should rank highest\n"
        "- Substitutes should rank above complements\n"
        "- Irrelevant products should rank lowest\n\n"
        f"{chr(10).join(doc_texts)}\n\n"
        "Output ONLY a comma-separated list of identifiers: [3], [1], [2], ...\n"
        "Do not explain your reasoning."
    )

Trois modes d’exécution

La démonstration prend en charge trois backends pour LLM reranking :

ModeModèleComment il fonctionne
ollamallama3.2:3b (configurable)Local via Ollama API
apiclaude-haiku-4-5-20251001Anthropic API
localQwen/Qwen2.5-1.5B-InstructHuggingFace Transformers

Analyse et mécanisme de fallback

Les sorties LLM ne garantissent pas de respecter le schéma demandé ; par conséquent, le parsing ainsi qu’une solution de secours sont essentiels :

def _parse_ranking(output: str, n: int) -> list[int] | None:
    """Parse LLM output to extract ranking order."""
    matches = re.findall(r"\[(\d+)\]", output)

    if not matches:
        return None

    positions = [int(m) - 1 for m in matches]

    # Pad with remaining positions if LLM returned partial output
    if len(positions) < n:
        seen = set(positions)
        for i in range(n):
            if i not in seen:
                positions.append(i)

    return positions[:n]

Lorsque le parsing échoue complètement, la démonstration recourt à l’ordre de traitement du cross-encoder. Un parseur en environnement de production doit également rejeter les identifiants hors plage ou dupliqués, ajouter les candidats manquants dans leur ordre précédent, enregistrer l’échec, et comparer le taux d’utilisation de ce mécanisme de fallback à une valeur seuil prédéfinie.


Résultats de cet échantillon ESCI

Voici les résultats obtenus en exécutant le pipeline complet sur environ 500 requêtes ESCI :

Pipeline Résultats

ÉtapeNDCG@10MRR@10Rappel@100Delta NDCG
BM250.5850.8120.741
Bi-encodeur dense0.6110.8080.825+0.026
Hybride (RRF)0.6280.8340.842+0.017
+ Encodage croisé0.6450.8600.842+0.017
+ LLM Reranker0.7170.9010.842+0.072

Observations clés

La recherche hybride surpasse chacune des méthodes utilisées séparément. Le score RRF NDCG (0.628) est supérieur à celui de BM25 (0.585) ainsi qu’à celui de la méthode Dense (0.611). La récupération sparse et la récupération dense présentent des modes de défaillance complémentaires ; en les combinant, il est possible de retrouver des documents qui seraient manqués si l’on ne s’appuyait que sur l’une d’elles.

Le taux de rappel est déterminé au niveau de la récupération des données. Le taux de rappel@100 reste stable à 0,842 tout au long des deux étapes reranking. Lors du réordonnancement Rerankers, aucun document n’est ajouté. Si vous souhaitez un taux de rappel plus élevé, il faut corriger le niveau de récupération.

Le LLM sollicité génère la plus grande augmentation mesurée au cours de cette exécution. Le score NDCG@10 augmente de 0,072 après l’étape du LLM. Comme le prompt intègre la hiérarchie de pertinence ESCI, ce résultat permet d’évaluer la combinaison modèle-prompt-dataset. Avant de pouvoir attribuer cette amélioration à un reranker globalement supérieur, il est nécessaire de réaliser des exécutions répétées, de déterminer les intervalles de confiance, de mesurer la latence et le coût, ainsi que d’examiner un ensemble de données non utilisé lors de l’entraînement.

La récupération dense surpasse BM25 sur cet échantillon. Il convient d’examiner les tronçons de requête avant d’en déterminer la cause. Une inadéquation du vocabulaire constitue un facteur plausible, mais la structure de l’échantillon, le tokeniseur, le domaine d’entraînement du modèle ainsi que les champs du corpus influencent également cette comparaison.


Évaluation : mesurer ce qui compte

La démonstration utilise trois métriques complémentaires. Chacune d’elles analyse le classement sous un angle différent :

NDCG@10 (métrique principale)

Gain cumulé déprécié normalisé permet d’évaluer la qualité du classement des 10 meilleurs résultats en s’appuyant sur une mesure de pertinence graduelle. Il récompense le fait de placer des documents hautement pertinents près du sommet grâce à une dépréciation logarithmique :

DCG@k=i=1k2reli1log2(i+1)NDCG@k=DCG@kIDCG@k\text{DCG@k} = \sum_{i=1}^{k} \frac{2^{rel_i} - 1}{\log_2(i + 1)} \qquad \text{NDCG@k} = \frac{\text{DCG@k}}{\text{IDCG@k}}

Le NDCG est la seule métrique qui exploite pleinement la hiérarchie à quatre niveaux de pertinence définie par ESCI — un système où une correspondance exacte placée au niveau 1 obtient un score supérieur à celle où un terme substitut occupe cette même position. C’est pourquoi il constitue la métrique principale pour évaluer la qualité globale des recherches.

MRR@10 (premier résultat pertinent)

Le rang réciproque moyen prend en compte la position du premier résultat considéré comme pertinent. Si celui‑ci se trouve à la position 1, le rang réciproque est égal à 1,0 ; s’il se trouve à la position 3, il vaut 0,333. Pour les labels gradués tels que ESCI, il convient de préciser le seuil de pertinence utilisé pour transformer ces grades en une décision binaire.

Recall@100 (couverture de récupération)

Le taux de rappel indique quelle fraction des documents jugés pertinents figurent parmi les 100 premiers résultats. Il s’agit d’une métrique de plafond pour les jugements évalués : un reranker ne peut pas ajouter de document que la récupération a omis, tandis que des jugements incomplets peuvent rendre ce plafond apparent incertain.


Indexation des vecteurs denses au-delà de la démonstration

Les méthodes de type embeddings denses ne deviennent utiles qu’à grande échelle, une fois qu’on dispose d’un index de Proche voisin approximatif (ANN). La démonstration fait appel à une comparaison de similarité cosinus par force brute (ce qui est suffisant pour environ 8 500 documents), mais les systèmes en production exigent des index spécialisés.

HNSW (petit monde hiérarchique navigable)

HNSW M contrôle la connectivité du graphe, tandis que efSearch Il privilégie la précision au détriment du rappel. Les valeurs optimales dépendent de la dimension, de la distribution des distances, des filtres, de l’implémentation ainsi que du niveau de rappel souhaité.

Les mises à jour et les suppressions constituent une considération opérationnelle, car les index de graphe peuvent conserver des tombstones ou nécessiter des réparations en arrière-plan. Le comportement varie en fonction de la base de données. A Problème avec Qdrant, Par exemple, les rapports indiquent une dégradation de la qualité suite à un travail de charge caractérisé par des suppressions massives de données. Il convient de reproduire le schéma de désabonnement cible et d’inclure dans l’évaluation le comportement de compactage ou de réconstruction.

IVF (fichier inversé)

Les index IVF partitionnent l’espace vectoriel en clusters, puis effectuent un balayage du nprobe les clusters les plus proches de la requête. Ils permettent d’obtenir un bon équilibre entre la mémoire utilisée, le temps de construction et le taux de rappel, en particulier lorsqu’ils sont associés à une compression. La sémantique des mises à jour ainsi que les performances dépendent de l’implémentation, et non uniquement du type d’index.

Pour des échelles extrêmes, IVF_RaBitQ (Gao & Long, SIGMOD 2024) permet de compresser des vecteurs à virgule flottante en représentations à un seul bit. Dans un espace à haute dimension, le signe (+/-) d’une coordonnée contient suffisamment d’information angulaire pour effectuer des calculs de similarité.

DimensionHNSW grapheClusters IVF
Contrôle de requêteefSearchnprobe
Contrôle de constructionConnectivité et poutre de constructionNombre de clusters et échantillons d’entraînement
Profil de mémoireArêtes de graphe et vecteursCentroïdes, listes et vecteurs stockés
Comportement de mise à jourRéparation/nettoyage spécifique à la base de donnéesMaintenance de la liste spécifique à la base de données
Évaluer avecCourbe de dégradation mémoire liée au délai de rappelCourbe de dégradation mémoire-retard de rappel

Dans un Étude de cas : recherche de livraison Uber, La réduction d’un paramètre de recherche au niveau du shard, de 1 200 à 200, a permis de diminuer la latence mesurée de 34 % ainsi que CPU de 17 %, avec une perte quasi nulle en taux de rappel. La leçon à retenir est qu’il convient d’ajuster la courbe coût-rappel sur des flux similaires à ceux en production, plutôt que de copier simplement la valeur 200.


Extensions optionnelles après le noyau pipeline

Lorsque la récupération des données et reranking disposent de métriques distinctes, il devient plus aisé d’évaluer diverses extensions sans altérer le fonctionnement fondamental de pipeline.

Compréhension de la requête

L’expansion et la réécriture des requêtes permettent de corriger les incohérences de vocabulaire avant la récupération des données. Query2doc Il a généré des pseudo-documents et rapporté des améliorations obtenues grâce au score BM25 lors de ses expériences sur MS MARCO. L’expansion peut également introduire une intention erronée ; il est donc nécessaire de comparer le taux de rappel et la précision pour les ensembles de requêtes ambigües, de navigation ainsi que celles impliquant des identifiants précis.

Modèles pratiques : expansion des abréviations, enrichissement des entités, décomposition des sous-queries pour le raisonnement multi-niveaux, et RAG - Fusion — génération de plusieurs variantes de requête et combinaison des résultats au moyen de RRF.

LLM-étiquetage de pertinence assisté

LLMs peut générer des étiquettes de pertinence lorsque les jugements humains sont rares. TALEC et Le travail de mise en étiquette de la pertinence sur Pinterest Fournissez deux conceptions ayant fait l’objet d’évaluation. Une étiquette LLM représente toujours une sortie du modèle : il convient donc de la calibrer à l’aide de jugements humains non avertis, d’examiner les zones de désaccord, et de conserver un ensemble de référence humain pour les tests de régression.

Parmi les contrôles utiles, on trouve :

Distillation des connaissances

Lorsqu’un formateur LLM apporte de la valeur mais ne peut pas respecter les contraintes serving, la distillation constitue l’une des solutions possibles :

  1. Utiliser un LLM puissant (le professeur) pour réclasser des milliers de requêtes d’entraînement.
  2. Entraîner un encodeur croisé de petite taille et rapide (l’élève, avec environ 100 M–200 M de paramètres) afin d’imiter la distribution de classement du LLM.
  3. Comparer les performances de l’élève, tant par rapport au professeur qu’à la méthode de référence, en ce qui concerne la qualité, la calibration et le coût de serving.

InRanker il distille MonoT5-3B en modèles de 60 M et 220 M de paramètres, ce qui représente une réduction de taille de 50 x tout en conservant des performances compétitives. Le Rankement sans GPT Cette approche génère une liste d’open source de 7 milliards d’entités rerankers, atteignant 97 % de l’efficacité du GPT-4 grâce à des QLoRA fine-tuning.

Les résultats de compression publiés ne constituent que des points de départ, et non des taux de compression attendus en environnement de production. La distillation peut hériter des biais du modèle de référence et perdre en qualité pour certaines catégories de requêtes rares ; il est donc nécessaire de conserver les jugements de pertinence originaux au sein du cycle d’évaluation.


Personnalisation et biais de positionnement

La pertinence générique ne suffit que jusqu’à un certain point. Une recherche pour « apple » doit afficher des iPhone pour un passionné de technologie, ainsi que des recettes à base d’apple pour quelqu’un qui consulte du contenu culinaire.

Une architecture de récupération couramment utilisée pour la personnalisation repose sur un modèle à deux tours embedding : le tour de requête encode la requête ainsi que le contexte de l’utilisateur, tandis que le tour d’éléments encode les éléments eux-mêmes et leurs métadonnées. La séparation entre mode hors ligne et mode en ligne permet une recherche par voisin le plus proche approximatif ; sa latence dépend néanmoins de l’encodeur, de l’index, des filtres et du système serving.

l’annonce d’Airbnb embeddings, celui de Pinterest OmniSearchSage, et Les systèmes à deux tours d’Uber Affichez différentes conceptions de production. Leur échelle ainsi que les améliorations rapportées correspondent à ces systèmes ; le schéma transférable consiste en une tour d’éléments hors ligne associée à une tour de requêtes/utilisateurs en ligne.

Les données de clic présentent des biais de position et d’exposition. PAL Une approche de débiaisage consiste à utiliser la position pendant l’entraînement, puis à la maintenir constante durant serving. Il ne s’agit pas d’une solution universelle ; des interventions aléatoires, des méthodes basées sur l’inverse de la propension et une évaluation par contrefactuel peuvent être plus adaptées pour un autre produit.


Adaptation de domaine à l’aide de requêtes synthétiques

Une erreur fréquente dans la conception des stratégies de recherche consiste à penser qu’un modèle entraîné sur des données web générales (comme MS MARCO) fonctionnera bien dans un domaine spécialisé. Il s’agit du problème hors domaine (OOD).

LLMs peut réduire, mais non éliminer, le goulot d’étranglement lié aux données étiquetées grâce au Generative Pseudo-Labeling (GPL, InPars):

  1. Prenez votre corpus de documents spécifique à un domaine donné.
  2. Prompt un LLM afin de « générer une requête de recherche que ce document serait en mesure de répondre ».
  3. Utilisez les paires synthétiques (requête, document) pour affiner votre moteur de récupération et reranker.

Les paires synthétiques peuvent être utiles lorsque les requêtes réelles sont rares, mais elles reflètent le générateur ainsi que prompt. Il convient de les dédoublonner, de filtrer les requêtes peu plausibles, et de les valider à l’aide du trafic réel non utilisé pour l’entraînement.

Une séquence d’expériences

Ajoutez de la complexité uniquement lorsque l’étape précédente révèle une défaillance mesurée :

Voie de maturité pratique

Étape 1 (base de référence) : mettre en œuvre BM25 ou le système lexical actuel afin de constituer un ensemble de requêtes évaluées. Enregistrer le taux de rappel, le NDCG, la latence ainsi que les segments de pannes.

Étape 2 (rappel des candidats) : tester la récupération dense et la fusion uniquement si la méthode de référence manque des documents pertinents. Ajuster le seuil de sélection des candidats en fonction du rappel et du coût associé.

Étape 3 (précision du classement) : ajouter un encodeur croisé si les candidats pertinents existent mais apparaissent dans le mauvais ordre. Déterminer la taille de sa liste restreinte à partir d’une courbe qualité-délai.

Étape 4 (adaptation au domaine) : ne procéder au réglage fin ou à la distillation qu’après que les modèles génériques aient montré des échecs stables spécifiques au domaine. Conserver les jugements réels non utilisés séparément des données d’entraînement synthétiques.

Étape 5 (couche coûteuse optionnelle) : tester de manière exhaustive ou par raisonnement reranking uniquement lorsque sa qualité incrémentale résiste à des exécutions répétées et justifie ainsi le temps de réponse, le coût, les aspects de confidentialité ainsi que la complexité liée aux solutions de secours.


Directions de recherche à évaluer séparément

Le raisonnement rerankers ainsi que les agents basés sur la recherche présentent de grands potentiels, cependant ils répondent à des types de questions différents de ceux abordés dans la démonstration de recherche de produits en cinq étapes.

Raisonnement basé sur rerankers

Rank1 entraîne rerankers en intégrant des traces de raisonnement, ce qui lui permet d’obtenir d’excellents résultats BRIGHT benchmark. Ces données sont pertinentes pour une récupération axée sur le raisonnement, et non pour une prédiction directe dans le cadre de la recherche de produits ESCI.

Pour les recherches juridiques ou scientifiques, comparer le raisonnement rerankers à des modèles de référence basés sur des encodeurs croisés performants ainsi que sur des approches par liste, en évaluant les jugements d’experts, les citations, la latence et la cohérence face aux échecs.

Agentic recherche

Search-o1 Il étudie un modèle qui effectue des recherches supplémentaires lors de la réponse à des questions à plusieurs étapes. Il s’agit d’un problème d’orchestration — génération de requêtes, arrêt du processus, utilisation des preuves et évaluation de la réponse — et non d’une autre étape reranking. Il convient de l’évaluer en se basant sur la correction finale de la tâche ainsi que sur le soutien apporté par les citations, et non uniquement sur des métriques de récupération d’informations.


Principaux enseignements

  1. Traitez la pile comme une séquence d’expériences. Définissez une base de référence lexicale ainsi qu’un ensemble de requêtes évaluées avant d’intégrer des mécanismes de récupération dense, de fusion ou reranking.

  2. Mesurer le taux de rappel des candidats de manière distincte de la précision du classement. Dans cet échantillon ESCI, le Recall@100 atteint 0,842 après fusion et reste stable au cours des deux étapes reranking.

  3. Utiliser une récupération hybride lorsque les erreurs sont complémentaires. Le RRF a amélioré à la fois le Recall@100 et le NDCG@10 lors de la démonstration, mais un autre corpus pourrait ne pas justifier l’utilisation de deux index.

  4. Ajouter un encodeur croisé lorsque la liste de candidats est correcte mais que l’ordre est erroné. Sélectionner le nombre de candidats en se basant sur une courbe qualité-délai mesurée.

  5. Considérez LLM reranking comme une expérience finale optionnelle. L’amélioration de 0,072 sur l’indice NDCG@10 obtenue dans ce cas relève de ce prompt, c’est‑à‑dire du modèle, des échantillons ainsi que des critères de pertinence. Les exécutions répétées, le parsing strict, les mécanismes de secours et les coûts associés font partie intégrante de l’évaluation.

  6. Maintenez les types de preuves séparés. Un résultat issu d’une étude papier, une étude de cas d’un fournisseur, cette démonstration sur ordinateur portable, ainsi qu’un test A/B en environnement de production répondent à des questions différentes.

Le code complet pipeline se trouve à github.com/slavadubrov/search-ranking-stack. Cloniez-le, exécutez-le, remplacez les modèles et les paramètres par d’autres valeurs, puis observez vous-même les résultats chiffrés.

Références

Articles de recherche

Datasets et benchmarks

Modèles utilisés dans la démonstration

Outils et plateformes

Références sectorielles

Projet de démonstration