Entraînée sur des clichés. À ne pas prendre au sérieux.
6 / 16
Sous le capot
Qu'est-ce qui s'est passé pendant la démo ?
Vous tapez
« la pétanque »
?
La page répond
Un camp + un score
Dans la boîte, deux briques. La première transforme le texte en nombres. La seconde tranche.
7 / 16
Brique 1 : l'embedding
Une carte du sens
Un embedding, ce sont les coordonnées d'un texte sur une carte du sens.
Chaque point est un texte. Ceux qui parlent de la même chose se retrouvent ensemble. Sens proches, positions proches.
« la pétanque », pour de vrai : 768 nombres
[-0.0880, -0.0350, …, 0.0046]
Tout un talk là-dessus : « Embeddings : Symfony AI en pratique », AFUP Day 2026 · speakerdeck.com/lyrixx
8 / 16
Brique 2 : la régression logistique
Tracer un trait sur la carte
au début
en cours
après 2 000 tours
côté gauche
côté droit
nouveau texte
1. On part de ~970 exemples classés à la main. Chacun est placé sur la carte, en rouge ou en bleu. Et on pose un trait au hasard.
2. À chaque tour, on corrige. On regarde les points du mauvais côté et on tourne ou décale un peu le trait. C'est la descente de gradient.
3. Après 2 000 tours, le trait est calé. C'est ça, l'entraînement. Jamais parfait : un point reste du mauvais côté.
4. Un nouveau texte ? Son côté donne le camp, sa distance au trait le score. Loin, c'est sûr. Près, l'aiguille hésite.
En vrai, pas un trait en 2D mais un hyperplan en 768 dimensions : 768 poids pour son orientation, 1 biais pour sa position.
9 / 16
Récap
Deux briques, zéro serveur
Un texte
« la pétanque »
Brique 1
Le placer sur la carte
EmbeddingGemma, 197 Mo, téléchargé une fois
Brique 2
De quel côté du trait ?
768 poids + 1 biais, un JSON de quelques Ko
Réponse
Un camp + un score
On trace le trait une fois, dans Node. Ensuite, tout tourne dans votre navigateur.
10 / 16
Leçon n°1
Quatre fois plus d'exemples, à peine mieux
253 exemples
~67 % de bonnes réponses
972 exemples
~70 % de bonnes réponses
Plus d'exemples, c'est plus de points. Mais ils restent là où la carte les met : dans la zone en pointillés, les deux camps sont mélangés, et aucun trait ne peut les séparer.
Le goulot d'étranglement, c'est la carte.
Bonnes réponses mesurées sur des exemples cachés pendant l'entraînement. Points dessinés pour l'exemple.
11 / 16
Leçon n°2
Changer de carte, ça change tout
Modèle d'embeddings
Taille
Bonnes réponses sur des exemples cachés
multilingual-e5-small · 1er choix
118 Mo
~70 %
multilingual-e5-large
562 Mo
~76 %
Snowflake Arctic Embed v2
311 Mo
~77 %
EmbeddingGemma · choix final
197 Mo
~80 %
Qwen3-Embedding 0.6B
614 Mo
~80 %
Mesuré sur des exemples cachés pendant l'entraînement, les mêmes pour tous les modèles. Chiffres arrondis.
12 / 16
Leçon n°3
Du prompt engineering… pour un embedding
Texte envoyé à Qwen3
Bonnes réponses
la raclette
~80 %
Les gens qui aiment la raclette votent pour
~89 %
Qwen3-Embedding vient d'un LLM : sa position sur la carte est calculée à partir du dernier mot. Finissez la phrase par « votent pour », et il anticipe probablement… un parti.
Sur les modèles classiques, reformuler ne change rien (±1 point). Et Qwen3 pèse 614 Mo.
13 / 16
Leçon n°4
Sans exemples, c'est pile ou face
Pas d'exemples, pas de trait : on regarde juste si le texte est plus près de « de gauche » ou de « de droite » sur la carte. (Le « zero-shot ».)
48-60 %
de bonnes réponses. Une pièce de monnaie fait 50 %.
Sur la carte, « de droite », c'est aussi… le côté droit.
Jev, lui, promet de trancher sans exemples. Respect.
14 / 16
Les pièges du navigateur
Ça marchait pourtant dans Node
GatherBlockQuantized
La version compressée du modèle (q4) utilise une opération que le moteur WebAssembly ne sait pas exécuter.
→ Une variante sans cette opération, pour l'entraînement ET pour le site.
COOP / COEP
Sans ces en-têtes HTTP, pas de multi-thread. GitHub Pages ne les envoie pas : un seul cœur, ~1 s par calcul, la page gèle.
→ wasm.proxy = true : le calcul part dans un Web Worker.
submit()
Envoyer pendant le téléchargement rechargeait la page… et relançait les 200 Mo.