Cómo integrar Transformers.js en una extensión Chrome bajo MV3
Este artículo explica cómo diseñar una extensión Chrome que aloje modelos con Transformers.js bajo las restricciones de Manifest V3. Verán la arquitectura recomendada (service worker, panel lateral y content script), el manejo de modelos y consideraciones prácticas para producción.
Introducción
Hugging Face publicó un demo de Transformers.js que muestra cómo ejecutar un asistente en el navegador usando Gemma 4 E2B. La implementación combina un service worker en el background, un panel lateral para chat y un content script para interactuar con la página. En esta guía adaptada revisamos las decisiones de arquitectura, cómo y dónde correr la inferencia, el ciclo de descarga y cache, y las piezas de mensajería que permiten organizar todo bajo Manifest V3.
El ejemplo público está disponible en la Chrome Web Store y su código fuente en GitHub: github.com/nico-martin/gemma4-browser-extension.
Qué construiremos
Al final de este artículo tendrán el diseño arquitectónico usado en el proyecto referenciado: un motor de Transformers.js alojado en el background, un panel lateral para la interfaz conversacional y un content script que extrae y resalta contenido en la página. No profundizaremos en la capa UI (React/Vite), sino en cómo se distribuyen responsabilidades y se comunican los componentes dentro de MV3.
Arquitectura de la extensión (MV3)
Puntos de entrada y contextos
En Manifest V3 todo arranca desde public/manifest.json. En el ejemplo se definen tres entradas principales:
- service_worker de background (background.js) construido desde src/background/background.ts
- side_panel con default_path apuntando a sidebar.html (src/sidebar/index.html)
- content_scripts que inyectan content.js en páginas con matches http(s):/// y run_at: document_idle (src/content/content.ts)
El service worker también responde a chrome.action.onClicked para abrir el panel lateral en la pestaña activa. Opcionalmente se puede usar action.default_popup para acciones rápidas; el patrón de orquestación es el mismo si se elige popup en lugar de panel lateral.
Qué corre en cada contexto
La regla de diseño clave es mantener la orquestación pesada en el background y dejar la UI y el content script lo más livianos posible:
- Background: plano de control. Aquí vive el ciclo de vida del agente, la inicialización de modelos, la ejecución de herramientas y servicios compartidos como extracción de features.
- Side panel: capa de interacción. Entrada y salida de chat, streaming de respuestas y controles de configuración.
- Content script: puente con la página. Extracción del DOM, resaltar elementos y responder a comandos de la UI.
Una consecuencia práctica es que el historial de conversación se mantiene en el background (por ejemplo Agent.chatMessages): la UI envía comandos como AGENT_GENERATE_TEXT, el background agrega el mensaje, ejecuta la inferencia y luego emite MESSAGES_UPDATE para que el panel se renderice. Este enfoque evita cargas duplicadas de modelos y reduce la carga de memoria.
Contrato de mensajería
Cuando se separan runtimes, la mensajería es fundamental. En el proyecto los mensajes están tipados (src/shared/types.ts) y siguen un contrato claro:
- Side panel -> background (BackgroundTasks): CHECK_MODELS, INITIALIZE_MODELS, AGENT_INITIALIZE, AGENT_GENERATE_TEXT, AGENT_GET_MESSAGES, AGENT_CLEAR, EXTRACT_FEATURES
- Background -> side panel (BackgroundMessages): DOWNLOAD_PROGRESS, MESSAGES_UPDATE
- Background -> content (ContentTasks): EXTRACT_PAGE_DATA, HIGHLIGHT_ELEMENTS, CLEAR_HIGHLIGHTS
Regla de orquestación: el background es el coordinador único; el panel y el content script son workers especializados que piden acciones y muestran resultados. Flujo típico: el panel envía AGENT_GENERATE_TEXT → el background actualiza Agent.chatMessages y ejecuta pasos del modelo/herramientas → el background emite MESSAGES_UPDATE → el panel vuelve a renderizar.
Integración de Transformers.js
Modelos y responsabilidades
El ejemplo usa dos roles de modelo definidos en src/shared/constants.ts:
- TextGeneration / LLM: onnx-community/gemma-4-E2B-it-ONNX (texto, q4f16)
- VectorEmbeddings: onnx-community/all-MiniLM-L6-v2-ONNX (feature-extraction, fp32)
La separación es intencional: Gemma 4 maneja razonamiento y decisiones de herramienta, mientras que MiniLM genera embeddings para búsquedas semánticas (por ejemplo en ask_website y find_history).
Dónde corre la inferencia
Toda la inferencia se ejecuta en el background (src/background/background.ts):
- Generación de texto con pipeline(“text-generation”, …) usando un KV Caching consistente (implementado con una clase DynamicCache en el proyecto)
- Embeddings con pipeline(“feature-extraction”, …) y normalización de vectores
Tener un host de modelos centralizado evita duplicar memoria entre pestañas y mantiene la UI ágil. Además, como los artefactos se cargan desde el origin de la extensión (chrome-extension://<extension-id>), la cache es compartida por toda la instalación de la extensión en lugar de quedar por sitio web.
Importante: bajo MV3 los service workers pueden suspenderse y reiniciarse; por eso cualquier estado del runtime de modelos debe considerarse recuperable y re-inicializarse cuando sea necesario.
Ciclo de descarga y cache
El proyecto expone un flujo explícito para la gestión de modelos:
- CHECK_MODELS inspecciona qué ya está cacheado y estima el tamaño restante a descargar.
- INITIALIZE_MODELS descarga e inicializa modelos y emite DOWNLOAD_PROGRESS para la UI.
Esto permite mostrar al usuario el progreso y evitar sorpresas de ancho de banda. Los desarrolladores deben prever que las descargas pueden interrumpirse y diseñar reintentos o estimaciones que sean claras para el usuario.
Agente, herramientas y flujo de ejecución
La lógica de agentes y la ejecución de herramientas corre en el background. En esencia, el agente decide cuándo invocar herramientas (por ejemplo extracción de página o búsquedas en historial), y luego orquesta la llamada a los modelos y la agregación de resultados. Mantener esta capa en el service worker centraliza la lógica y las dependencias.
El diseño usado en el proyecto mantiene mensajes del agente en el background y permite que la UI reciba actualizaciones continuas (streaming), lo que mejora la sensación de interactividad sin exigir que la UI ejecute modelos localmente.
Límites de datos y persistencia
Algunos puntos de diseño relevantes:
- El historial de conversación se guarda en el background para evitar inconsistencias y cargas duplicadas.
- La cache de modelos está vinculada al origin chrome-extension://…, lo que permite un cache compartido entre pestañas.
- Debido al ciclo de vida de MV3, no se debe confiar en que un service worker retenga estado indefinidamente; diseñen re-inicialización y estrategias de persistencia cuando sea necesario.
- CHECK_MODELS ayuda a estimar descargas restantes, útil en entornos con limitaciones de ancho de banda.
Consejos prácticos para equipos en América Latina
- Bandwidth y costos: muchos usuarios y equipos en la región tienen planes de datos limitados; exponer estimaciones de descarga y permitir descargas diferidas o por red Wi‑Fi mejora la adopción.
- Hardware: la ejecución local de modelos ONNX puede ser intensiva en CPU; valorar la experiencia en dispositivos móviles y equipos de gama baja.
- Privacidad y cumplimiento: alojar modelos en la extensión evita enviar datos a servidores externos, pero siempre comunique claramente cómo se procesan y almacenan los datos locales para cumplir con políticas y expectativas de usuarios.
- UX: ofrecer un fallback claro si el service worker se reinicia (por ejemplo un indicador de reconexión) mejora la percepción de confiabilidad.
Notas de empaquetado y evaluación final
- Evaluar si un panel lateral o un popup encaja mejor con su caso de uso: el panel es ideal para sesiones persistentes.
- Recuerden que MV3 impone restricciones al ciclo de vida del service worker; diseñen la re-inicialización de modelos como parte natural del flujo.
- Mantener la carga pesada en el background simplifica la UI y reduce problemas de seguridad alrededor del DOM.
Conclusión
Transformers.js permite llevar capacidades de LLM y embeddings directamente al navegador. Bajo Manifest V3, la arquitectura recomendada es un background service worker que actúe como host de modelos y coordinador, una UI ligera en un panel lateral y un content script para acciones sobre la página. Esta separación reduce duplicidad de recursos, facilita la gestión de cache y ofrece una experiencia más consistente —consideraciones clave para equipos y productos en América Latina donde la conectividad y el hardware pueden variar ampliamente.
Fuente original: Hugging Face Blog