Intermedio 12 minPlan diario

WebLLM: un modelo de IA en el navigateur

WebLLM: un modelo de IA en el navigateur

WebLLM es una biblioteca de JavaScript que ejecuta un LLM en la pestaña del navegador, en la GPU del equipo, gracias a WebGPU. No hay que instalar nada en el sistema, pero hay tres condiciones que comprobar: la compatibilidad del navegador, la descarga del modelo y el comportamiento real de la página. Que un cálculo se ejecute en tu GPU no demuestra que la página funcione sin conexión ni que tus mensajes se queden en tu equipo. Esta guía explica cómo comprobarlo; no contiene ningún benchmark.

Por Mohamed Meguedmi·Actualización 2026-11-09·Probado en Windows, macOS y Linux
!
Límite de esta guía
No se pudieron revisar el repositorio de WebLLM ni su documentación el día de la redacción, el 9 de noviembre de 2026, y QuelLLM no ha ejecutado ningún código de esta guía. Los fragmentos de WebLLM describen la API tal como la conocemos, sin garantía de versión: si hay diferencias, prevalece el README del repositorio. La información sobre WebGPU, el almacenamiento y la política de seguridad procede de MDN, revisado el 9 de noviembre de 2026.

#WebLLM: lo que hace la biblioteca

Con Ollama, un programa instalado en la máquina carga el modelo y responde en http://localhost:11434. Con WebLLM, todo pasa por una página web: esta carga el código JavaScript y WebAssembly del motor, obtiene los pesos del modelo y luego envía los cálculos a la GPU mediante WebGPU. No hay ningún servicio que iniciar ni ningún puerto que abrir.

Para el desarrollador, la API sigue la forma de la de OpenAI: se crea un motor y luego se llama a engine.chat.completions.create con una lista de mensajes. Por eso, una aplicación escrita para este formato se adapta con bastante rapidez. Sin embargo, el motor vive dentro de la página: no es un servidor HTTP al que puedan conectarse Open WebUI, un editor de código o un script de Python.

WebGPU
API del navegador que da acceso a la GPU para el cálculo. Sin ella, o sin un adaptador disponible, el motor no puede funcionar en la GPU.
WebAssembly
Formato en el que se distribuye una parte del motor. Forma parte de lo que la página debe cargar, igual que el JavaScript.
Los pesos del modelo
Archivos voluminosos, independientes del código de la página. Se descargan desde la dirección indicada en la configuración y luego el navegador los guarda en caché.
El formato MLC
WebLLM utiliza modelos compilados para su motor, reconocibles por el sufijo MLC en sus identificadores. Un archivo GGUF descargado para Ollama o LM Studio no se carga tal cual.

#WebLLM o Ollama: ¿qué herramienta para cada necesidad?

El kit completo para crear tu propio asistente de IA.

Aprovecha nuestra experiencia y un recorrido guiado para crear tu asistente local y usar tu IA en el día a día.

  • Espacio en línea de por vida
  • PDF + archivos
  • Reembolsado 30 d

WebLLM no sustituye a una instalación local clásica. Su valor está en otra parte: ofrecer una función de IA en una página a personas que no van a instalar nada.

WebLLM es adecuado para
Una demostración pública, una herramienta web interna, un asistente integrado en una aplicación, una prueba rápida en un equipo donde no se puede instalar nada.
Ollama o LM Studio son adecuados para
Un uso diario, la elección entre un amplio catálogo, modelos más grandes, una API reutilizable por otras herramientas, un funcionamiento que no depende de los límites de una pestaña.
Los costes que hay que asumir
El catálogo depende de los modelos compilados en formato MLC, la memoria disponible depende también de los límites del navegador y la caché puede borrarse sin avisarte.

No ofrecemos una comparación de velocidad: ninguna medición con protocolo y hardware documentados respalda esta guía. Si es importante para tu proyecto, mide en tus máquinas de destino, con el mismo modelo y la misma cuantización, anotando la versión del navegador y del controlador.

#Requisitos previos y compatibilidad con WebGPU

