Дата публикации
ai_products

Локальный ИИ в 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 докачивает и инициализирует модели и шлёт в UI DOWNLOAD_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 превращает инструменты расширения в формат, удобный для модели:

  • name
  • description
  • inputSchema
  • execute

Примеры инструментов:

  • 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) — то, что видит пользователь: текст ассистента, отметки о вызовах инструментов, метрики.

Поток работы:

  1. Добавить пользовательский ввод в chatMessages.
  2. Создать «пустое» сообщение ассистента и начать стриминг токенов.
  3. Прогнать поток через extractToolCalls.ts и получить { message, toolCalls }.
  4. В UI оставить чистый текст ассистента, а вызовы инструментов выполнить во фоне.
  5. Добавить результаты инструментов в метаданные и передать их как следующий ход в messages.
  6. Повторять, пока модель не перестанет вызывать инструменты.
  7. Финализировать текст ответа и метрики.

Пользователь видит аккуратный чат, а сложный цикл инструментов и внутренних сообщений остаётся во фоне.

Хранение и границы данных

Состояние разделено по типу и жизненному циклу:

  • История диалога — в памяти фона (Agent.chatMessages) для быстрых ответов.
  • Настройки инструментов — в chrome.storage.local, чтобы они переживали перезапуск браузера.
  • Семантическая история — в IndexedDB (VectorHistoryDB) для хранения векторов и поиска по прошлым сессиям.
  • Контент страницы — в кэше фона (WebsiteContentManager), ключ — активный URL.

Это даёт один источник правды для истории, быстрый доступ во время диалога и устойчивое хранение тяжёлых данных.

Сборка и упаковка

Проект использует Vite с несколькими точками входа (vite.config.ts):

  • src/sidebar/index.html
  • src/background/background.ts
  • src/content/content.ts

Сборка должна выдавать артефакты в точности под manifest:

  • sidebar.html
  • background.js
  • content.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, вам понадобится:

  1. Manifest V3 с тремя точками входа:
    • background.service_worker для фоновой логики и моделей;
    • side_panel.default_path для UI чата;
    • content_scripts для работы со страницами.
  2. Vite‑конфиг с мульти‑entry сборкой:
    • src/sidebar/index.html → sidebar.html;
    • src/background/background.ts → background.js;
    • src/content/content.ts → content.js.
  3. Transformers.js в фоне для пайплайнов text-generation и feature-extraction.
  4. Типизированный протокол сообщений между фоном, UI и content script.
  5. Слои хранения: память фона для диалога, chrome.storage.local для настроек, IndexedDB для векторов.

Дальше можно наращивать инструменты под свои задачи: от управления вкладками до внутренних API вашей компании, не выводя данные за пределы браузера пользователя.


Читайте также