🔍
Les Text Embeddings en pratique : construire un système de recommandation de contenu en cold-start

Les Text Embeddings en pratique : construire un système de recommandation de contenu en cold-start

Note: Cet article a été traduit avec Claude Code le 1 mars 2026. La version originale est disponible ici.

Au cours de l’année passée, les text embeddings sont devenus au cœur de mon travail sur l’amélioration des systèmes de recommandation. Les tutoriels sur les text embeddings couvrent bien la théorie, mais le déploiement en production soulève des questions sans réponse sur la sélection des modèles, l’architecture de stockage et la validation.

Cet article rassemble ce que j’ai appris au cours de ce processus. Je vais présenter un cas d’usage réaliste — la construction d’un système de contenu connexe pour une plateforme de streaming vidéo — et montrer les choix pratiques auxquels vous serez confronté : sélection des modèles, choix du stockage, validation des résultats, et déploiement de quelque chose que les parties prenantes peuvent réellement tester.

Commençons par les fondamentaux des text embeddings.

Text Embeddings : concepts fondamentaux et contexte historique

Qu’est-ce qu’un text embedding ?

Un text embedding est un vecteur ; formellement, c’est une représentation d’un texte sous forme de vecteur dans un espace latent multidimensionnel. Comme tout vecteur, le texte embarqué est représenté par une direction et une magnitude, positionnant les textes dont le sens ou les caractéristiques sont similaires plus proches les uns des autres. Word2Vec illustre cela par l’arithmétique vectorielle : les vecteurs de Roi - Homme + Femme approximent Reine, illustrant les relations sémantiques apprises par un embedding (mappées à des opérations géométriques).

king queen schema from https://dev.to/mshojaei77/from-words-to-vectors-a-gentle-introduction-to-word-embeddings-4mia

Évolution des méthodes d’embedding

Pour créer des représentations capturant les caractéristiques d’un texte, il existe plusieurs approches qui ont suivi l’évolution de la puissance de calcul. Ces approches peuvent analyser un seul mot, une phrase ou un document entier. Chaque approche mérite une exploration détaillée ; voici un regroupement permettant de comprendre leur évolution et leurs compromis :

  • Méthodes basées sur les comptes (1950–2010s) : ces méthodes représentent les mots ou les documents sous forme de vecteurs creux de haute dimension basés sur les fréquences des mots ou les statistiques de co-occurrence.
  • Embeddings prédictifs (début des années 2010) : apparus avec la résurgence des réseaux de neurones, apprenant des représentations vectorielles denses qui prédisent les mots à partir du contexte.
  • Embeddings contextuels (fin des années 2010) : produisant des représentations qui varient selon le texte environnant.
  • Embeddings de documents (années 2020) : une nouvelle évolution des embeddings prédictifs, conçus pour représenter des documents entiers plutôt que des mots individuels.

Pipeline texte vers embedding

Malgré leurs différences, toutes les approches d’embedding suivent un pipeline commun pour transformer le texte en représentations vectorielles, composé des étapes suivantes :

  1. Normalisation du texte : normaliser le texte standardise l’entrée avant l’embedding.
    • Mots-clés : mise en minuscules, suppression de la ponctuation, racinisation
  2. Tokenisation : les machines ne peuvent pas vraiment comprendre le texte brut tel quel, il doit d’abord être segmenté en unités plus petites appelées tokens que les modèles peuvent traiter. Le texte peut être tokenisé à différents niveaux (caractère, sous-mot ou mot complet) offrant un niveau d’encodage (et d’information) différent.
    • Mots-clés : niveau mot/sous-mot, Byte Pair Encoding (BPE), Wordpiece
  3. Indexation du vocabulaire : pour chaque modèle d’embedding, il existe un vocabulaire associé qui mappe chaque token connu possible à un tokenID. Appliqué au texte complet, cela donnera une séquence de tokenID.
    • Mots-clés : indexation par table de correspondance
  4. Vectorisation & pondération : cette étape transforme les identifiants de tokens discrets en vecteurs numériques. Elle mappe chaque token à une représentation de caractéristiques, dérivée de la fréquence statistique ou de paramètres appris selon le modèle, et affine ces valeurs pour capturer l’importance sémantique du token par rapport au texte ou à l’ensemble du jeu de données.
    • Mots-clés : embedding statique, table de correspondance
  5. Encodage & agrégation : agréger les représentations au niveau du token en un vecteur final représentant le texte.
    • Mots-clés : mean/max pooling, token CLS

