Un embedding est un vecteur de nombres qui encode le sens d'un texte : deux phrases proches par le sens produisent des vecteurs proches dans l'espace, même sans aucun mot commun. C'est ce qui rend possible la recherche sémantique (par le sens), par opposition à la recherche par mots-clés. Cet article explique ce qu'est un embedding, comment on l'apprend, comment on mesure la proximité, et comment passer à l'échelle avec la recherche vectorielle.
Qu'est-ce qu'un embedding ?
Un embedding est une représentation numérique apprise qui place un texte (mot, phrase, document) dans un espace vectoriel où la proximité géométrique reflète la proximité de sens. Un modèle convertit un texte de longueur quelconque en un vecteur dense de taille fixe — par exemple 384 dimensions pour all-MiniLM-L6-v2, 1024 pour Cohere v3, 3072 pour OpenAI text-embedding-3-large.
Figure : un word embedding. Source : Wikimedia Commons (CC BY-SA).
Contrairement aux représentations lexicales creuses (sac de mots, TF-IDF), les embeddings rapprochent les synonymes même sans mot partagé : c'est toute la différence entre « sémantique » et « mots-clés ».
Comment on les apprend
La lignée historique va de la sémantique distributionnelle (Firth, 1957) à word2vec (Mikolov et al., Google, 2013), la percée qui a popularisé les vecteurs de mots. word2vec utilise une fenêtre de contexte glissante avec deux architectures : CBOW (le contexte prédit le mot, plus rapide) et skip-gram (le mot prédit le contexte, meilleur pour les mots rares). Ces vecteurs sont statiques (un mot = un vecteur).
Figure : CBOW vs Skip-gram. Source : Wikimedia Commons (CC BY-SA).
Les embeddings de phrases modernes utilisent un bi-encodeur entraîné par objectif contrastif : rapprocher les paires positives (qui correspondent), éloigner les négatives. La perte dominante en production est MultipleNegativesRankingLoss (négatifs « dans le batch »). Enfin, les modèles contextuels (BERT et successeurs) donnent à un mot un vecteur différent selon le contexte, ce qui règle la polysémie — un progrès clé sur les vecteurs statiques.
L'espace vectoriel et la géométrie du sens
Chaque dimension est une caractéristique latente ; le sens est encodé par la direction et la position relative, pas par un axe interprétable isolément. La structure d'analogie linéaire est célèbre :
vecteur("roi") − vecteur("homme") + vecteur("femme") ≈ vecteur("reine")
Le même décalage conceptuel (la royauté) est une direction constante. On retrouve le mot dont le vecteur a la plus forte similarité cosinus avec b − a + c. Comme ces espaces ont des centaines de dimensions, on les projette en 2-D (t-SNE, UMAP) pour visualiser les regroupements.
Figure : projection t-SNE d'embeddings. Source : Wikimedia Commons (CC BY-SA).
Mesurer la proximité
La similarité se mesure le plus souvent par le cosinus de l'angle entre deux vecteurs : proche de 1, les sens se ressemblent ; proche de 0, ils sont indépendants.
function cosine(a: number[], b: number[]): number {
let dot = 0, na = 0, nb = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i]! * b[i]!; na += a[i]! ** 2; nb += b[i]! ** 2;
}
return dot / (Math.sqrt(na) * Math.sqrt(nb));
}
Le produit scalaire tient compte de la direction ET de la magnitude (et est plus rapide) ; sur des vecteurs normalisés (longueur 1), produit scalaire et cosinus coïncident exactement, et la distance euclidienne donne le même classement. Règle pratique : utilisez la métrique avec laquelle le modèle a été entraîné, normalisez de bout en bout, et « en cas de doute, choisissez le cosinus ». Un mismatch de normalisation (index normalisé, requête brute) corrompt silencieusement le classement.
Recherche vectorielle et ANN
Comparer la requête à chaque vecteur (kNN exact) donne un rappel de 100 % mais coûte O(N·d) — intenable à des millions de vecteurs. Les index ANN (Approximate Nearest Neighbors) échangent un peu d'exactitude contre d'énormes gains de vitesse/mémoire. Le compromis central est rappel ↔ latence ↔ mémoire, réglé par paramètres.
- HNSW : un graphe de petit monde multi-couches. La recherche part d'un point d'entrée en haut, saute vers les voisins plus proches, puis descend des couches grossières vers les fines. Paramètres :
M(voisins par nœud) etef(largeur de recherche) — plus élevés = meilleur rappel, plus coûteux. - IVF : on partitionne en
nlistcellules (k-means) et on ne sonde quenprobecellules à la requête. - PQ / quantification : on découpe le vecteur en sous-vecteurs remplacés par des identifiants de centroïdes — jusqu'à ~64× de compression, au prix d'une chute de rappel à surveiller.
Figure : index HNSW. Source : Wikimedia Commons (CC BY).
Bases de données vectorielles
Une base vectorielle stocke les embeddings + leurs métadonnées et sert des requêtes ANN à faible latence à grande échelle (pgvector, Qdrant, Weaviate, Pinecone ; FAISS étant la bibliothèque d'index sous-jacente à beaucoup). Fonctions clés : index ANN, filtrage par métadonnées, recherche hybride (vecteurs + BM25), partitions/namespaces. Règle d'or : le même modèle des deux côtés — indexer les documents et encoder la requête avec le même modèle, sous peine de casser la géométrie partagée.
Choisir un modèle d'embedding
Quelques critères :
- Dimension : plus de dimensions = souvent meilleure qualité, mais plus de stockage. Les modèles Matryoshka (Gemini, OpenAI v3) permettent de tronquer (ex. 3072 → 768) avec peu de perte.
- Longueur de contexte : doit dépasser la taille de vos chunks, sinon le texte est tronqué silencieusement (MiniLM ~256, Cohere v3 512, OpenAI v3 8191 tokens).
- Multilingue : Cohere multilingual et Gemini couvrent 100+ langues et la recherche cross-lingue (requête FR, documents EN) — précieux ici.
- MTEB : un benchmark de 56 jeux × 8 types de tâches, jusqu'à 112 langues. Mise en garde : aucun modèle ne domine partout — choisissez selon VOTRE tâche (la récupération ≠ la similarité de phrases), votre langue et votre latence, pas le sommet du classement global.
Cas d'usage
Recherche sémantique et RAG (chunker → embarquer → stocker → récupérer le top-k par similarité pour ancrer le LLM), mais aussi clustering et découverte de thèmes, déduplication, recommandation, classification et reranking. Le chunking est de premier ordre : trop gros, un chunk devient trop générique pour matcher ; trop petit, il perd sa cohérence.
Pièges fréquents
- Mismatch de modèle : indexer et interroger avec des modèles (ou versions) différents donne des espaces incompatibles — ré-encodez tout en changeant de modèle.
- Bugs de normalisation : stocker des vecteurs normalisés et interroger en brut dégrade silencieusement le classement.
- Métrique inadaptée : utiliser l'euclidien sur un modèle optimisé pour le cosinus.
- Gap de domaine et dérive : un modèle généraliste sous-performe sur le jargon spécialisé ; les distributions dérivent dans le temps — surveillez, et envisagez un fine-tuning.
- Excès de confiance dans le classement : un bon rang MTEB ne garantit pas la meilleure performance sur votre tâche, votre langue ou votre latence.
En somme : un embedding transforme le sens en géométrie, et la recherche vectorielle exploite cette géométrie à l'échelle — à condition de garder le même modèle des deux côtés, la bonne métrique, et la recherche hybride comme valeur sûre en production.