Intermédiaire 12 minPlan quotidien

WebLLM : un modèle IA dans le navigateur

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.

Par Mohamed Meguedmi·Màj 2026-11-09·Testé sur Windows, macOS, Linux
!
Limite de ce guide
Le dépôt de WebLLM et sa documentation n'ont pas pu être relus le jour de la rédaction, le 9 novembre 2026, et aucun code de ce guide n'a été exécuté par QuelLLM. Les extraits WebLLM décrivent l'API telle que nous la connaissons, sans version garantie : le README du dépôt fait foi s'il diffère. Les éléments sur WebGPU, le stockage et la politique de sécurité viennent de MDN, relu le 9 novembre 2026.

#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 ?

Le kit complet pour créer ton propre assistant IA.

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.

Console du navigateur : tester WebGPU
if (!navigator.gpu) {
  console.log('WebGPU absent : navigateur non compatible, API désactivée ou contexte non sécurisé');
} else {
  const adapter = await navigator.gpu.requestAdapter();
  if (!adapter) {
    console.log('API présente, mais aucun adaptateur disponible');
  } else {
    console.log('shader-f16 :', adapter.features.has('shader-f16'));
    console.log('maxBufferSize :', adapter.limits.maxBufferSize);
    console.log('maxStorageBufferBindingSize :', adapter.limits.maxStorageBufferBindingSize);
  }
}

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.

Console de la page : quota et stockage persistant
const { usage, quota } = await navigator.storage.estimate();
console.log('Utilisé :', usage, 'octets sur un quota estimé de', quota);

const persistant = await navigator.storage.persist();
console.log('Stockage persistant accordé :', persistant);
→
Demander la persistance ne garantit rien
Firefox affiche une demande à l'utilisateur ; Chrome, Edge et Safari décident seuls, selon l'historique d'interaction avec le site (MDN, page modifiée le 5 janvier 2026). Si persist renvoie false, prévoyez que le modèle puisse être téléchargé à nouveau.

#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.

Terminal, dans votre projet
npm install @mlc-ai/web-llm
  1. 01
    Figer la version
    Notez 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.
  2. 02
    Lister les modèles proposés
    Ne 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.
  3. 03
    Commencer petit
    Choisissez 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.
  4. 04
    Afficher la progression
    Le téléchargement peut être long. Sans retour visuel, la page paraît bloquée : initProgressCallback fournit le texte d'avancement à afficher.
  5. 05
    Passer dans un Web Worker
    Le 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.
  6. 06
    Tester sur les machines cibles
    Un 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.
Lister les modèles de la version installée
import { prebuiltAppConfig } from '@mlc-ai/web-llm';

console.table(prebuiltAppConfig.model_list.map((m) => ({
  id: m.model_id,
  vramMo: m.vram_required_MB,
})));
Charger un modèle et lire la réponse en flux
import { CreateMLCEngine } from '@mlc-ai/web-llm';

// Remplacez par un identifiant relevé dans la liste ci-dessus
const modelId = 'IDENTIFIANT_DU_MODELE';

const engine = await CreateMLCEngine(modelId, {
  initProgressCallback: (p) => console.log(p.text),
});

const stream = await engine.chat.completions.create({
  messages: [{ role: 'user', content: 'Explique WebGPU en deux phrases.' }],
  stream: true,
});

let reponse = '';
for await (const chunk of stream) {
  reponse += chunk.choices[0]?.delta?.content || '';
}
console.log(reponse);

#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.

  1. 01
    Préparer un profil propre
    Ouvrez 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.
  2. 02
    Relever le chargement
    Chargez 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.
  3. 03
    Relever l'envoi d'un message
    Une 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.
  4. 04
    Inspecter 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.
  5. 05
    Regarder ce qui reste sur le disque
    Dans 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.
  6. 06
    Couper vraiment le réseau
    Fermez 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.
!
Un modèle en cache ne rend pas la page hors ligne
Si le HTML, le JavaScript ou le WebAssembly de la page ne sont pas eux aussi conservés, typiquement par un service worker, l'adresse ne s'ouvrira plus sans réseau, même avec tout le modèle sur le disque. Un moteur déjà ouvert qui continue de répondre après la coupure ne prouve donc pas le fonctionnement hors ligne : seul le test de réouverture compte.

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.

Configuration personnalisée (adresses d'exemple)
import { CreateMLCEngine } from '@mlc-ai/web-llm';

const appConfig = {
  model_list: [{
    model: 'https://outil.example.fr/modeles/mon-modele/',
    model_id: 'mon-modele',
    model_lib: 'https://outil.example.fr/libs/mon-modele.wasm',
  }],
};

const engine = await CreateMLCEngine('mon-modele', { appConfig });

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.

En-tête HTTP, à adapter à votre page
Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'

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é.

Ce guide vous a aidé ?

Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.