Le pipeline exact varie selon l’approche. Les méthodes basées sur les comptes comme TF-IDF nécessitent un nettoyage et une normalisation explicites du texte, tandis que les modèles modernes basés sur les transformers gèrent en interne la sensibilité à la casse et la ponctuation.

Maintenant que la génération d’embeddings est couverte, parlons de notre cas d’usage réel.

Découverte de contenu en cold-start

Pour ce cas d’usage, je jouerai le rôle d’un data scientist faisant partie de l’équipe personnalisation et découvrabilité d’un service de streaming vidéo appelé Netprimey+. L’équipe travaille sur de nouvelles fonctionnalités pour la plateforme, et l’une des parties prenantes responsable de la page produit a formulé la demande suivante :

« Bonjour, nous devons repenser la section des éléments connexes sur une page de contenu. Actuellement, si le contenu dispose de données historiques, le système affiche les éléments les plus proches basés sur les embeddings issus du pipeline de filtrage collaboratif. S’il n’y a pas de données historiques, il affiche le contenu le plus populaire de la dernière heure. Nous voulons quelque chose qui ne repose pas sur les données historiques et qui peut relier un contenu à d’autres contenus en se basant sur des informations générales comme le casting, l’équipe de production et les détails du contenu lorsqu’un nouvel élément est disponible sur la plateforme. »

C’est une demande valide, et nous disposons déjà de beaucoup d’informations pour chaque contenu sur la plateforme. Parmi toutes ces données, il existe une description produit en anglais créée lors de l’ajout d’un élément. Cette description contient la plupart des informations mentionnées par la partie prenante, alors expérimentons avec elle.

Actuellement, nous avons un catalogue de plus de 200 000 contenus/éléments sur la plateforme. Voici quelques exemples de contenus :

Ce sont deux contenus avec des formats différents et de pays différents. Voici une illustration de leurs descriptions associées dans le système.

La question est maintenant : comment les embeddings permettraient-ils cette fonctionnalité ? En créant un embedding pour chaque description de contenu sur la plateforme. Le contenu connexe pour un élément donné sera le vecteur le plus proche dans l’index d’embedding.

L’approche étant définie, le prochain défi est de choisir quel modèle d’embedding utiliser parmi les milliers disponibles.

Sélection du modèle

En 2025, voici quelques bons points de départ si vous souhaitez travailler avec des embeddings :

Le benchmark MTEB

Il existe actuellement plus de 18 000 modèles disponibles sur la plateforme Hugging Face compatibles avec sentence-transformers. La question est de savoir comment choisir le bon modèle. Pour y répondre, prenons du recul et voyons comment un modèle d’embedding est créé.

Les modèles d’embedding sont optimisés pour des tâches spécifiques, dans un contexte spécifique défini par les langues, les domaines et les tailles de texte. Par exemple, certains modèles sont entraînés sur des corpus en anglais pour regrouper des textes similaires, ce qui est exactement ce que nous voulons faire ici.

La sélection du modèle devrait prioriser les données d’entraînement correspondant à votre langue cible, au vocabulaire du domaine et à la longueur typique des documents, mais l’espace des tâches est vaste ; j’ai regroupé les tâches les plus courantes en trois familles :

  • Tâches d’analyse : comprendre un texte en testant les embeddings sur des tâches de classification, de résumé ou de clustering
  • Tâches comparatives : comprendre des textes ensemble en testant les embeddings sur des tâches de similarité textuelle sémantique (STS), de minage bilingue ou de classification par paires
  • Tâches de recherche et découverte : trouver un texte parmi un grand nombre d’autres textes, incluant la récupération, la récupération par instruction et le reranking

