Polydesk-logotype
Polydesk.ai — Header

Cross-Encoder

Un cross-encoder est un modèle Transformer qui prend en entrée une paire requête-document concaténée et produit un score de pertinence unique. Contrairement au bi-encoder qui encode chaque texte séparément, le cross-encoder permet une interaction directe entre tous les tokens de la requête et du document via le mécanisme d’attention.

C’est cette interaction directe qui fait toute la différence. Dans un bi-encoder, le mot « recyclage » dans la requête ne « voit » jamais le mot « risques sanitaires » dans le document. Chacun est compressé dans son propre vecteur indépendant. Dans un cross-encoder, chaque token de la requête peut interagir avec chaque token du document à chaque couche du Transformer. Le modèle capture ainsi des relations sémantiques fines que la simple comparaison de vecteurs ne peut pas saisir. Le prix à payer : il faut exécuter le modèle pour chaque paire, ce qui le rend inutilisable comme retriever sur de gros corpus mais idéal comme reranker sur un petit ensemble de candidats.

Cross-Encoder en bref
Catégorie
NLP / Information Retrieval
Architecture
Transformer unique, entrée = [CLS] requête [SEP] document [SEP]
Sortie
Score de pertinence (0 à 1)
Usage principal
Reranking dans les pipelines de recherche et de RAG
Modèles populaires
ms-marco-MiniLM, BGE Reranker, Cohere Rerank 4, Jina Reranker
Complémentaire de
Bi-encoder (retrieval initial)

Architecture du cross-encoder

Comment ça fonctionne

Le cross-encoder repose sur un modèle Transformer pré-entraîné (typiquement BERT, RoBERTa, MiniLM ou un modèle plus récent). Le processus se déroule en trois étapes.

1. Concaténation de l’entrée. La requête Q et le document D sont fusionnés en une seule séquence d’entrée selon le format standard des modèles BERT : [CLS] tokens_requête [SEP] tokens_document [SEP]. Le token spécial [CLS] servira de représentation globale de la paire. Le token [SEP] marque la séparation entre requête et document.

2. Encodage conjoint avec cross-attention. La séquence concaténée traverse le Transformer. À chaque couche, le mécanisme d’auto-attention (self-attention) permet à chaque token de la séquence d’interagir avec tous les autres tokens. Cela signifie que les mots de la requête peuvent directement « voir » les mots du document et réciproquement. C’est cette cross-attention qui donne son nom au modèle et qui explique sa supériorité en termes de précision : les relations fines entre requête et document sont explicitement modélisées.

3. Prédiction du score de pertinence. Le vecteur de sortie correspondant au token [CLS] est passé dans une couche de classification (une couche dense avec activation sigmoïde) qui produit un score entre 0 et 1. Un score de 0,95 signifie que le document est très pertinent pour la requête. Un score de 0,05 signifie qu’il ne l’est pas.

Pas d’embedding indépendant Un cross-encoder ne produit pas d’embedding pour la requête ni pour le document. Il ne produit qu’un score pour la paire. Vous ne pouvez pas encoder un document seul et le stocker dans une base vectorielle. C’est pourquoi il ne peut pas être utilisé comme retriever : il nécessite de connaître à la fois la requête et le document pour fonctionner.

Cross-encoder vs bi-encoder : comparaison détaillée

La distinction entre ces deux architectures est fondamentale pour comprendre les pipelines de recherche modernes.

Critère Bi-encoder Cross-encoder
Encodage Séparé (requête et document encodés indépendamment) Conjoint (requête + document concaténés et encodés ensemble)
Sortie Un vecteur par texte (embedding) Un score par paire (pas d’embedding)
Interaction Aucune interaction directe entre requête et document Cross-attention complète à chaque couche du Transformer
Pré-calcul Oui (les documents sont encodés une fois, stockés en base vectorielle) Non (chaque paire requête-document nécessite une inférence)
Vitesse (1M docs) Millisecondes (recherche ANN dans la base vectorielle) Impossible (1M inférences par requête)
Vitesse (50 docs) Sub-milliseconde (50 comparaisons de vecteurs) 100 à 500 ms (50 inférences Transformer)
Précision Bonne (65-80% sur les requêtes complexes) Excellente (+4 points nDCG@10 vs meilleurs bi-encoders)
Rôle dans le pipeline Retriever (étage 1 : recall) Reranker (étage 2 : precision)
Scalabilité Millions à milliards de documents 10 à 100 candidats maximum en pratique

La conclusion est limpide : le bi-encoder et le cross-encoder ne sont pas en compétition, ils sont complémentaires. Le bi-encoder est le sprinter qui parcourt tout le stade pour trouver les candidats. Le cross-encoder est le juge expert qui classe les finalistes avec précision. En production, on utilise toujours les deux.


Pourquoi le cross-encoder est plus précis

