- Дата публикации
Локальный ИИ в Chrome: как запустить Transformers.js и Gemma 4 прямо в расширении
Что нового
Hugging Face показала рабочий пример браузерного ассистента на Transformers.js — это расширение для Chrome на Manifest V3, которое:
- Запускает локальный LLM Gemma 4 E2B (
onnx-community/gemma-4-E2B-it-ONNX, режимtext-generation, квантованиеq4f16) прямо в фоне браузера. - Дополнительно использует отдельную модель для эмбеддингов:
onnx-community/all-MiniLM-L6-v2-ONNX(feature-extraction,fp32) для семантического поиска по истории и текущей странице. - Разносит логику по трём контекстам Chrome:
- фоновый service worker с моделями и агентом,
- боковая панель с чатом,
- content script для чтения DOM и подсветки элементов.
- Строит единый движок Transformers.js в фоне, который обслуживает все вкладки и все окна браузера.
- Явно описывает протокол обмена сообщениями между частями расширения:
- задачи от боковой панели к фону,
- сообщения от фона к UI,
- команды от фона к content script.
- Даёт готовый каркас для «агентного» ассистента с инструментами: открытие и переключение вкладок, поиск по истории, анализ текущей страницы, подсветка нужных элементов.
Цифр по скорости, латентности и объёму контекста в проекте нет, но архитектура заточена под WebGPU и KV‑кэш, чтобы генерация шла быстрее и не пересчитывала весь контекст при каждом ответе.
Как это работает
Архитектура расширения (Manifest V3)
Точка входа — public/manifest.json. Проект задаёт три основных entry point:
- Фон:
background.service_worker = background.js(собирается изsrc/background/background.ts). - Боковая панель:
side_panel.default_path = sidebar.html(изsrc/sidebar/index.html). - Content script:
content_scripts[].js = content.jsсmatches: http(s)://*/*иrun_at: document_idle(изsrc/content/content.ts).
Фоновый service worker также подписан на chrome.action.onClicked, чтобы открывать боковую панель для активной вкладки. Вместо боковой панели можно было бы использовать action.default_popup, но в этом проекте делают ставку на постоянный чат сбоку.
Что где выполняется
Разработчики жёстко разделили ответственность между контекстами:
-
Background (
src/background/background.ts) — «центр управления полётами»:- инициализация и хранение моделей Transformers.js;
- запуск пайплайнов генерации текста и эмбеддингов;
- жизненный цикл агента (какие сообщения, какие инструменты, в каком порядке);
- исполнение инструментов (работа с вкладками, история, сайтами);
- общие сервисы, например feature extraction.
-
Боковая панель (
src/sidebar/*) — только интерфейс:- поле ввода, вывод чата;
- показ прогресса скачивания моделей;
- отображение обновлений сообщений в стриме.
-
Content script (
src/content/content.ts) — «мост» к странице:- чтение DOM и извлечение текста;
- подсветка элементов на странице;
- очистка подсветки.
История диалога хранится во фоне в Agent.chatMessages. UI отправляет события вроде AGENT_GENERATE_TEXT, фон добавляет сообщения, запускает инференс и шлёт назад MESSAGES_UPDATE. Это убирает дублирование моделей, разгружает UI и не нарушает ограничения Chrome на доступ к DOM.
Контракт сообщений между частями
Всё общение типизировано через enum’ы в src/shared/types.ts.
Боковая панель → фон (BackgroundTasks):
CHECK_MODELS— проверка, что уже закешировано, оценка оставшегося объёма скачивания.INITIALIZE_MODELS— скачивание и инициализация моделей с отправкой прогресса.AGENT_INITIALIZE— старт или сброс состояния агента.AGENT_GENERATE_TEXT— запрос на генерацию ответа.AGENT_GET_MESSAGES— запрос текущей истории.AGENT_CLEAR— очистка истории.EXTRACT_FEATURES— запрос на извлечение признаков (эмбеддингов).
Фон → боковая панель (BackgroundMessages):
DOWNLOAD_PROGRESS— прогресс скачивания и инициализации моделей.MESSAGES_UPDATE— обновлённый список сообщений для рендера в UI.
Фон → content script (ContentTasks):
EXTRACT_PAGE_DATA— вытащить данные со страницы.HIGHLIGHT_ELEMENTS— подсветить элементы по селекторам или другим признакам.CLEAR_HIGHLIGHTS— убрать подсветку.
Правило простое: фон — единственный координатор. Боковая панель и content script — «рабочие», которые делают запросы и отображают результаты.
Интеграция Transformers.js
Проект использует две роли моделей, описанные в src/shared/constants.ts:
-
Генерация текста / LLM:
onnx-community/gemma-4-E2B-it-ONNX- задача
text-generation - квантование
q4f16 - запуск через
pipeline("text-generation", ...)наwebgpu.
-
Векторные эмбеддинги:
onnx-community/all-MiniLM-L6-v2-ONNX- задача
feature-extraction fp32
Gemma 4 отвечает за рассуждение и выбор инструментов. MiniLM — за векторные представления текста для семантического поиска в инструментах ask_website и find_history.
Все инференсы идут во фоне (src/background/background.ts):
- генерация текста — через
pipeline("text-generation", ...)с KV‑кэшем, реализованным черезDynamicCache; - эмбеддинги — через
pipeline("feature-extraction", ...)с последующей нормализацией векторов.
Модели живут в одном экземпляре на фоне и обслуживают все вкладки. Это снижает расход памяти и ускоряет повторные запросы. Артефакты моделей кэшируются под origin расширения chrome-extension://<extension-id>, а не под каждый сайт, что даёт общий кэш для всей установки.
Manifest V3 периодически «усыпляет» service worker, поэтому код должен уметь переинициализировать модели при пробуждении.
Жизненный цикл скачивания и кэша
Фон явно управляет состоянием моделей:
CHECK_MODELSпроверяет локальный кэш и оценивает, сколько ещё нужно скачать.INITIALIZE_MODELSдокачивает и инициализирует модели и шлёт в UIDOWNLOAD_PROGRESS.- После инициализации используются долгоживущие инстансы:
- пайплайн генерации в
src/background/agent/Agent.ts; - пайплайн эмбеддингов в
src/background/utils/FeatureExtractor.ts.
- пайплайн генерации в
Разрешения и приватность
public/manifest.json запрашивает:
sidePanel— управление боковой панелью.storage— хранение настроек и состояния инструментов между сессиями.tabs+scripting— работа с вкладками и сценариями на странице.host_permissionsнаhttp(s)://*/*— чтобы ассистент мог анализировать и подсвечивать любые сайты.
Ключевой момент: инференс идёт локально в контексте расширения. Данные страницы и чата не отправляются на внешний сервер моделей, всё обрабатывается в браузере.
Агент и инструменты
Как устроен вызов инструментов
Transformers.js умеет работать с «функциями» (tools). Разработчик передаёт сообщения и схему инструментов (имя, описание, параметры), а библиотека сама форматирует промпт под конкретный шаблон чата Gemma 4.
Пример из проекта:
import { pipeline } from "@huggingface/transformers";
const generator = await pipeline(
"text-generation",
"onnx-community/gemma-4-E2B-it-ONNX",
{
dtype: "q4f16",
device: "webgpu",
},
);
const messages = [{ role: "user", content: "What's the weather in Bern?" }];
const output = await generator(messages, {
max_new_tokens: 128,
do_sample: false,
tools: [
{
type: "function",
function: {
name: "getWeather",
description: "Get the weather in a location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The location to get the weather for",
},
},
required: ["location"],
},
},
},
],
});
Gemma 4 может сгенерировать блок вида:
<|tool_call>call:getWeather{location:<|"|>Bern<|"|>}<tool_call|>
Поэтому в проекте есть нормализация webMcp и парсер extractToolCalls, которые превращают сырую текстовую разметку в структурированные вызовы инструментов.
Интерфейс инструментов
src/background/agent/webMcp.tsx превращает инструменты расширения в формат, удобный для модели:
namedescriptioninputSchemaexecute
Примеры инструментов:
get_open_tabs— получить список открытых вкладок.go_to_tab— переключиться на вкладку.open_url— открыть новый URL.close_tab— закрыть вкладку.find_history— поиск по истории браузера.ask_website— вопросы по содержимому текущей страницы с использованием эмбеддингов.highlight_website_element— подсветить элементы на странице.
Цикл работы агента (Agent.runAgent)
Разработчики разделили два уровня истории:
- Внутренняя история модели (
messages) — то, что уходит вgenerator(...): system / user / tool / assistant. - UI‑история (
chatMessages) — то, что видит пользователь: текст ассистента, отметки о вызовах инструментов, метрики.
Поток работы:
- Добавить пользовательский ввод в
chatMessages. - Создать «пустое» сообщение ассистента и начать стриминг токенов.
- Прогнать поток через
extractToolCalls.tsи получить{ message, toolCalls }. - В UI оставить чистый текст ассистента, а вызовы инструментов выполнить во фоне.
- Добавить результаты инструментов в метаданные и передать их как следующий ход в
messages. - Повторять, пока модель не перестанет вызывать инструменты.
- Финализировать текст ответа и метрики.
Пользователь видит аккуратный чат, а сложный цикл инструментов и внутренних сообщений остаётся во фоне.
Хранение и границы данных
Состояние разделено по типу и жизненному циклу:
- История диалога — в памяти фона (
Agent.chatMessages) для быстрых ответов. - Настройки инструментов — в
chrome.storage.local, чтобы они переживали перезапуск браузера. - Семантическая история — в IndexedDB (
VectorHistoryDB) для хранения векторов и поиска по прошлым сессиям. - Контент страницы — в кэше фона (
WebsiteContentManager), ключ — активный URL.
Это даёт один источник правды для истории, быстрый доступ во время диалога и устойчивое хранение тяжёлых данных.
Сборка и упаковка
Проект использует Vite с несколькими точками входа (vite.config.ts):
src/sidebar/index.htmlsrc/background/background.tssrc/content/content.ts
Сборка должна выдавать артефакты в точности под manifest:
sidebar.htmlbackground.jscontent.js
Content script собирают как самодостаточный бандл, без динамической подгрузки чанков — это снижает риск проблем на стороне Chrome.
Что это значит для вас
Для кого это вообще нужно
Этот подход интересен, если вы:
- Пишете Chrome‑расширения и хотите добавить локальные ИИ‑функции без своего бэкенда.
- Хотите, чтобы ассистент:
- анализировал содержимое страниц,
- подсвечивал элементы,
- работал с вкладками и историей,
- но при этом не отправлял данные на внешние LLM‑API.
- Экспериментируете с агентами и инструментами прямо в браузере.
Где это особенно полезно
- Внутренние корпоративные ассистенты в браузере, где нельзя выносить данные на сервера OpenAI или других провайдеров.
- Исследовательские и образовательные инструменты: подсветка ключевых фрагментов текста, вопросы к статье, поиск по уже прочитанным материалам.
- Инструменты для разработчиков: ассистент, который понимает DOM, подсвечивает нужные элементы, помогает навигироваться по сложным интерфейсам.
- Offline‑ориентированные сценарии: когда нет стабильного доступа к API, но есть мощный ноутбук с WebGPU.
Где лучше не использовать
- Если вам нужен максимальный уровень качества текста и рассуждений, сравнимый с GPT‑4o или Claude 3.5, — Gemma 4 E2B в браузере, скорее всего, уступит крупным облачным моделям.
- Если у пользователей слабое железо или нет поддержки WebGPU — локальный инференс может быть медленным или вообще не стартовать.
- Если ваш продукт критичен к размеру дистрибутива: модели ONNX весят заметно больше, чем обычный код расширения.
Доступность и ограничения
Расширение лежит в Chrome Web Store (ссылка есть в исходном проекте) и код открыт на GitHub: github.com/nico-martin/gemma4-browser-extension.
Для пользователей в России могут потребоваться VPN и обходные методы, если Chrome Web Store или GitHub открываются с ограничениями.
Место на рынке
Прямых числовых сравнений с GPT‑4o, Claude или другими моделями в проекте нет. Зато ясно, чем этот подход отличается по классу задач:
- По приватности: все данные и инференс остаются в браузере. В отличие от расширений, которые отправляют запросы в GPT‑4o или Claude 3.5, здесь не нужен внешний API.
- По инфраструктуре: не нужен сервер, биллинг и управление ключами. Достаточно опубликовать расширение.
- По удобству разработки: Transformers.js даёт тот же интерфейс
pipeline, что и Python‑экосистема Hugging Face, но в браузере.
За это приходится платить:
- более высокой нагрузкой на машину пользователя;
- зависимостью от WebGPU и ограничений Manifest V3;
- потенциально меньшим качеством ответа по сравнению с флагманскими облачными моделями.
Если задача — максимум качества текста и сложное рассуждение, логичнее использовать GPT‑4o или Claude 3.5 через API. Если важнее приватность и автономность, архитектура Gemma 4 + Transformers.js в браузере выглядит практичным компромиссом.
Установка / Как запустить
Ниже — ключевой пример кода из проекта, который показывает, как запустить Gemma 4 E2B через Transformers.js в браузере и дать ей инструмент getWeather.
import { pipeline } from "@huggingface/transformers";
const generator = await pipeline(
"text-generation",
"onnx-community/gemma-4-E2B-it-ONNX",
{
dtype: "q4f16",
device: "webgpu",
},
);
const messages = [{ role: "user", content: "What's the weather in Bern?" }];
const output = await generator(messages, {
max_new_tokens: 128,
do_sample: false,
tools: [
{
type: "function",
function: {
name: "getWeather",
description: "Get the weather in a location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The location to get the weather for",
},
},
required: ["location"],
},
},
},
],
});
Чтобы собрать архитектуру, аналогичную демо‑расширению Gemma 4 Browser Assistant, вам понадобится:
- Manifest V3 с тремя точками входа:
background.service_workerдля фоновой логики и моделей;side_panel.default_pathдля UI чата;content_scriptsдля работы со страницами.
- Vite‑конфиг с мульти‑entry сборкой:
src/sidebar/index.html → sidebar.html;src/background/background.ts → background.js;src/content/content.ts → content.js.
- Transformers.js в фоне для пайплайнов
text-generationиfeature-extraction. - Типизированный протокол сообщений между фоном, UI и content script.
- Слои хранения: память фона для диалога,
chrome.storage.localдля настроек, IndexedDB для векторов.
Дальше можно наращивать инструменты под свои задачи: от управления вкладками до внутренних API вашей компании, не выводя данные за пределы браузера пользователя.