Dans ce contexte, comment trouver encore le bon modèle ? Hugging Face et ses contributeurs ont créé le Massive Text Embedding Benchmark (MTEB) et sa version multilingue MMTEB. Ils ont défini un pipeline pour évaluer les modèles sur divers jeux de données et tâches et exposent les métriques sur un classement public.

Si nous revenons au cas d’usage de la page de contenu connexe et examinons la configuration du benchmark pour trouver le bon modèle :

  • Le jeu de données : il est composé majoritairement de mots anglais, mais il y a aussi des noms d’acteurs ou de personnages dans la langue d’origine du film. Les descriptions ont des longueurs variables mais ne dépassent pas 700 mots, et la plupart du temps elles font moins de 100 mots.

  • La tâche : trouver un contenu connexe basé sur des descriptions textuelles est une tâche de similarité textuelle sémantique (STS), car nous voulons mesurer à quel point deux descriptions sont similaires.

Choisir la taille du modèle

Au-delà des performances MTEB pures, les contraintes de production influencent significativement le choix de la taille du modèle. Pour référence, un petit modèle désigne ici un modèle de moins de 500 millions de paramètres avec des embeddings de moins d’un millier de dimensions.

Le bon choix dépend de votre type de charge de travail.

Inférence en temps réel (recherche ou chat orientés utilisateur)

Optez par défaut pour un petit modèle. Les grands modèles introduisent une latence qui nuira à l’expérience utilisateur à moins que vous ne disposiez d’une capacité GPU importante. Deux conditions imposent automatiquement un petit modèle, quoi qu’il arrive : une exigence de latence inférieure à 100 ms, et un matériel CPU uniquement ou à VRAM limitée. Le seul cas où un grand modèle se justifie en temps réel est lorsque vos données contiennent de longs documents (>512 tokens) ou du jargon technique dense — et que vous disposez de la capacité GPU pour absorber le coût.

Traitement par lots / indexation hors ligne

Là encore, commencez petit. Paralléliser un petit modèle sur des CPU bon marché ou de petits GPU battra presque toujours un seul grand modèle en débit. Passez à un grand modèle uniquement lorsque la précision est votre seul KPI et que vous indexez rarement — le calcul supplémentaire devient un coût unique pour des gains de qualité permanents. Les préoccupations de coût de stockage ou de base de données penchent également vers le petit.

Du live au batch inference, il peut y avoir beaucoup d’autres conditions qui s’appliquent au cas d’usage que vous mettez en place. J’ai essayé de compiler celles qui me semblent les plus importantes, ainsi qu’un ordre de grandeur de taille de modèle à garder en tête.

Condition Recommandation
Temps réel — latence < 100 ms requise Petit
Temps réel — CPU uniquement ou VRAM limitée Petit
Temps réel — longs documents (>512 tokens) + GPU disponible Grand
Batch — minimiser le temps d’indexation Petit
Batch — les coûts de stockage ou de BDD sont un enjeu Petit
Batch — indexation unique, la précision est le seul KPI Grand

La vie n’est pas binaire

Au-delà de la distinction entre petit et grand modèle, leur taille, leur nombre de paramètres, etc., il y a aussi une chose à garder à l’esprit : la méthode utilisée pour entraîner ces modèles, car certains sont plus efficaces que d’autres. Par exemple, le Matryoshka Representation Learning (MRL) — les modèles entraînés avec MRL produisent des embeddings où les N premières dimensions capturent la majeure partie de l’information sémantique, vous permettant de tronquer un vecteur de 768 dimensions à 128 ou 256 dimensions avec une perte de qualité minimale.

Ma sélection pour l’exploration de la découverte de contenu