MDN seguía clasificando WebGPU con disponibilidad limitada, es decir, no Baseline, en su página modificada el 2 de septiembre de 2026: la API no funciona en algunos navegadores muy utilizados. La compatibilidad depende de la combinación de navegador, sistema y controlador gráfico. Por tanto, un navegador puede exponer WebGPU en un sistema y no en otro. En lugar de una lista de versiones que caduca rápido, consulta la tabla de compatibilidad de MDN y luego prueba cada máquina de destino.

Contexto seguro
Según MDN, toda la API solo está disponible en un contexto seguro: sirve la página por HTTPS, o en localhost durante el desarrollo. Una página abierta por HTTP en una dirección de red local no sirve.
Navegador y controlador
Ambos actualizados. Una GPU reciente no basta si el controlador o el navegador bloquean el acceso.
Memoria de la GPU
Referencias de QuelLLM en Q4 con la pila habitual: 3B, unos 2 GB; 7B, unos 5 GB. Son órdenes de magnitud, no mediciones de WebLLM.
Espacio en disco y conexión
Lo necesario para almacenar el modelo y descargarlo al menos una vez. Comprueba el tamaño real en el seguimiento de la carga.

Esta prueba se pega en la consola de las herramientas de desarrollo, en una página con HTTPS o en localhost. Se basa en la API estándar y no carga ningún modelo. Según MDN, requestAdapter devuelve null cuando no hay ningún adaptador adecuado disponible: por tanto, la presencia de navigator.gpu no basta para sacar conclusiones.

Consola del navegador: probar 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 línea shader-f16 te ayuda a elegir la variante. Los identificadores de WebLLM suelen distinguir entre modelos q4f16, que requieren esta función, y q4f32, que no la necesitan. Los dos límites de búfer indican lo que el navegador acepta asignar; pueden bloquear un modelo grande aunque la tarjeta tenga memoria suficiente.

#Lo que implica la descarga

En la primera carga, la página obtiene los archivos del modelo y el código compilado asociado desde las direcciones de su configuración. En la lista predefinida de WebLLM, según nuestra información, estas direcciones apuntan a repositorios externos como Hugging Face y GitHub: compruébalo en la pestaña Red. Estos proveedores ven entonces tu dirección IP y el modelo solicitado, aunque todavía no se haya enviado ningún mensaje.

Después, los archivos se conservan en el almacenamiento del navegador, vinculado al origen de la página. MDN detalla las reglas que hay que conocer: por defecto, este almacenamiento funciona en modo best-effort, y el navegador puede desalojarlo cuando falta espacio en disco sin interrumpir al usuario, empezando por los orígenes usados menos recientemente. Un origen desalojado pierde todos sus datos de golpe. Safari también puede eliminar los datos creados por script de un origen sin interacción durante siete días de uso del navegador, cuando la prevención del seguimiento entre sitios está activa.

Consola de la página: cuota y almacenamiento persistente
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);
→
Solicitar la persistencia no garantiza nada
Firefox muestra una solicitud al usuario; Chrome, Edge y Safari deciden por su cuenta, según el historial de interacción con el sitio (MDN, página modificada el 5 de enero de 2026). Si persist devuelve false, ten previsto que el modelo pueda tener que descargarse de nuevo.

#Instalar WebLLM en una página: los pasos

Este recorrido supone un proyecto JavaScript con una herramienta de build, por ejemplo Vite. Instalar el paquete en el proyecto, en lugar de importarlo desde un CDN, evita añadir un dominio de terceros a la carga de la página y facilita el funcionamiento sin conexión.

Terminal, en tu proyecto
npm install @mlc-ai/web-llm
  1. 01
    Fijar la versión
    Anota la versión instalada en package-lock.json y lee el README correspondiente. Comprueba en ese momento la licencia del paquete y la del modelo, que son dos cosas distintas.
  2. 02
    Listar los modelos disponibles
    No copies un identificador de un artículo: la lista cambia. Consúltala en la versión instalada, con el primer fragmento de abajo. El campo de memoria que indica sirve como punto de partida, no como garantía.
  3. 03
    Empezar poco a poco
    Elige primero el modelo útil más pequeño, en q4f32 si la prueba anterior indica que falta shader-f16. Un primer intento exitoso separa los problemas de código de los problemas de memoria.
  4. 04
    Mostrar el progreso
    La descarga puede tardar. Sin indicación visual, la página parece bloqueada: initProgressCallback proporciona el texto de progreso que mostrar.
  5. 05
    Pasar a un Web Worker
    La carga y la generación pueden entorpecer la interfaz si se ejecutan en el hilo principal. Para ello, WebLLM ofrece CreateWebWorkerMLCEngine, con el gestor WebWorkerMLCEngineHandler en el lado del worker. Tenlo previsto antes de publicar.
  6. 06
    Probar en las máquinas de destino
    Un resultado en una estación de desarrollo no dice nada de un portátil con GPU integrada. Prevé un mensaje claro si falta WebGPU, en lugar de una página en blanco.
