Le modèle mental par défaut dans les pipelines RAG ressemble à peu près à ceci : embarquer tout avec un modèle de pointe, le stocker dans une base vectorielle, interroger avec le même modèle. Voilà. La similarité sémantique trouvera ce qui est pertinent. C'est un modèle correct pour le langage naturel. Il se dégrade silencieusement sur les corpus techniques, et le mode de défaillance est assez subtil pour que la plupart des équipes le déploient en production avant de s'en apercevoir.
Nous avons exécuté 3 200 requêtes contre un corpus technique de 620 000 chunks : documentation d'API, références de SDK, registres de codes d'erreur et guides opérationnels internes. Le type de contenu qui se lit bien pour un humain mais qui est statistiquement rare dans les données d'entraînement de tout modèle d'embeddings. BM25 a remporté deux des quatre catégories de requêtes haut la main, avec des marges suffisamment larges pour donner à réfléchir à tout ingénieur RAG. Le point de croisement, c'est là que se situe la vraie histoire.
Le postulat de retrieval que tout le monde fait
Les embeddings denses apprennent à représenter des voisinages sémantiques : les mots et expressions qui apparaissent dans des contextes similaires se regroupent. C'est exactement ce qu'on veut quand un utilisateur demande « comment redémarrer le service » et que la documentation dit « pour réinitialiser le démon ». L'embedding comble l'écart lexical, et le retrieval semble magique.
L'échec survient quand un utilisateur interroge un numéro de modèle spécifique, un code d'erreur, un SKU de produit, le nom d'une personne ou un acronyme rare. Le modèle d'embeddings se retrouve face à un problème différent. Ces termes sont soit sous-représentés dans la distribution d'entraînement, soit leur forme de surface compte davantage que leur voisinage sémantique. ERR_CONN_RESET_7421 n'a pas de voisinage sémantique. Il a une chaîne exacte qui soit apparaît dans le document, soit n'y apparaît pas.
BM25, une fonction de retrieval probabiliste de 1994, traite ce cas par conception. C'est, dans son essence, un modèle de fréquence de termes pondérée. Il récompense les correspondances exactes sur les termes rares davantage qu'il ne récompense les correspondances approximatives sur les termes courants. Sur du contenu technique, c'est souvent ce qu'on veut, et l'algorithme vieux de 32 ans bat le transformer.
Ce que nous avons mesuré, et pourquoi la taxonomie des requêtes compte
Même méthodologie que le comparatif de bases vectorielles : recall@5 par rapport à la vérité terrain en recherche exacte, requêtes classifiées à la main, aucun cherry-picking. Les requêtes ont été classifiées à l'aveugle : les classificateurs ne savaient pas quelle méthode de retrieval serait testée. Le corpus présente une forte densité d'entités nommées rares (identifiants de modèles, chaînes de version, noms de code internes, codes d'erreur), exactement le type de contenu qui expose le mode de défaillance dense-uniquement.
| type de requête | part | BM25 | Dense | Hybride | gagnant |
|---|---|---|---|---|---|
| recherche d'entité nommée | 28 % | 0,961 ★ | 0,712 | 0,948 | BM25 |
| conceptuelle / sémantique | 34 % | 0,724 | 0,951 | 0,963 ★ | Hybride |
| code d'erreur / identifiant | 21 % | 0,974 ★ | 0,681 | 0,952 | BM25 |
| mixte / ambiguë | 17 % | 0,803 | 0,861 | 0,931 ★ | Hybride |
La séparation est nette. BM25 gagne sur la recherche d'entités nommées et les codes d'erreur par des marges qui devraient donner à réfléchir à tout ingénieur RAG. Le dense gagne sur les requêtes conceptuelles, ce qui confirme que les embeddings fonctionnent comme prévu. L'hybride gagne ou égalise partout, mais la marge sur la catégorie gagnante est faible. La vraie histoire, c'est l'écart entre dense et BM25 sur les catégories à entités sparse : 0,712 contre 0,961 sur la recherche d'entités nommées n'est pas un problème de réglage, c'est un problème structurel.
Pourquoi les embeddings échouent sur les entités nommées rares
Cela vaut la peine de comprendre le mécanisme, parce que cela change la façon dont on conçoit le corpus et le routage des requêtes. Les modèles d'embeddings sont entraînés sur de grands corpus textuels avec un objectif de modélisation du langage. Les termes qui apparaissent rarement dans cette distribution d'entraînement obtiennent des représentations faibles et à haute variance. Quand le modèle les rencontre lors de l'inférence, il les projette vers le voisinage sémantique que ses données d'entraînement leur ont associé, ce qui est souvent inexact ou diffus.
| terme | type | score dense | mode de défaillance |
|---|---|---|---|
ERR_CONN_RESET_7421 | code d'erreur · 3× dans le corpus | 0,58 | projeté vers le groupe générique « erreur de connexion » |
libvorbis-1.3.7 | chaîne de version | 0,51 | confondu avec 1.3.5 et 1.3.6 : spécificité de version perdue |
Thornton-Vance protocol | nom de code interne | 0,43 | aucun signal d'entraînement externe, atterrit près du générique « protocole » |
| authentication flow | concept courant | 0,91 | placé correctement près d'OAuth, échange de jeton, connexion |
La pondération fréquence de terme / fréquence inverse de document de BM25 est précisément adaptée à ce mode de défaillance. L'IDF accorde un poids plus élevé aux termes plus rares : l'inverse de ce que fait implicitement un modèle d'embeddings dense. Une requête contenant ERR_CONN_RESET_7421 donne à ce jeton un score très élevé précisément parce qu'il n'apparaît que dans 3 documents. Le signal est concentré, pas diffusé.
Retrieval hybride avec RRF
Le retrieval hybride exécute les deux méthodes et fusionne les listes classées. L'approche de fusion canonique est la Reciprocal Rank Fusion : simple, peu paramétrée et étonnamment efficace. Le score RRF d'un document est la somme de ses rangs réciproques provenant de chaque méthode de retrieval.
RRF(d) = Σ 1 / (k + ranki(d)) k = 60 (constante, atténue l'impact des rangs très élevés). rank_i(d) = rang du document d dans la liste de résultats i. La somme porte sur chaque méthode de retrieval (BM25, dense, éventuellement d'autres). Les documents absents d'une liste obtiennent rang = ∞, ce qui contribue 0.
La valeur par défaut k=60 de RRF n'est pas magique. Elle a été dérivée empiriquement dans l'article original de 2009 et s'est révélée étonnamment robuste à travers les domaines. La constante empêche un document classé n°1 dans une liste de dominer un document classé n°2 dans les deux listes. C'est un plafond souple sur la dominance d'une seule liste.
L'alternative à RRF est une combinaison linéaire pondérée : α · score_dense + (1-α) · score_bm25. Cela nécessite de normaliser les scores entre les méthodes, un problème non trivial puisque les scores BM25 et la similarité cosinus vivent sur des échelles différentes. RRF contourne entièrement ceci en opérant sur les rangs, pas sur les scores. C'est le bon défaut pour la plupart des cas d'usage.
La combinaison pondérée gagne quand on dispose d'une connaissance préalable solide de la distribution des requêtes. Si on sait que 80 % des requêtes sont des recherches d'entités nommées, on peut régler α vers BM25 et dépasser le RRF fixe. Nous avons construit un classificateur de requêtes pour faire cela dynamiquement, plus de détails ci-dessous.
La carte thermique rend le point de croisement visible. Pour les requêtes d'entités nommées et de codes d'erreur, la courbe de recall descend en pente raide à mesure que α augmente. Même un léger glissement vers le dense coûte de la précision. Pour les requêtes sémantiques, c'est l'inverse. Le α fixe optimal est un compromis qui ne satisfait pleinement aucun des deux types de requête. C'est pourquoi le routage adaptatif aux requêtes vaut la peine d'être construit.
Routage des requêtes : le classificateur en deux lignes
Un α adaptatif paraît coûteux. En pratique, le signal de routage est souvent lexical : on peut classifier la plupart des requêtes correctement avec une heuristique simple avant de faire appel à un modèle. Nous avons construit un classificateur à deux étages.
Étape 1, correspondance de motifs. Si la requête contient un jeton correspondant à une regex pour des motifs d'entités connus (codes d'erreur, chaînes de version, identifiants de modèle, UUID, codes alphanumériques dépassant un seuil de longueur), la router vers BM25-dominant (α = 0,1). Cela capture environ 82 % de la catégorie de requêtes à entités sparse sans aucune inférence de modèle.
Étape 2, heuristique d'entropie. Calculer l'entropie des tokens de la requête par rapport au vocabulaire du corpus. Les requêtes à faible entropie (tokens fréquents dans l'index) vont vers le dense-dominant (α = 0,8). Les requêtes à haute entropie (tokens rares ou absents de l'index) vont vers BM25-dominant. Cela gère les cas que la correspondance de motifs rate, au coût d'une recherche rapide dans le vocabulaire.
Le classificateur de modèle complet, une tête binaire fine-tunée sur un petit encodeur, n'est invoqué que pour le milieu ambigu : environ 15 % du trafic. Surcoût de routage de bout en bout : moins de 3 ms p99. Amélioration du recall par rapport au RRF fixe : +4,2 points sur le trafic mixte. Ça vaut le coup.
Ce qu'il faut vraiment construire
Le choix entre les méthodes de retrieval dépend de votre corpus et de la distribution de vos requêtes, pas du classement de votre modèle d'embeddings sur les benchmarks. Voici l'arbre de décision pratique.
k=60). Mesurez votre distribution de requêtes. Ajoutez le routeur à deux étages une fois que vous avez confirmé que la distribution est suffisamment stable pour régler contre elle. Notre défaut actuel pour les nouveaux déploiements. Une note opérationnelle : les index BM25 sont légers, rapides à construire et trivialement inspectables. Si vous déboguez un échec de recall et que votre pile de retrieval est dense-uniquement, vous opérez à l'aveugle. Vous ne pouvez pas voir pourquoi un document a été classé où il l'a été sans sonder l'espace d'embeddings. La décomposition du score BM25 est lisible par un humain. Ça compte en production quand quelque chose se passe mal à 2 h du matin.
Si vous souhaitez qu'on examine la bonne architecture de retrieval pour votre corpus, le formulaire de contact est le moyen le plus rapide. Nous faisons des révisions gratuites de 30 minutes pour les systèmes RAG en production.