Pour le PoC, j’ai décidé de choisir deux modèles à comparer et tester :

  • sentence-transformers/all-MiniLM-L6-v2 : un modèle d’embedding populaire sur Hugging Face utilisé dans de nombreux tutoriels. Il est uniquement en anglais et peut traiter des textes jusqu’à 256 word pieces, selon la fiche du modèle.
  • google/embeddinggemma-300m : l’un des nouveaux modèles Google Gemma. Ce modèle d’embedding textuel est léger, entraîné sur du texte web en plus de 100 langues, et peut gérer une longueur de contexte de 2048 tokens.

Ce ne sont pas les modèles les plus grands ou les mieux classés — ils sont classés 18 et 131 sur la tâche STS dans le classement MTEB en décembre 2025. Cependant, ils fonctionnent efficacement sur mon ordinateur portable, et je veux quelque chose de rapide pour prototyper une première itération et faire une comparaison simple. Voici une représentation du contenu sélectionné dans leur espace d’embedding, affichée sous forme de carte thermique. (inspiré par cet article de Stack Overflow)

Nous devons maintenant stocker 200 000 vecteurs quelque part où ils pourront être interrogés efficacement.

Stocker les embeddings avec une base de données vectorielle et l’indexation

L’embedding est un tableau composé de milliers de valeurs en virgule flottante, il peut donc facilement être stocké dans n’importe quelle base de données moderne supportant le stockage de tableaux. Cependant, ces dernières années, avec l’essor des LLM (Large Language Models) et des applications comme le RAG (Retrieval-Augmented Generation), un nouveau type de base de données est apparu : la base de données vectorielle.

Une base de données vectorielle est une base de données spécialisée qui stocke des vecteurs de haute dimension générés par des modèles d’embedding et les indexe pour une recherche de similarité efficace. Contrairement aux bases de données classiques qui utilisent des index pour des correspondances exactes ou des requêtes de plage (B-tree, hash) et retournent des résultats basés sur l’égalité ou des filtres, les bases de données vectorielles utilisent des index dédiés (tels que HNSW ou IVF) pour trouver rapidement les voisins les plus proches dans l’espace vectoriel, récupérant des données sémantiquement similaires plutôt qu’exactement correspondantes.

Demandez-vous d’abord si vous avez vraiment besoin d’une base de données vectorielle — pour les petits jeux de données (moins de 1 000 documents) ou les cas d’usage non orientés recherche, des solutions plus simples peuvent suffire.

Mais dans le cas d’une base de données vectorielle, lors de la sélection, vous devez vous concentrer sur le compromis entre la simplicité opérationnelle et les performances architecturales. De nombreuses entreprises proposent ce type de service, comme Pinecone, Qdrant, ou même les fournisseurs cloud avec leurs propres solutions. Bien que les éditeurs mettent en avant la latence des requêtes, le succès en production dépend davantage des capacités de filtrage des métadonnées et des performances de rappel sous charges réelles.

Il existe de nombreux benchmarks en ligne, comme par exemple celui de Qdrant. Chacun peut être biaisé, je vous recommande donc fortement de tester 2 à 3 bases de données vectorielles différentes sur votre propre cas d’usage pour voir laquelle répond le mieux à vos besoins.

Pour mon prototype, j’ai décidé de partir sur une configuration légère de type base de données vectorielle en utilisant un package appelé Voyager de Spotify, qui peut facilement être connecté avec sentence-transformers. Voici un extrait de code pour stocker des embeddings :

Quand vous mettez en place ce type de stockage pour les embeddings, il est important d’avoir un indexage incrémental pour suivre votre catalogue d’éléments. Au-delà du stockage de l’embedding dans la base de données, cela peut aussi aider lors de la construction de systèmes de recommandation pour d’autres techniques comme les algorithmes de filtrage collaboratif qui peuvent s’appuyer sur cet indexage pour la phase de factorisation matricielle. Il existe un extrait de code rapide montrant comment construire un index incrémental en PySpark. Vous pouvez faire quelque chose de similaire en Python pur ou dans tout autre langage.

Revenons à notre cas d’usage — trouver du contenu similaire nécessite des métriques de distance.