Listar los modelos de la versión instalada
import { prebuiltAppConfig } from '@mlc-ai/web-llm';

console.table(prebuiltAppConfig.model_list.map((m) => ({
  id: m.model_id,
  vramMo: m.vram_required_MB,
})));
Cargar un modelo y leer la respuesta en streaming
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);

#Verificar una página WebLLM: red, scripts, sin conexión

Como mucho, WebLLM garantiza dónde se ejecuta el cálculo. El resto depende de la página que lo integra: un script de analítica, un widget o una función de envío puede leer el contenido del campo de entrada y transmitirlo, ya que cualquier script cargado en la página tiene acceso a ella. Esta comprobación se aplica a cualquier sitio que anuncie una IA en el navegador, incluido el tuyo.

  1. 01
    Preparar un perfil limpio
    Abre un perfil de navegador sin extensiones: una extensión con permiso en la página puede leer lo que se muestra en ella y falsea el resultado. Abre la pestaña Red y activa la conservación del registro.
  2. 02
    Registrar la carga
    Carga la página y anota cada dominio contactado y su función: página, motor, modelo, fuente tipográfica, analítica de audiencia, publicidad. Cualquier dominio sin una función clara queda pendiente de explicar.
  3. 03
    Registrar el envío de un mensaje
    Una vez cargado el modelo, vacía el registro. Envía un mensaje que contenga un marcador inventado, por ejemplo TEST-MARQUEUR-7Q2X, y búscalo en el registro con la búsqueda de la pestaña Red. Examina también cada solicitud enviada durante la generación, incluidos los mensajes WebSocket.
  4. 04
    Inspeccionar los scripts y el encabezado de seguridad
    En la pestaña Sources, enumera los dominios de origen de los scripts. En los encabezados de respuesta del documento, busca Content-Security-Policy: una directiva connect-src estricta reduce los destinos posibles; su ausencia no demuestra nada.
  5. 05
    Revisar lo que queda en el disco
    En la pestaña Aplicación o Almacenamiento, abre IndexedDB, Cache y el almacenamiento local. Normalmente el modelo aparece ahí, pero tus conversaciones también pueden estar ahí, en texto claro para cualquiera que use esa sesión.
  6. 06
    Cortar realmente la red
    Cierra la página, desactiva el Wi-Fi o desconecta el cable y, después, vuelve a abrir la dirección y envía un mensaje nuevo. La página debe cargarse y responder. Repite la prueba después de cerrar el navegador.
!
Un modelo en caché no hace que la página funcione sin conexión
Si el HTML, el JavaScript o el WebAssembly de la página no se conservan también, normalmente mediante un service worker, la dirección ya no se abrirá sin red, aunque tengas todo el modelo en el disco. Por eso, un motor ya abierto que sigue respondiendo después del corte no demuestra que funcione sin conexión: lo único que cuenta es la prueba de volver a abrir la página.

Estas comprobaciones tienen sus límites. Que no se encuentre un marcador no descarta un envío cifrado o codificado por un script. Las conexiones WebRTC no aparecen como solicitudes normales en la pestaña Red: en Chrome, chrome://webrtc-internals permite detectarlas. Por último, el resultado solo es válido para la versión probada, porque el responsable del sitio puede cambiar sus scripts en cualquier momento.

