Почему я решил, что это бред, а потом собрал и офигел
Когда я впервые услышал фразу «запустим языковую модель в браузере, да ещё и роботом через USB порулим», я фыркнул. Серьёзно? LLM — это гигабайты весов, десятки гигафлопс, а браузер — это про вкладки с котиками. Но потом Google выпустил Gemma 4, а команда Hugging Face доделала Transformers.js с WebGPU-бэкендом. И я понял: время ломать стереотипы пришло. В этой статье я покажу, как собрать стенд, где Gemma 4 работает полностью локально в браузере (никаких облаков), а её текстовые команды превращаются в движения реального робота через WebSerial. Спойлер: это работает, и это пугающе быстро.
Для кого: разработчики, робототехники, экспериментаторы. Если вы когда-нибудь хотели скрестить AI и железо, не выходя из браузера — читайте дальше.
Что нам нужно, чтобы не обжечься
В теории всё просто: браузер на Chromium (Chrome 128+, Edge 128+), компьютер с поддержкой WebGPU (практически любой ноутбук последних лет с дискретной или хотя бы встроенной Intel Iris/Xe) и минимум 8 ГБ ОЗУ. Для робота подойдёт любая плата с USB-последовательным портом — Arduino, ESP32, или, как у меня, Reachy Mini. Если у вас нет робота, можно просто поиграться с эмулятором последовательного порта — но где драйв?
Из софта: никаких Python, никаких контейнеров. Только HTML, JavaScript и немного удачи. Весь код умещается в один файл.
Важно: WebGPU пока не работает в Safari, а в Firefox только за флагом. Для эксперимента берите Chrome или Edge.
Пошаговый план: от пустого файла до робота-болтуна
1Создаём каркас и подключаем Transformers.js
Создайте пустую папку, в ней — файл index.html. Transformers.js мы будем тянуть с CDN, но сама модель будет загружена один раз и закэширована в IndexedDB — после первого запуска интернет не нужен.
Gemma 4 + Robot
2Загружаем Gemma 4 с WebGPU
Для Gemma 4 нужна квантизованная версия, иначе браузер ляжет. На момент мая 2026 лучший вариант — gemma-4-2b-it-q4f16 (2 млрд параметров, 4-битное квантование). Она весит около 1.5 ГБ и запускается на любой современной GPU.
// Настраиваем WebGPU
env.useWebGPU = true;
// Создаём пайплайн text-generation
const generator = await pipeline('text-generation', 'Xenova/gemma-4-2b-it-q4f16', {
device: 'webgpu',
dtype: 'q4f16',
});Код выше — магия. Transformers.js сам конвертирует модель в ONNX, загружает и оптимизирует под WebGPU. Если всё ок, в консоли увидите Loaded model. Если нет — читайте раздел «Грабли» в конце.
3Пишем интерфейс: чат + джойстик
Добавим два поля: одно для ввода текстовой команды (например, «поверни налево»), второе — для вывода ответа модели. Но сам ответ модели мы будем не только показывать, но и парсить в команды для робота.
По кнопке вызываем генерацию:
document.getElementById('send').onclick = async () => {
const prompt = document.getElementById('prompt').value;
const result = await generator(prompt, { max_new_tokens: 50 });
const text = result[0].generated_text;
document.getElementById('output').innerText = text;
// Парсим команду
parseAndSend(text);
};Функция parseAndSend будет искать ключевые слова: «вперёд», «назад», «влево», «вправо», «стоп» и отправлять соответствующие байты в порт.
4Подключаем WebSerial и ловим робота
WebSerial API позволяет браузеру общаться с железом через USB, как через обычный COM-порт. Запрашиваем доступ по кнопке «Подключить робота».
let port, reader, writer;
async function connectRobot() {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
writer = port.writable.getWriter();
reader = port.readable.getReader();
}
function sendCommand(cmd) {
const encoder = new TextEncoder();
writer.write(encoder.encode(cmd + '\n'));
}Теперь parseAndSend превращается в:
function parseAndSend(text) {
const lower = text.toLowerCase();
if (lower.includes('вперёд')) sendCommand('F');
else if (lower.includes('назад')) sendCommand('B');
else if (lower.includes('влево')) sendCommand('L');
else if (lower.includes('вправо')) sendCommand('R');
else if (lower.includes('стоп')) sendCommand('S');
}На стороне Arduino/ESP32 достаточно читать символ и крутить моторы. Простейший скетч:
void loop() {
if (Serial.available()) {
char cmd = Serial.read();
switch (cmd) {
case 'F': digitalWrite(motor, HIGH); break;
case 'S': digitalWrite(motor, LOW); break;
}
}
}И всё. Команда от Gemma 4 -> браузер -> WebSerial -> робот. Задержка — меньше секунды.
Грабли, на которые я наступил, чтобы вы не наступали
1. Модель не загружается. Самая частая проблема — не хватает памяти GPU. Зайдите в chrome://gpu и проверьте, что WebGPU включён. На встроенной Intel UHD 620 модель запускается, но с 2 токенами в секунду. На RTX 3060 — 30 токенов. Решение: используйте квантизацию q4f16 или даже q4 — качество страдает, но работает на всём.
2. WebSerial не видит порт. Браузер запрашивает доступ только по действию пользователя (клик). Никогда не вызывайте requestPort() просто в коде — повесьте на кнопку. И да, в HTTP (без HTTPS) WebSerial не работает — нужен localhost или SSL.
3. Робот не реагирует. Проверьте скорость (baud rate) на обоих концах. Часто ставят 9600, а мы пишем 115200 — несостыковка. Ловите ответ от железа через reader.
Почему это не игрушка, а новый способ думать о AI
Раньше, чтобы скрестить нейросеть с железом, нужно было ставить ROS, пилить микросервисы, поднимать сервер. Теперь — открыл браузер, подключил робота, и он уже понимает естественный язык. Это не шутка: на конференции 2026 я видел, как такой стенд управлял манипулятором Reachy Mini, и он брал стакан по команде «подай воды».
А что с безопасностью? WebSerial запрашивает явное разрешение, модель работает локально — данные не уходят. Идеально для прототипирования на заводе или в лаборатории, где нельзя светить данные в облако.
Кстати, Google недавно показала Gemini Robotics 1.5 — там агенты управляют роботами в реальном мире, но через API. Наш подход проще и быстрее для экспериментов.
Как сделать код ещё круче: мультимодальность и обратная связь
Gemma 4 бывает мультимодальной (понимает изображения). Если подключить камеру через getUserMedia() и передавать снимок модели, робот сможет реагировать на визуальные команды. «Видишь красный кубик? Возьми его». Я описал это в статье «Как создать real-time переводчик объектов с камеры на Gemma-4-E4B-it».
Добавьте микрофон — модель может слушать (Gemma 4 ловит звук). Об этом читайте здесь.
Одна строка, которая всё меняет
Главный инсайт, который я вынес из этого эксперимента: браузер перестал быть просто плеером для контента. Он стал полноправной платформой для AI + IoT. И да, вы можете сделать то же самое на Raspberry Pi 5 (он поддерживает WebGPU через Panthor). Попробуйте — удивитесь, насколько это просто.
А если модель генерирует ерунду — прочитайте мою заметку о странном поведении Gemma 4 при генерации кода. Иногда она упрямится, но это лечится правильным промптом.