Métriques de similarité et validation

Les embeddings sont définis par leur magnitude et leur direction dans l’espace, une étape clé consiste donc à les comparer pour en extraire de l’information. Les principales mesures utilisées pour cette comparaison sont :

  • Similarité cosinus : calcule le cosinus de l’angle entre deux vecteurs et se concentre sur leur direction plutôt que sur leur magnitude.
  • Distance euclidienne : calcule la distance en ligne droite entre deux points dans l’espace vectoriel.
  • Produit scalaire : évalue la similarité en multipliant les composantes correspondantes et en sommant les résultats. Il combine les informations de magnitude et de direction.

Le choix de la métrique dépend de la tâche que vous souhaitez résoudre avec les embeddings. Pour les tâches STS, la similarité cosinus est préférée car elle mesure l’alignement sémantique indépendamment de la longueur du document, en se concentrant purement sur la similarité directionnelle dans l’espace vectoriel.

La normalisation joue un rôle clé ici : en normalisant les embeddings à une longueur unitaire, l’information de magnitude est supprimée et la similarité cosinus devient équivalente au produit scalaire, ce qui est utile lorsqu’on compare uniquement le sens. Cependant, dans les applications où la magnitude de l’embedding porte une information significative (par exemple, la rareté du contenu, la confiance ou l’importance), garder les embeddings non normalisés et utiliser le produit scalaire ou la distance euclidienne est plus approprié, car ces mesures prennent en compte la direction et la magnitude.

Dans notre cas de contenu connexe basé sur la description du contenu (un STS typique), la normalisation L2 est appropriée (la plupart des bibliothèques de modèles la gèrent par défaut) et la similarité cosinus est la bonne métrique pour cette tâche. Lorsque j’ai créé l’index avec Voyager, j’ai spécifiquement choisi un espace défini par la similarité cosinus, ce qui me permet d’interagir facilement avec tous les points de l’index en utilisant cette mesure.

Pour illustrer cela, j’avais deux scénarios de validation en tête pouvant soutenir la fonctionnalité de contenu connexe :

  • Obtenir les 5 contenus les plus proches d’un contenu donné
  • Obtenir les contenus les plus proches partagés par deux contenus

Extrayons donc les 5 contenus les plus proches avec chaque modèle d’embedding.

Comme on peut le voir, les voisins les plus proches de MiniLM semblent être davantage influencés par le début de la description, donnant souvent plus de poids au titre. En revanche, le modèle Gemma semble mieux capturer la description complète. Pour Astérix, il fait remonter des films avec de vrais acteurs et Alain Chabat, et pour l’exemple Superman, les résultats les plus proches sont des suites à venir qui partagent une partie du casting.

Si nous regardons maintenant les contenus les plus proches de notre sélection ensemble, nous avons calculé les meilleurs résultats avec les deux modèles.

Gemma semble prioriser le contenu animé lié à Superman, tandis que MiniLM retourne un mélange de résultats, incluant des animations plus anciennes comme Superman 1941 et Le Premier Combat des Chefs Astérix, ainsi que du contenu plus récent comme le documentaire Christopher Reeve : Superman Forever.

Les benchmarks publics comme MTEB mesurent les performances générales, mais ils ne vous diront pas si vos embeddings fonctionnent pour votre cas d’usage spécifique. Pour Netprimey+, nous avions besoin de savoir si « Astérix et Obélix » relie correctement à d’autres séries animées françaises — pas si le modèle obtient 0,85 sur des benchmarks académiques.

Construire un jeu de validation spécifique au domaine garantit que les fonctionnalités basées sur les embeddings répondent aux exigences métier, ce que les benchmarks génériques ne peuvent pas garantir, et cela peut prendre différentes formes selon votre cas d’usage. Pour le cas d’usage de Netprimey+, si je devais concevoir un jeu de données de validation, je le concevrais avec trois composantes en tête :