La supériorité du cross-encoder vient de deux facteurs architecturaux fondamentaux.

Pas de compression en un seul vecteur

Le bi-encoder doit compresser tout le sens d’un document de 500 mots en un seul vecteur de 768 dimensions. Inévitablement, de l’information est perdue. Un document qui traite de « l’impact environnemental du recyclage plastique sur la santé publique » contient de multiples concepts. Le vecteur résultant est une moyenne qui représente le sens général du document, pas ses nuances spécifiques. Le cross-encoder, lui, travaille directement sur les tokens bruts, sans compression.

Interaction contextuelle entre requête et document

Dans un bi-encoder, le document est encodé sans connaître la requête (les embeddings sont pré-calculés). Le vecteur du document est donc « générique », optimisé pour toutes les requêtes possibles. Le cross-encoder, en revanche, encode le document dans le contexte spécifique de la requête. Si la requête porte sur « recyclage et santé », le modèle peut focaliser son attention sur les passages du document qui traitent de ce lien précis, en ignorant les parties non pertinentes.

Les études empiriques confirment cette différence. Sur les benchmarks BEIR (un ensemble de 18 tâches de retrieval), les cross-encoders surpassent les meilleurs bi-encoders de 4+ points nDCG@10. L’écart est encore plus marqué en zero-shot (sur des domaines non vus à l’entraînement), car les cross-encoders généralisent mieux grâce à leurs interactions riches.


Les principaux modèles de cross-encoder

Modèle Taille Accès Caractéristiques
ms-marco-MiniLM-L-6-v2 ~22M params Open source (HuggingFace) Baseline standard, rapide sur CPU, entraîné sur MS MARCO (Bing). Le choix par défaut pour commencer.
ms-marco-TinyBERT-L-2 ~14M params Open source (HuggingFace) Ultra-léger, très rapide, précision moindre. Pour les contraintes de latence extrêmes.
BGE Reranker v2-m3 ~568M params Open source (HuggingFace) Multilingue, performant. Recommandé pour les corpus non anglophones.
Cohere Rerank 4 Pro Propriétaire API managée État de l’art commercial, 100+ langues, contexte 32K, self-learning. Lancé décembre 2025.
Cohere Rerank 4 Fast Propriétaire (compact) API managée Optimisé latence, bon rapport qualité-coût pour la production.
Jina Reranker v3 0,6B params API + open source Architecture « last but not late interaction » (LBNL). Listwise, multilingue, BEIR SOTA (61,94 nDCG@10).
Jina ColBERT v2 Variable API + open source Late interaction (ColBERT). 89 langues, 8192 tokens. Pré-calcul partiel des embeddings.
Quel modèle choisir ? Pour prototyper : ms-marco-MiniLM-L-6-v2 (gratuit, simple, rapide). Pour du multilingue / français : bge-reranker-v2-m3. Pour la production avec budget API : Cohere Rerank 4 (meilleur rapport qualité globale). Pour les longs documents (> 4000 tokens) : Jina ColBERT v2 ou Jina Reranker v3 avec leur contexte étendu.

Implémentation en Python

Avec Sentence Transformers

from sentence_transformers import CrossEncoder

# Charger le modèle
model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

# Scorer des paires requête-document
query = "impact du recyclage sur la santé publique"
documents = [
    "Le recyclage des plastiques réduit la pollution chimique qui affecte la santé des riverains",
    "Les programmes de recyclage municipaux coûtent en moyenne 50€ par habitant",
    "La santé publique bénéficie directement de la réduction des déchets toxiques par le recyclage",
    "L'industrie du recyclage emploie 500 000 personnes en Europe",
]

# Créer les paires
pairs = [(query, doc) for doc in documents]

# Obtenir les scores
scores = model.predict(pairs)

# Afficher les résultats triés
results = sorted(zip(scores, documents), reverse=True)
for score, doc in results:
    print(f"Score: {score:.4f} | {doc}")

# Résultat attendu :
# Score: 0.9823 | La santé publique bénéficie directement de la réduction...
# Score: 0.9456 | Le recyclage des plastiques réduit la pollution chimique...
# Score: 0.0234 | L'industrie du recyclage emploie 500 000 personnes...
# Score: 0.0089 | Les programmes de recyclage municipaux coûtent...

Le cross-encoder classe correctement les documents qui traitent du lien spécifique entre recyclage ET santé publique. Les documents qui parlent de recyclage OU de santé mais pas du lien entre les deux sont relégués en bas du classement. Un bi-encoder aurait probablement classé les quatre documents de façon plus homogène, car ils contiennent tous des mots liés au recyclage.

Pipeline complet bi-encoder + cross-encoder

from sentence_transformers import SentenceTransformer, CrossEncoder, util

# Étage 1 : Retrieval avec bi-encoder
bi_encoder = SentenceTransformer('all-MiniLM-L6-v2')