Puedes decir «funciona sin conexión»
Si la reapertura y un nuevo mensaje funcionan con la red desconectada, en el navegador probado, en la fecha de la prueba. Indica que la caché puede ser desalojada.
Puedes decir «no se ha observado ningún envío»
Si el registro no muestra ninguna solicitud relacionada con el mensaje, en la versión probada y según el protocolo descrito. Es una observación fechada.
No puedes decir «totalmente privado»
Salvo que controles todo el código servido y sus actualizaciones, sin ningún script de terceros, y completes esta comprobación con una lectura del código. Incluso en ese caso, el proveedor que aloja el modelo ve la descarga y las extensiones siguen siendo un riesgo.

#Servirlo todo desde tu dominio

Para una herramienta interna, la configuración más fácil de controlar consiste en servir la página, el motor y el modelo desde el mismo origen, sin ningún script de terceros. WebLLM acepta una configuración personalizada en la que cada modelo indica la dirección de sus pesos y la de su biblioteca compilada. Las rutas siguientes son ejemplos que debes adaptar.

Configuración personalizada (direcciones de ejemplo)
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 });

El motor construye por sí mismo las direcciones de los archivos a partir de este prefijo. Puede esperar una estructura de directorios similar a la de Hugging Face: si algunas solicitudes fallan con 404, revisa en la pestaña Red las rutas exactas solicitadas y reprodúcelas en tu servidor. La biblioteca compilada debe corresponder al modelo: no la combines con otro al azar.

Una vez que lo tengas todo alojado en tu servidor, una política de seguridad puede convertir una promesa en una restricción técnica: según MDN, connect-src limita, entre otros, fetch, XMLHttpRequest, WebSocket, EventSource y sendBeacon, y recurre a default-src si no está definida. El siguiente ejemplo no se ha probado con WebLLM. Despliégalo primero en modo Content-Security-Policy-Report-Only y revisa la consola.

Encabezado HTTP, para adaptar a tu página
Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'

Este encabezado también bloquea las descargas desde Hugging Face: es intencionado, y en ese caso el modelo debe servirse desde tu dominio. No cubre todas las salidas posibles, como una navegación hacia otra dirección. Para el modo sin conexión, añade un service worker que almacene en caché los archivos de la página. WebLLM también ofrece un motor para este contexto, CreateServiceWorkerMLCEngine: consulta su README.

#Solución de problemas

navigator.gpu es undefined
Primero verifica la dirección: HTTPS o localhost. Después consulta la tabla de compatibilidad de MDN para tu navegador y tu sistema, y luego actualiza ambos.
requestAdapter devuelve null
La API existe, pero no hay ningún adaptador adecuado disponible. Actualiza el controlador y comprueba que la aceleración por hardware del navegador esté activada. Prueba otro navegador para aislar la causa.
Error relacionado con shader-f16
El modelo elegido requiere una función que tu adaptador no tiene. Usa su variante q4f32 si existe.
QuotaExceededError
Se ha superado la cuota del origen: MDN indica este error para IndexedDB, Cache y OPFS. Libera espacio o elige un modelo más pequeño, y captura el error en el código.
Bloqueo al final de la carga o pérdida de la GPU
Probablemente la memoria es insuficiente o se alcanzó el límite del búfer. Cierra las pestañas pesadas, baja un tamaño de modelo y consulta el mensaje exacto en la consola.
El modelo se vuelve a descargar
Navegación privada, desalojo del almacenamiento, datos del sitio borrados o cambio de origen, porque cada dominio tiene su propio almacenamiento. Según nuestra información, el paquete expone hasModelInCache para comprobarlo antes de iniciar la carga.
La interfaz se congela durante la generación
El motor se ejecuta en el hilo principal. Cambia a CreateWebWorkerMLCEngine.
Error de política de seguridad en la consola
El mensaje indica la directiva y la dirección bloqueadas. Comprueba si esa dirección es legítima antes de ampliar la regla, sobre todo si anuncias una página sin envíos externos.

#Para ir más allá

Si buscas un asistente para ti en lugar de una función integrada en una página, una instalación local clásica será más fácil de controlar: la comparativa de soluciones gratuitas es el punto de partida adecuado. Para un uso sensible, completa las comprobaciones de esta guía con la checklist de privacidad.

¿Esta guía te ha ayudado?

¿Un comentario, un error, una precisión? Avísanos, eso mejora la guía para todos.