1. Paires positives : contenu qui devrait correspondre

  • Même franchise : « Breaking Bad » ↔ « El Camino »
  • Genre similaire : « Stranger Things » ↔ « The Umbrella Academy »

2. Paires négatives : contenu qui ne devrait pas correspondre malgré des similitudes de surface

  • Même acteur, genres différents : « En quête de bonheur » ↔ « Men in Black »
  • Titres similaires, émissions différentes : « The Office » (US) ↔ « The Office » (UK)

3. Cas limites : scénarios qui exposent les faiblesses du modèle

  • Multilingue : « La Casa de Papel » ↔ « Money Heist » (même série, langues différentes)
  • Remakes : Le Roi Lion (2019) ↔ Le Roi Lion (1994)

Au-delà de l’évaluation des performances, construire un jeu de données de validation pourrait également permettre le fine-tuning et la communication avec les parties prenantes via des exemples concrets.

Explorer et mettre en valeur l’espace des embeddings

Au-delà de la construction de classements et de comparaisons comme ceux-là, il y a aussi un aspect de représentation important à réaliser avec les embeddings dans un espace 2D pour qu’il puisse être interprété par un humain (ma précédente visualisation en carte thermique n’est pas très scalable à des milliers d’embeddings). Pour créer une visualisation où tous les embeddings peuvent coexister dans le même espace, vous pouvez utiliser une technique appelée réduction de dimensionnalité, qui réduit la dimensionnalité tout en préservant la structure basée sur les distances inter-embeddings. De nombreux algorithmes sont disponibles pour cela, comme PCA, t-SNE ou UMAP, mais cela mériterait un article dédié sur ce seul sujet (et sur la façon de choisir le bon).

De nos jours, UMAP est l’une des techniques les plus populaires d’après ce que je vois dans divers articles, et il existe une implémentation efficace en Python ici. J’ai appliqué un UMAP de base à mon jeu de données et voici une visualisation UMAP des descriptions en 2D pour les deux modèles.

Être capable d’explorer l’espace de vos embeddings est important, et disposer d’une certaine interactivité est également essentiel. Vous pouvez construire un outil pour soutenir cette exploration, mais j’ai récemment découvert qu’Apple a rendu open-source un package appelé Atlas qui fournit une interface pour explorer les embeddings. Le package peut gérer à la fois la création d’embeddings et la réduction de dimensionnalité, et il offre une interface claire pour explorer les embeddings réduits et toute information supplémentaire associée.

Un excellent point de départ si vous souhaitez explorer rapidement l’espace et les points que vous y avez construits. Mais explorer l’espace peut encore sembler un peu abstrait pour les parties prenantes, donc mon principal conseil est le suivant : déployez tôt une démo autonome de votre fonctionnalité, en utilisant vos embeddings. Une simple application web, accessible 24h/24 et 7j/7, vaut mieux qu’attendre l’intégration complète dans l’UI ou s’appuyer sur des exemples de notebooks. Ainsi, les parties prenantes peuvent la tester à tout moment, se faire une idée claire de son comportement et fournir des retours.

Pour le cas d’usage du contenu connexe, j’ai déployé un outil avec Streamlit et Hugging Face Space pour explorer le catalogue et simuler une page de contenu, montrant à quoi pourrait ressembler une ligne de contenu connexe :

(En version gratuite, je n’ai pas pu ajouter les index Gemma et MiniLM ensemble, mais l’idée est de donner à l’outil la capacité de choisir le mode d’embedding.)

Notes de clôture

Les text embeddings sont simples en surface, mais trouver le bon modèle pour effectuer la conversion et gérer le stockage vectoriel ne sont pas des détails à négliger. J’espère que cet article vous a donné quelques clés pour affiner votre sélection et aller au-delà de l’approche « plus grand modèle / plus de ressources ».

Je continue d’expérimenter activement avec les embeddings, vous pouvez donc vous attendre à des articles de suivi dans les prochains mois où j’approfondis le sujet.

Merci à Josiane Van Dorpe pour la relecture d’un brouillon de cet article.

Références