WebLLM : un modèle IA dans le navigateur

WebLLM est une bibliothèque JavaScript qui exécute un LLM dans l'onglet du navigateur, sur le GPU de la machine, grâce à WebGPU. Rien à installer côté système, mais trois conditions à vérifier : la compatibilité du navigateur, le téléchargement du modèle et le comportement réel de la page. Un calcul exécuté sur votre GPU ne prouve ni que la page fonctionne hors ligne ni que vos messages restent chez vous. Ce guide explique comment le contrôler ; il ne contient aucun benchmark.
#WebLLM : ce que fait la bibliothèque
Avec Ollama, un programme installé sur la machine charge le modèle et répond sur http://localhost:11434. Avec WebLLM, tout passe par une page web : celle-ci charge le code JavaScript et WebAssembly du moteur, récupère les poids du modèle, puis envoie les calculs au GPU via WebGPU. Il n'y a ni service à lancer ni port à ouvrir.
Côté développeur, l'API suit la forme de celle d'OpenAI : on crée un moteur, puis on appelle engine.chat.completions.create avec une liste de messages. Une application écrite pour ce format s'adapte donc assez vite. Le moteur vit toutefois dans la page : ce n'est pas un serveur HTTP sur lequel Open WebUI, un éditeur de code ou un script Python pourraient se brancher.
- WebGPU
- API du navigateur qui donne accès au GPU pour le calcul. Sans elle, ou sans adaptateur disponible, le moteur ne peut pas fonctionner sur le GPU.
- WebAssembly
- Format dans lequel est livrée une partie du moteur. Il fait partie de ce que la page doit charger, au même titre que le JavaScript.
- Les poids du modèle
- Fichiers volumineux, distincts du code de la page. Ils sont téléchargés depuis l'adresse indiquée dans la configuration, puis mis en cache par le navigateur.
- Le format MLC
- WebLLM utilise des modèles compilés pour son moteur, reconnaissables au suffixe MLC de leurs identifiants. Un fichier GGUF téléchargé pour Ollama ou LM Studio ne se charge pas tel quel.
#WebLLM ou Ollama : quel outil pour quel besoin ?
Profite de notre expérience et d’un parcours guidé pour créer ton assistant local et utiliser ton IA au quotidien.
- Espace en ligne à vie
- PDF + fichiers
- Remboursé 30 j
WebLLM ne remplace pas une installation locale classique. Sa valeur est ailleurs : proposer une fonction d'IA dans une page, à des personnes qui n'installeront rien.
- WebLLM convient pour
- Une démonstration publique, un outil web interne, un assistant intégré à une application, un essai rapide sur un poste où l'on ne peut rien installer.
- Ollama ou LM Studio conviennent pour
- Un usage quotidien, le choix parmi un large catalogue, de plus gros modèles, une API réutilisable par d'autres outils, un fonctionnement qui ne dépend pas des limites d'un onglet.
- Les coûts à accepter
- Le catalogue dépend des modèles compilés au format MLC, la mémoire disponible dépend aussi des limites du navigateur, et le cache peut être effacé sans vous prévenir.
Nous ne donnons pas de comparaison de vitesse : aucune mesure avec protocole et matériel documentés n'étaye ce guide. Si cela compte pour votre projet, mesurez sur vos machines cibles, avec le même modèle et la même quantification, en notant la version du navigateur et du pilote.
#Prérequis et compatibilité WebGPU
MDN classait encore WebGPU en disponibilité limitée, donc non Baseline, sur sa page modifiée le 2 septembre 2026 : l'API ne fonctionne pas dans certains navigateurs très utilisés. Le support dépend de la combinaison du navigateur, du système et du pilote graphique. Un navigateur peut donc exposer WebGPU sur un système et pas sur un autre. Plutôt qu'une liste de versions vite périmée, consultez le tableau de compatibilité de MDN, puis testez chaque machine visée.
- Contexte sécurisé
- Selon MDN, toute l'API n'est disponible qu'en contexte sécurisé : servez la page en HTTPS, ou en localhost pendant le développement. Une page ouverte en HTTP sur une adresse de réseau local ne convient pas.
- Navigateur et pilote
- À jour tous les deux. Un GPU récent ne suffit pas si le pilote ou le navigateur bloque l'accès.
- Mémoire GPU
- Repères QuelLLM en Q4 sur la pile habituelle : 3B environ 2 Go, 7B environ 5 Go. Ce sont des ordres de grandeur, pas des mesures WebLLM.
- Espace disque et connexion
- De quoi stocker le modèle et le télécharger au moins une fois. Contrôlez la taille réelle dans le suivi de chargement.
Ce test se colle dans la console des outils de développement, sur une page en HTTPS ou en localhost. Il repose sur l'API standard et ne charge aucun modèle. D'après MDN, requestAdapter renvoie null lorsqu'aucun adaptateur approprié n'est disponible : la présence de navigator.gpu ne suffit donc pas à conclure.
La ligne shader-f16 aide à choisir la variante. Les identifiants WebLLM distinguent en général des modèles q4f16, qui exigent cette fonction, et q4f32, qui s'en passent. Les deux limites de tampon renseignent sur ce que le navigateur accepte d'allouer ; elles peuvent bloquer un gros modèle même si la carte possède assez de mémoire.
#Ce que le téléchargement implique
Au premier chargement, la page récupère les fichiers du modèle et le code compilé associé depuis les adresses de sa configuration. Dans la liste préconstruite de WebLLM, ces adresses pointent, à notre connaissance, vers des dépôts externes comme Hugging Face et GitHub : contrôlez-le dans l'onglet Réseau. Ces hébergeurs voient alors votre adresse IP et le modèle demandé, même si aucun message n'est encore parti.
Les fichiers sont ensuite conservés dans le stockage du navigateur, rattaché à l'origine de la page. MDN précise les règles à connaître : par défaut, ce stockage est en mode best-effort, et le navigateur peut l'évincer sous pression disque sans interrompre l'utilisateur, en commençant par les origines utilisées le moins récemment. Une origine évincée perd toutes ses données d'un coup. Safari peut aussi supprimer les données créées par script d'une origine sans interaction depuis sept jours d'utilisation du navigateur, quand la prévention du suivi intersite est active.
#Installer WebLLM dans une page : les étapes
Ce parcours suppose un projet JavaScript avec un outil de build, par exemple Vite. Installer le paquet dans le projet, plutôt que l'importer depuis un CDN, évite d'ajouter un domaine tiers au chargement de la page et facilite le fonctionnement hors ligne.
- 01Figer la versionNotez la version installée dans package-lock.json et lisez le README correspondant. Vérifiez à ce moment la licence du paquet et celle du modèle, qui sont deux choses distinctes.
- 02Lister les modèles proposésNe recopiez pas un identifiant depuis un article : la liste évolue. Lisez-la dans la version installée, avec le premier extrait ci-dessous. Le champ de mémoire qu'elle indique sert de point de départ, pas de garantie.
- 03Commencer petitChoisissez d'abord le plus petit modèle utile, en q4f32 si le test précédent indique que shader-f16 manque. Un premier essai réussi sépare les problèmes de code des problèmes de mémoire.
- 04Afficher la progressionLe téléchargement peut être long. Sans retour visuel, la page paraît bloquée : initProgressCallback fournit le texte d'avancement à afficher.
- 05Passer dans un Web WorkerLe chargement et la génération peuvent gêner l'interface s'ils s'exécutent dans le fil principal. WebLLM propose pour cela CreateWebWorkerMLCEngine, avec le gestionnaire WebWorkerMLCEngineHandler côté worker. Prévoyez-le avant la mise en ligne.
- 06Tester sur les machines ciblesUn résultat sur une station de développement ne dit rien d'un portable à GPU intégré. Prévoyez un message clair si WebGPU manque, plutôt qu'une page vide.
#Vérifier une page WebLLM : réseau, scripts, hors ligne
WebLLM garantit au mieux où le calcul s'exécute. Le reste dépend de la page qui l'embarque : un script de mesure d'audience, un widget ou une fonction d'envoi peut lire le contenu du champ de saisie et le transmettre, car tout script chargé dans la page a accès à celle-ci. Ce contrôle vaut pour tout site qui annonce une IA dans le navigateur, y compris le vôtre.
- 01Préparer un profil propreOuvrez un profil de navigateur sans extension : une extension autorisée sur la page peut lire ce qui s'y affiche et fausse le résultat. Ouvrez l'onglet Réseau et activez la conservation du journal.
- 02Relever le chargementChargez la page, puis notez chaque domaine contacté et son rôle : page, moteur, modèle, police, mesure d'audience, publicité. Tout domaine sans rôle clair reste à expliquer.
- 03Relever l'envoi d'un messageUne fois le modèle chargé, videz le journal. Envoyez un message contenant un marqueur inventé, par exemple TEST-MARQUEUR-7Q2X, puis cherchez-le dans le journal avec la recherche de l'onglet Réseau. Examinez aussi chaque requête partie pendant la génération, messages WebSocket compris.
- 04Inspecter les scripts et l'en-tête de sécuritéDans l'onglet Sources, listez les domaines d'origine des scripts. Dans les en-têtes de réponse du document, cherchez Content-Security-Policy : une directive connect-src stricte réduit les destinations possibles, son absence ne prouve rien.
- 05Regarder ce qui reste sur le disqueDans l'onglet Application ou Stockage, ouvrez IndexedDB, Cache et le stockage local. Le modèle y figure normalement, mais vos conversations peuvent s'y trouver aussi, en clair pour quiconque utilise cette session.
- 06Couper vraiment le réseauFermez la page, désactivez le Wi-Fi ou débranchez le câble, puis rouvrez l'adresse et envoyez un nouveau message. La page doit se charger et répondre. Recommencez après avoir fermé le navigateur.
Ces contrôles ont leurs limites. Un marqueur introuvable n'exclut pas un envoi chiffré ou encodé par un script. Les connexions WebRTC n'apparaissent pas comme des requêtes ordinaires dans l'onglet Réseau : sur Chrome, chrome://webrtc-internals permet de les repérer. Le résultat ne vaut enfin que pour la version testée, car l'exploitant du site peut changer ses scripts à tout moment.
- Vous pouvez dire « fonctionne hors ligne »
- Si la réouverture et un nouveau message réussissent réseau coupé, sur le navigateur testé, à la date du test. Précisez que le cache peut être évincé.
- Vous pouvez dire « aucun envoi observé »
- Si le journal ne montre aucune requête liée au message, sur la version testée et selon le protocole décrit. C'est une observation datée.
- Vous ne pouvez pas dire « totalement privé »
- Sauf à maîtriser tout le code servi et ses mises à jour, sans aucun script tiers, et à compléter ce contrôle par une lecture du code. Même dans ce cas, l'hébergeur du modèle voit le téléchargement et les extensions restent un risque.
#Tout servir depuis son domaine
Pour un outil interne, la configuration la plus facile à contrôler consiste à servir la page, le moteur et le modèle depuis la même origine, sans aucun script tiers. WebLLM accepte une configuration personnalisée dans laquelle chaque modèle indique l'adresse de ses poids et celle de sa bibliothèque compilée. Les chemins ci-dessous sont des exemples à adapter.
Le moteur construit lui-même les adresses des fichiers à partir de ce préfixe. Il peut attendre une arborescence semblable à celle de Hugging Face : si des requêtes échouent en 404, regardez dans l'onglet Réseau les chemins exacts demandés et reproduisez-les sur votre serveur. La bibliothèque compilée doit correspondre au modèle : ne l'associez pas à un autre au hasard.
Une fois tout rapatrié, une politique de sécurité peut transformer une promesse en contrainte technique : d'après MDN, connect-src limite notamment fetch, XMLHttpRequest, WebSocket, EventSource et sendBeacon, et se rabat sur default-src s'il est absent. L'exemple suivant n'a pas été testé avec WebLLM. Déployez-le d'abord en mode Content-Security-Policy-Report-Only et lisez la console.
Cet en-tête bloque aussi les téléchargements depuis Hugging Face : c'est voulu, et le modèle doit alors être servi par votre domaine. Il ne couvre pas toutes les sorties possibles, comme une navigation vers une autre adresse. Pour le hors ligne, ajoutez un service worker qui met en cache les fichiers de la page. WebLLM fournit aussi un moteur pour ce contexte, CreateServiceWorkerMLCEngine : reportez-vous à son README.
#Dépannage
- navigator.gpu vaut undefined
- Vérifiez d'abord l'adresse : HTTPS ou localhost. Consultez ensuite le tableau de compatibilité de MDN pour votre navigateur et votre système, puis mettez les deux à jour.
- requestAdapter renvoie null
- L'API existe, mais aucun adaptateur approprié n'est disponible. Mettez à jour le pilote et vérifiez que l'accélération matérielle du navigateur est active. Essayez un autre navigateur pour isoler la cause.
- Erreur liée à shader-f16
- Le modèle choisi exige une fonction absente de votre adaptateur. Prenez sa variante q4f32 si elle existe.
- QuotaExceededError
- Le quota de l'origine est dépassé : MDN signale cette erreur pour IndexedDB, Cache et OPFS. Libérez de la place ou prenez un modèle plus petit, et capturez l'erreur dans le code.
- Plantage en fin de chargement ou perte du GPU
- Mémoire probablement insuffisante ou limite de tampon atteinte. Fermez les onglets lourds, descendez d'une taille de modèle et consultez le message exact dans la console.
- Le modèle se retélécharge
- Navigation privée, éviction du stockage, données de site effacées, ou changement d'origine, car chaque domaine a son propre stockage. Le paquet expose, à notre connaissance, hasModelInCache pour le vérifier avant de lancer le chargement.
- L'interface se fige pendant la génération
- Le moteur tourne dans le fil principal. Passez à CreateWebWorkerMLCEngine.
- Erreur de politique de sécurité dans la console
- Le message nomme la directive et l'adresse bloquées. Vérifiez si cette adresse est légitime avant d'élargir la règle, surtout si vous annoncez une page sans envoi externe.
#Pour aller plus loin
Si vous cherchez un assistant pour vous-même plutôt qu'une fonction intégrée à une page, une installation locale classique sera plus simple à contrôler : le comparatif des solutions gratuites est le bon point de départ. Pour un usage sensible, complétez les contrôles de ce guide par la checklist de confidentialité.
Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.