# Pré-calcul des embeddings du corpus (fait une seule fois)
corpus_embeddings = bi_encoder.encode(corpus, convert_to_tensor=True)

# Recherche des top-k candidats
query = "impact du recyclage sur la santé"
query_embedding = bi_encoder.encode(query, convert_to_tensor=True)
hits = util.semantic_search(query_embedding, corpus_embeddings, top_k=50)[0]

# Étage 2 : Reranking avec cross-encoder
cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
candidates = [(query, corpus[hit['corpus_id']]) for hit in hits]
rerank_scores = cross_encoder.predict(candidates)

# Tri final par score du cross-encoder
final_results = sorted(
    zip(rerank_scores, [corpus[h['corpus_id']] for h in hits]),
    reverse=True
)[:5]  # Top 5 après reranking

Ce pipeline en deux étages est le pattern standard. Le bi-encoder gère l’échelle (millions de documents en millisecondes), le cross-encoder gère la précision (50 candidats en quelques centaines de millisecondes).


Cas d’usage du cross-encoder

Reranking dans les pipelines RAG

C’est le cas d’usage dominant. Dans un pipeline RAG, le hybrid search (BM25 + vecteurs) récupère les chunks candidats, puis le cross-encoder les reclasse. Seuls les top 3-5 chunks les plus pertinents sont injectés dans le prompt du LLM. L’impact est double : le LLM reçoit une meilleure information (moins de bruit), et la fenêtre de contexte est utilisée plus efficacement. Des études montrent que l’ajout d’un cross-encoder réduit les hallucinations en augmentant la fidélité du contexte de 20 à 30%.

Moteurs de recherche

Les moteurs de recherche utilisent des cross-encoders (ou des modèles similaires) pour le re-scoring final des résultats. Après le retrieval initial (index inversé + signaux de ranking), un modèle neural évalue les top candidats avec plus de finesse. Elasticsearch intègre cette logique via ses fonctionnalités de reranking et son modèle ELSER.

Classification de paires de textes

Au-delà du reranking, les cross-encoders sont utilisés pour des tâches de classification de paires : détection de paraphrases, vérification de contradiction (NLI, Natural Language Inference), détection de doublons dans les bases de FAQ, et scoring de similarité sémantique fine.

Question answering

Dans les systèmes de questions-réponses, un cross-encoder peut déterminer si un passage contient réellement la réponse à une question, en évaluant l’adéquation spécifique entre la question et le passage candidat.


Limites du cross-encoder

Non scalable pour le retrieval. Évaluer chaque document d’un corpus de 10 millions avec un cross-encoder prendrait des heures pour une seule requête. Le cross-encoder ne peut fonctionner que sur un petit ensemble de candidats pré-filtrés (typiquement 20 à 100).

Pas d’embedding réutilisable. Contrairement au bi-encoder, le cross-encoder ne produit pas de représentation vectorielle indépendante d’un document. Vous ne pouvez pas stocker ses « résultats » dans une base vectorielle. Chaque nouvelle requête nécessite de refaire l’inférence sur toutes les paires.

Latence non négligeable. Sur CPU, un modèle comme ms-marco-MiniLM traite environ 20 à 50 paires par seconde. Sur GPU, c’est 200 à 500 paires par seconde en batch. Pour 50 candidats, cela représente 100 ms à 2,5 secondes selon l’infrastructure. C’est acceptable en post-traitement, mais pas pour un retrieval temps réel.

Sensible à la longueur des entrées. Les modèles BERT standard ont une limite de 512 tokens pour l’entrée combinée requête + document. Si le document est plus long, il faut le tronquer ou le découper en chunks. Les modèles récents comme Jina Reranker v3 (131K tokens) et Cohere Rerank 4 (32K tokens) ont considérablement élargi cette limite.


Évolutions et alternatives

ColBERT et le late interaction

ColBERT propose un compromis entre bi-encoder et cross-encoder. Il encode séparément la requête et le document en matrices de vecteurs au niveau des tokens (pas un seul vecteur). La similarité est calculée par MaxSim : pour chaque token de la requête, on prend la similarité maximale avec les tokens du document, puis on somme. Les embeddings de documents sont pré-calculables, ce qui rend ColBERT beaucoup plus rapide qu’un cross-encoder tout en capturant des interactions plus fines qu’un bi-encoder. Jina ColBERT v2 est la variante multilingue de référence.

Knowledge distillation

La distillation consiste à entraîner un bi-encoder à imiter les scores d’un cross-encoder. Le cross-encoder produit des labels de pertinence sur des paires de données, puis le bi-encoder est entraîné à reproduire ces scores. Le résultat est un bi-encoder plus précis qui conserve l’avantage de vitesse et de scalabilité. C’est une technique de plus en plus utilisée pour fermer l’écart entre les deux architectures.

