Aller au contenu
Cercle IA Tech · Embeddings Un site du réseau Cercle IA Tech

Guide

Recherche sémantique sans RAG : un moteur interne

Faire retrouver vos documents ou vos pages par le sens de la question, sans modèle qui rédige : architecture, code minimal, pièges et mesure.

Mis à jour le

Un moteur de recherche sémantique retrouve des documents par le sens de la question, même quand ils n'emploient pas les mêmes mots. Il suffit d'un modèle de plongements et d'un index de vecteurs : pas de modèle de langage, pas de réponse rédigée, seulement une liste de résultats, comme un moteur classique. C'est souvent la bonne première étape avant un RAG (génération augmentée par récupération, où un modèle rédige la réponse à partir des documents trouvés), et parfois tout ce dont on a besoin.

Recherche sémantique ou RAG ?

Recherche sémantique RAG
Ce que voit l'utilisateur une liste de documents ou de passages une réponse rédigée, avec ses sources
Modèle de langage aucun oui, à chaque question
Risque d'invention aucun dans la liste elle-même possible, à surveiller
Coût par question le plongement de la question plongement + génération
Bon choix pour intranet, base documentaire, catalogue, aide en ligne assistant qui répond en langage courant

Si vos utilisateurs veulent « le bon document » plutôt qu'« une réponse », la recherche sémantique suffit. Pour la version avec réponse rédigée, voir Mettre en place un RAG. Pour une explication non technique de la différence entre mots-clés et sens, voir Mots-clés ou question.

Recherche symétrique ou asymétrique

La documentation de Sentence Transformers distingue deux cas, et insiste : il est essentiel de choisir le modèle adapté à son type de tâche.

  • Symétrique : la question et les entrées ont la même forme. Exemple : retrouver une question déjà posée dans une foire aux questions.
  • Asymétrique : une question courte, des passages longs. Exemple : chercher « délai de préavis » dans des contrats. C'est le cas le plus fréquent dans un moteur interne.

En asymétrique, la question et les documents ne s'encodent pas de la même façon : encode_query et encode_document dans Sentence Transformers, préfixes query: et passage: pour multilingual-e5.

Le code minimal

Pour un petit corpus, tout tient en mémoire (méthodes documentées par Sentence Transformers) :

from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer("intfloat/multilingual-e5-large")
corpus = ["passage: Procédure de remboursement des notes de frais.",
          "passage: Règlement intérieur : horaires et congés."]
corpus_emb = model.encode(corpus, normalize_embeddings=True)

q = model.encode(["query: comment me faire rembourser un repas ?"], normalize_embeddings=True)
hits = util.semantic_search(q, corpus_emb, top_k=5, score_function=util.dot_score)
print(hits[0])  # [{'corpus_id': ..., 'score': ...}, ...]

Les vecteurs étant normalisés, le produit scalaire (dot_score) remplace le cosinus, comme le conseille la documentation pour gagner du temps. Les textes de l'exemple sont illustratifs.

Passer à l'échelle

La même documentation situe la recherche exacte faite à la main jusqu'à environ un million d'entrées. Au-delà, ou si vous voulez une base persistante partagée par plusieurs applications :

  • une base avec index approximatif : pgvector dans PostgreSQL, ou une base dédiée (voir le comparatif) ;
  • une bibliothèque de recherche approximative citée par Sentence Transformers : Annoy, FAISS, hnswlib ;
  • un moteur de recherche existant : la documentation rappelle qu'Elasticsearch indexe des vecteurs denses avec un index HNSW, et qu'OpenSearch combine vecteurs et recherche par mots-clés BM25.

Les cinq pièges d'un moteur interne

  1. Les références exactes. Un numéro de commande ou un code article se retrouve mal par le sens. Combinez avec une recherche par mots-clés : voir Recherche hybride. BGE-M3 fournit d'ailleurs, d'après sa fiche, une sortie lexicale en plus du vecteur dense.
  2. Les documents trop longs. Un document de 40 pages résumé en un seul vecteur perd ses détails. Indexez des passages, et affichez le document parent dans les résultats.
  3. Les droits. Le moteur ne doit pas montrer un document à qui n'a pas le droit de le lire. Filtrez pendant la recherche (avec pgvector, une clause WHERE).
  4. L'absence de « rien trouvé ». Une recherche par vecteurs renvoie toujours les plus proches, même s'ils sont sans rapport. Fixez un seuil de score après essais, ou affichez le score.
  5. Le classement fin. Pour des recherches complexes, la documentation conseille deux étapes : une recherche large, puis un retri des meilleurs candidats par un modèle plus précis, dit de retri (reranking).

Mesurer avant d'ouvrir

Préparez une liste de recherches réelles (tirées des journaux de votre moteur actuel si vous en avez un) avec le document attendu pour chacune. Comparez l'ancien moteur et le nouveau : le document attendu apparaît-il dans les cinq premiers résultats ? C'est la même logique que la note de recherche du classement MTEB, appliquée à vos propres données.

Questions fréquentes

Faut-il un modèle de langage (LLM) pour faire de la recherche sémantique ?

Non. Un modèle de plongements suffit : il transforme documents et questions en vecteurs, et la recherche renvoie les documents les plus proches. Aucun texte n'est rédigé, ce qui évite les erreurs de rédaction et réduit le coût.

Jusqu'à quel volume peut-on chercher sans index ?

La documentation de Sentence Transformers indique qu'une recherche exacte faite à la main convient jusqu'à environ un million d'entrées ; au-delà, elle oriente vers des index approximatifs.

Sources

Pages consultées pour écrire cet article :

  1. https://sbert.net/examples/sentence_transformer/applications/semantic-search/README.html
  2. https://huggingface.co/intfloat/multilingual-e5-large
  3. https://huggingface.co/BAAI/bge-m3
  4. https://github.com/pgvector/pgvector

À lire aussi