Ce qu'il faut retenir.
- Le modèle « model2vec » (potion-base-8M) réduit la recherche sémantique à un tableau de correspondance de 29 528 tokens : ni couche, ni attention, ni inférence, juste une moyenne de vecteurs normalisée.
- Comparée à un vrai transformeur (MiniLM via Transformers.js : 23,45 Mo et environ 2 secondes de chargement), la table quantifiée en int8 pèse environ 4 Mo et reproduit le modèle original à une similarité cosinus de 0,999958.
- Tout se calcule côté client à partir d'un fichier JSON généré au moment du build : aucun serveur, aucune API de LLM, aucun coût d'inférence, ce qui rend la technique directement exploitable sur un site statique.
Résumé généré par IA
Le développeur néerlandais Bart de Goede a documenté, sur son blog technique, la recette complète d'un moteur de recherche sémantique qui pèse environ 4 Mo une fois compressé, tourne entièrement dans le navigateur du visiteur et ne dépend ni d'un serveur, ni d'une API de LLM, ni d'une carte graphique. Pas d'abonnement, pas de clé API à faire fuiter, pas de facture qui grimpe avec le trafic.
Pour un blog, une documentation technique ou un catalogue de contenus hébergé en statique, c'est la promesse d'ajouter une vraie compréhension du sens des requêtes (chercher « désastre alcoolisé en Angleterre » et tomber sur un article qui parle d'une inondation de bière, sans que le mot « désastre » y figure) sans ouvrir le moindre port serveur. Voici comment la technique fonctionne, et ce qu'elle change concrètement si vous gérez un site en Astro, Hugo, Jekyll ou 11ty.
Le problème de départ : chercher des mots, pas du sens
Sur son propre blog, Bart de Goede utilisait depuis huit ans Lunr.js pour la recherche : un index inversé généré au moment du build, exporté en JSON, puis interrogé directement dans le navigateur. Cela fonctionne, à condition que le mot tapé par le visiteur figure mot pour mot dans l'article. Tapez un synonyme ou une reformulation, et vous obtenez zéro résultat, même si l'article traite exactement du sujet recherché.
Plus tôt cette année, il avait aussi codé un moteur de recherche sémantique en environ 250 lignes de Python, basé sur des modèles de type sentence-transformers comme all-MiniLM-L6-v2. Problème : ce genre de modèle a besoin de PyTorch et de plusieurs centaines de mégaoctets de dépendances, et pour le servir en production il faut une machine capable d'encaisser cette charge. Rien de compatible avec un site statique hébergé gratuitement.
La solution : un modèle qui n'est plus un réseau de neurones, mais un tableau
C'est là qu'intervient une famille de modèles appelée model2vec, dont les variantes portent le nom de code « potion ». Ces modèles sont distillés à partir d'un vrai sentence-transformer, mais le résultat final n'a plus rien d'un réseau de neurones : c'est une table de correspondance. Le calcul complet, du texte au vecteur, tient en quatre étapes : découper le texte en tokens, aller chercher la ligne correspondante dans la table pour chaque token, faire la moyenne de ces lignes, puis normaliser le vecteur obtenu. Pas de couche d'attention, pas d'inférence : juste des lookups dans un tableau et une moyenne.
Pour la variante potion-base-8M, cette table fait 29 528 tokens sur 256 dimensions en float32, soit environ 30 Mo, et atteint 81 % de la qualité de recherche de MiniLM. C'est nettement moins précis qu'un vrai transformeur, mais largement suffisant pour indexer un blog ou une documentation, et sans commune mesure en termes de poids et de rapidité.
Les chiffres qui font la différence
- Transformers.js (MiniLM quantifié + runtime WebAssembly) : 23,45 Mo téléchargés, environ 2 secondes de chargement, puis environ 18 ms pour encoder une requête.
- La table model2vec en float32 : environ 30 Mo, ramenée à environ 4 Mo une fois quantifiée en int8, soit un quart du poids d'origine.
- Fidélité de la quantification : une similarité cosinus de 0,999958 avec le modèle original. La version compressée renvoie donc quasiment les mêmes résultats de recherche que la version complète.
Le détail le plus intéressant tient dans la façon dont le modèle encode déjà, sans qu'on le lui demande, une forme de liste de mots vides. En triant les tokens de potion-base-8M par la longueur de leur vecteur, les plus courts sont des mots comme « le », « la », « et » ou « de », tandis que les plus longs sont des mots rares et distinctifs. Autrement dit, le modèle a appris tout seul qu'un mot courant ne doit presque pas peser dans la moyenne, alors qu'un mot rare doit dominer le vecteur final. C'est cette propriété qui permet de compresser la table sans perdre grand-chose : les mots qui comptent vraiment gardent une magnitude suffisante même après quantification.
Comment ça se construit concrètement : chunking et tokenizer maison
Les vecteurs sont calculés au moment du build, pas à la volée. Un script découpe chaque article en supprimant le front matter et les blocs de code, puis le fractionne en morceaux d'environ 600 caractères avec chevauchement. Ce découpage n'est pas un détail : comme le vecteur final est une moyenne, encoder un article entier de 15 000 caractères en un seul vecteur noie les mots rares et spécifiques sous la masse des mots courants. En travaillant sur des chunks plus courts, les mots distinctifs gardent du poids dans la moyenne, et la recherche reste pertinente.
Cette étape se fait une seule fois au moment du build, pas chez le visiteur. Le fichier de vecteurs qui en résulte est ensuite téléchargé par le navigateur au moment où l'utilisateur clique dans le champ de recherche, pas au chargement de la page.
Reste un dernier morceau : transformer la requête tapée par le visiteur en tokens, exactement comme lors de la génération de l'index. Cela suppose de réimplémenter en JavaScript le tokenizer WordPiece utilisé par BERT, ce qui tient en une centaine de lignes mais cache plusieurs pièges : ne pas ajouter les tokens spéciaux de début et de fin de séquence que model2vec n'utilise pas, gérer le cas où un mot inconnu est purement supprimé de la séquence plutôt que remplacé par un vecteur générique, et faire attention à la configuration qui contrôle la suppression des accents, dont le comportement par défaut n'est pas celui qu'on croit lire dans le fichier de configuration. Trois détails silencieux, mais chacun suffit à fausser une requête si on ne les traite pas.
Notre lecture chez CZSyn
Cette approche nous semble particulièrement pertinente pour les sites que nous développons chez CZSyn : sites vitrines, blogs d'entreprise, documentations techniques ou catalogues de contenus hébergés en statique sur Astro, Hugo ou équivalent. Les solutions de recherche sémantique existantes reposent en général soit sur une API d'embeddings facturée à l'appel, soit sur un service tiers hébergé qui ajoute une dépendance et un coût récurrent. Ici, tout le calcul se fait une fois pour toutes au moment du build, et le visiteur télécharge quelques mégaoctets qui tournent ensuite localement, sans latence réseau et sans quota à surveiller.
Pour une PME française avec un site vitrine ou un blog de quelques dizaines d'articles, le gain concret est double : une recherche qui comprend enfin les synonymes et les reformulations, et une facture d'infrastructure qui reste à zéro. Le compromis, c'est une qualité de recherche inférieure à celle d'un vrai modèle de langage (81 % de la qualité de MiniLM selon les mesures de l'auteur), ce qui reste largement suffisant pour indexer un catalogue éditorial, mais mérite d'être testé avant d'être déployé sur un site où la précision de recherche a un impact direct sur les conversions.
Le point qui nous intéresse le plus, en tant qu'agence qui livre du code destiné à durer, c'est la philosophie de fond : avant d'aller chercher une API tierce ou un service payant, il vaut la peine de vérifier si le problème ne peut pas se résoudre avec quelques kilo-octets bien pensés au moment du build. Ce n'est pas toujours le cas, mais quand ça l'est, c'est nettement plus simple à maintenir sur la durée.
Vous voulez ajouter une recherche intelligente à votre site sans exploser votre budget infra ?
Nous développons des sites sur-mesure et des fonctionnalités IA légères, pensées pour tourner sans serveur additionnel. Audit gratuit sous 24h.
29 AVIS 5/5 · +200 PROJETS LIVRÉS · RÉPONSE EXPRESS
Sources primaires
- Bart de Goede, « Client-side semantic search for your static site ».
- MinishLab, dépôt officiel model2vec.
- Hugging Face, documentation officielle Transformers.js.
