Aller au contenu
Mohamed Tahiri
Miami --:--
← Tous les articles

La recherche hybride, expliquée en jouant

Pourquoi un assistant IA rate parfois des réponses évidentes, et comment combiner le sens et les mots pour qu’il les trouve. Avec un terrain de jeu interactif.

Tapez « code E-07 » dans l’aide en ligne d’un vélo électrique. Vous attendez la fiche du code E-07. Un assistant construit sur des embeddings, la technique à la mode, vous sert volontiers celle du code E-03. Il a bien compris que vous parliez d’un code d’erreur. Il n’a pas compris lequel.

J’ai vu ce bug des dizaines de fois en construisant un assistant pour des équipes de maintenance. Références de pièces, codes de panne, numéros de documents : tout ce qui compte vraiment dans un métier technique est précisément ce que la recherche « par le sens » gère le plus mal. La solution porte un nom un peu technique, la recherche hybride, mais l’idée tient en une phrase : chercher de deux façons, puis combiner.

Cet article la démonte pièce par pièce, avec de petites simulations à manipuler. Tout tourne dans votre navigateur, sur douze fiches d’aide fictives.

DocumentsPDF · PAGES · TICKETSDécoupagePASSAGESSensEMBEDDINGSMotsBM25FusionRRFReclassementCROSS-ENCODERRéponseAVEC SES SOURCES

Deux façons de chercher

La première est vieille comme les moteurs de recherche : on compte les mots. Une fiche qui contient les mots de la question remonte, d’autant plus que ces mots sont rares dans le reste du corpus. L’algorithme de référence s’appelle BM25. Il est rapide, prévisible, et il adore les mots exacts. Il ignore en revanche que « hiver » et « froid » parlent de la même chose.

La seconde transforme chaque texte en une liste de nombres, un embedding, calculée par un modèle qui a lu énormément de texte. Deux phrases qui veulent dire la même chose obtiennent des nombres proches, même sans un mot en commun. C’est ce qui donne l’impression que la machine comprend.

On peut se représenter ces nombres comme des coordonnées. Chaque fiche devient un point, et une question devient un point de plus, qui atterrit près des fiches qui lui ressemblent. Essayez :

Tapez maintenant « référence BX-220 » : le point ne bouge pas. Pour le modèle, un code produit est une suite de caractères sans signification. Il n’a aucune raison de le rapprocher de quoi que ce soit.

Chacune a ses angles morts

Les deux méthodes se trompent, mais jamais au même endroit. La recherche par mots rate les paraphrases : « ma batterie tient moins longtemps en hiver » ne contient presque aucun des mots de la fiche qui y répond. La recherche par le sens rate les identifiants : codes d’erreur, références, numéros de version, noms propres rares.

Voici les deux côte à côte, puis leur combinaison. Les suggestions montrent chaque cas, mais vous pouvez taper ce que vous voulez.

Fusionner deux classements

On a donc deux listes ordonnées, avec des scores qui ne se comparent pas : BM25 produit des nombres sans plafond, la similarité entre embeddings reste entre -1 et 1. Additionner les scores n’a pas de sens. La méthode la plus robuste, et de loin la plus simple, ignore les scores et ne garde que les rangs.

Elle s’appelle Reciprocal Rank Fusion, ou RRF. Chaque liste donne à chaque document un vote de 1 / (k + rang). Premier dans une liste, il reçoit un gros vote. Dixième, un petit. On additionne les votes, on trie, c’est fini.

rrf.py
def rrf(rankings, k=60):
    """Fuse ranked lists of document ids with Reciprocal Rank Fusion."""
    scores = {}
    for ranking in rankings:
        for rank, doc_id in enumerate(ranking, start=1):
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores, key=scores.get, reverse=True)

fused = rrf([bm25_ids, embedding_ids])

La constante k amortit l’écart entre les premières places. Avec un k petit, être premier quelque part suffit à gagner. Avec un k grand, mieux vaut être correctement classé partout. La valeur 60, proposée dans l’article qui a introduit la méthode, marche étonnamment bien : je n’ai presque jamais eu besoin d’y toucher.

Reclasser les meilleurs candidats

La fusion ramène presque toujours la bonne fiche dans le haut de la liste, mais pas forcément en tête. Pour ordonner finement les premiers résultats, on ajoute un reclasseur, souvent un cross-encoder : un modèle qui lit la question et chaque candidat ensemble, mot à mot, au lieu de comparer deux résumés chiffrés.

Il est bien plus précis, et bien plus lent. Impossible de lui faire lire tout le corpus à chaque question. D’où l’architecture en deux temps : une recherche large et rapide pour trouver une cinquantaine de candidats, puis un reclassement lent et précis sur ces cinquante-là.

Activez « Reclasser le top 5 » dans le terrain de jeu : sur les questions ambiguës, c’est souvent là que la bonne fiche passe de la deuxième à la première place.

Avant tout ça : bien découper

Tout ce qui précède suppose que la réponse se trouve dans un passage indexé. Or on n’indexe jamais un document entier : on le découpe en morceaux de quelques dizaines à quelques centaines de mots. Et la taille de ces morceaux décide de beaucoup de choses.

Trop petits, ils coupent les réponses en deux. Trop grands, ils noient la phrase utile dans du bruit, et le modèle qui rédige la réponse finale doit la retrouver lui-même. Jouez avec la taille et le chevauchement :

Le chevauchement est une assurance bon marché : chaque morceau reprend la fin du précédent, ce qui limite les réponses coupées net. En pratique, je découpe d’abord en suivant la structure du document, titres et paragraphes, et je n’utilise une taille fixe qu’en dernier recours.

Ce que je retiens en production

  • Mesurer avant de régler. Une centaine de questions avec leur bonne réponse vaut plus que toutes les intuitions. On regarde d’abord si la bonne fiche apparaît dans les cinq premiers résultats.
  • Garder les identifiants intacts. Un découpage en mots qui transforme « E-07 » en « e » et « 07 » détruit exactement ce que BM25 sait bien faire.
  • Ne pas sur-régler k. 60 par défaut, et on passe à autre chose : les gains sont presque toujours ailleurs.
  • Transformer chaque échec en test. Quand quelqu’un signale une mauvaise réponse, la question rejoint le jeu d’évaluation. Le système ne peut plus régresser dessus sans qu’on le voie.

C’est ce que j’ai mis en place pour Buddy, un assistant pour des équipes de maintenance. La recherche hybride n’y est pas une option : dans un métier où tout repose sur des références exactes, c’est la condition pour être utile.

Le corpus, les embeddings et le reclasseur de cet article sont des simulations simplifiées. BM25 et RRF, eux, sont implémentés pour de vrai.

Contact

Construisons quelque chose.

Ou laissez un message