Last But Not Late Interaction (Jina Reranker v3)

Jina Reranker v3 introduit une architecture hybride où la requête et tous les documents candidats sont traités ensemble dans une même fenêtre de contexte via l’auto-attention causale. Contrairement à ColBERT qui interagit après l’encodage, cette approche permet des interactions pendant l’encodage. Le modèle peut aussi comparer les documents entre eux (cross-document attention), ce qui améliore le classement listwise. Avec 0,6B de paramètres, il atteint des performances état de l’art sur BEIR.


Verdict

Le cross-encoder est le modèle le plus précis pour évaluer la pertinence d’un document par rapport à une requête. Son rôle dans les pipelines de recherche et de RAG est non négociable : c’est l’étage de reranking qui transforme un bon retrieval en un excellent résultat. Sans cross-encoder, vous envoyez au LLM un contexte approximatif. Avec, vous envoyez un contexte affiné.

Le compromis latence-précision est clair et accepté par l’industrie. En production, le pattern bi-encoder (retrieval) → cross-encoder (reranking) est le standard. Pour débuter, ms-marco-MiniLM-L-6-v2 est le choix par défaut. Pour la production multillingue à grande échelle, Cohere Rerank 4 ou BGE Reranker v2-m3 sont les références. Les évolutions comme ColBERT et Jina Reranker v3 cherchent à fermer l’écart entre vitesse du bi-encoder et précision du cross-encoder, et c’est la direction de recherche la plus prometteuse du domaine.


Questions fréquentes sur le cross-encoder

Quelle est la différence entre un cross-encoder et un bi-encoder ?

Le bi-encoder encode la requête et le document séparément en vecteurs indépendants, puis compare ces vecteurs par similarité cosinus. C’est rapide et scalable (les documents sont pré-encodés), mais moins précis car il n’y a pas d’interaction directe entre requête et document. Le cross-encoder concatène la requête et le document, les encode ensemble dans un Transformer, et produit un score de pertinence. C’est beaucoup plus précis (chaque token de la requête interagit avec chaque token du document), mais beaucoup plus lent. En production, on utilise le bi-encoder pour le retrieval initial (millions de documents) et le cross-encoder pour le reranking final (50-100 candidats).

Pourquoi un cross-encoder ne peut-il pas remplacer un bi-encoder ?

Le cross-encoder nécessite de traiter chaque paire requête-document individuellement dans le Transformer. Pour un corpus de 1 million de documents, cela signifierait 1 million d’inférences par requête, soit plusieurs heures de calcul. Un bi-encoder, lui, pré-calcule les embeddings des documents une seule fois, puis compare la requête à tous les documents via une simple recherche de plus proches voisins en quelques millisecondes. Le cross-encoder est réservé au reclassement d’un petit ensemble (20-100) de candidats déjà filtrés.

Quel modèle de cross-encoder utiliser pour du texte en français ?

Pour du français, les modèles ms-marco (entraînés sur de l’anglais) fonctionnent correctement mais ne sont pas optimaux. Préférez bge-reranker-v2-m3 de BAAI, un modèle multilingue qui gère bien le français. Si le budget le permet, Cohere Rerank 4 offre un support natif de plus de 100 langues avec des performances état de l’art. Jina Reranker v3, entraîné sur 89 langues dont le français, est aussi un excellent choix en open source.

Combien de paires un cross-encoder peut-il traiter par seconde ?

Cela dépend du modèle et du hardware. Pour ms-marco-MiniLM-L-6-v2 (~22M params) : environ 40-80 paires/seconde sur CPU, et 300-600 paires/seconde sur GPU en batch. Pour un modèle plus gros comme BGE Reranker v2-m3 (~568M params) : environ 5-15 paires/seconde sur CPU et 50-150 sur GPU. En pratique, pour 50 candidats, comptez 100-300 ms sur GPU avec MiniLM, ou 500 ms à 2 secondes sur CPU. Le traitement en batch (toutes les paires en une seule opération) est critique pour optimiser le débit.

Qu’est-ce que ColBERT et comment se compare-t-il au cross-encoder ?

ColBERT est un modèle à « late interaction » qui se situe entre le bi-encoder et le cross-encoder. Il encode la requête et le document séparément en matrices de vecteurs au niveau des tokens (pas un seul vecteur), puis calcule la similarité par MaxSim (similarité maximale entre chaque token de la requête et les tokens du document). Les embeddings de documents sont pré-calculables, ce qui le rend beaucoup plus rapide qu’un cross-encoder. Il est moins précis qu’un cross-encoder complet mais plus précis qu’un bi-encoder simple. Jina ColBERT v2 (89 langues, 8192 tokens) et le nouveau Jina Reranker v3 (architecture LBNL) sont les implémentations les plus avancées.

Polydesk.ai — Footer