Обзор
WebLLM — высокопроизводительный движок вывода больших языковых моделей (LLM inference engine), работающий прямо в браузере с аппаратным ускорением. Всё выполняется внутри браузера без какой-либо серверной поддержки и ускоряется с помощью WebGPU.
WebLLM полностью совместим с OpenAI API. Это означает, что вы можете использовать тот же OpenAI API для работы с любыми моделями с открытым исходным кодом локально, включая потоковую передачу, режим JSON, вызов функций (в разработке) и многое другое.
Это открывает широкие возможности для создания ИИ-ассистентов, доступных каждому, с соблюдением конфиденциальности и использованием ускорения на GPU.
Ключевые возможности
-
Вывод в браузере: WebLLM — высокопроизводительный движок вывода языковых моделей прямо в браузере, использующий WebGPU для аппаратного ускорения. Мощные операции с LLM выполняются непосредственно в браузере, без обработки на сервере.
-
Полная совместимость с OpenAI API: бесшовная интеграция приложения с WebLLM через OpenAI API с поддержкой потоковой передачи, режима JSON, управления на уровне логитов, задания начального зерна генерации и многого другого.
-
Структурированная генерация JSON: WebLLM поддерживает современный режим структурированной генерации JSON, реализованный в части библиотеки модели на WebAssembly для максимальной производительности. Попробуйте генерацию JSON по произвольной схеме на WebLLM JSON Playground на HuggingFace.
-
Поддержка широкого круга моделей: WebLLM из коробки поддерживает Llama 3, Phi 3, Gemma, Mistral, Qwen (通义千问) и многие другие модели, что делает его универсальным инструментом для различных задач ИИ. Полный список поддерживаемых моделей доступен на MLC Models.
-
Подключение пользовательских моделей: легко интегрируйте и развёртывайте собственные модели в формате MLC, адаптируя WebLLM под конкретные задачи и сценарии использования.
-
Plug-and-Play интеграция: подключайте WebLLM к своим проектам через менеджеры пакетов NPM и Yarn или напрямую через CDN. Доступны подробные примеры и модульная архитектура для подключения к UI-компонентам.
-
Потоковая передача и взаимодействие в реальном времени: поддержка потоковых ответов на запросы чата позволяет генерировать вывод в реальном времени, что особенно полезно для чат-ботов и виртуальных ассистентов.
-
Поддержка Web Worker и Service Worker: оптимизируйте производительность интерфейса и эффективно управляйте жизненным циклом моделей, перенося вычисления в отдельные рабочие потоки или сервис-воркеры (service workers).
-
Поддержка расширений Chrome: расширяйте возможности браузера с помощью пользовательских расширений Chrome на базе WebLLM — доступны примеры как простых, так и продвинутых расширений.
Встроенные модели
Полный список доступных моделей опубликован на MLC Models. WebLLM поддерживает подмножество этих моделей; актуальный список доступен в prebuiltAppConfig.model_list.
Основные семейства поддерживаемых моделей:
-
Llama: Llama 3, Llama 2, Hermes-2-Pro-Llama-3
-
Phi: Phi 3, Phi 2, Phi 1.5
-
Gemma: Gemma-2B
-
Mistral: Mistral-7B-v0.3, Hermes-2-Pro-Mistral-7B, NeuralHermes-2.5-Mistral-7B, OpenHermes-2.5-Mistral-7B
-
Qwen (通义千问): Qwen2 0.5B, 1.5B, 7B
Если нужной модели нет в списке, создайте запрос через issue или ознакомьтесь с разделом Пользовательские модели, чтобы скомпилировать и подключить собственную модель.
Быстрый старт с примерами
Изучите, как использовать WebLLM для интеграции больших языковых моделей в приложение и генерации ответов в чате, на основе простого примера чат-бота:
Пример более крупного и сложного проекта — WebLLM Chat.
Дополнительные примеры для различных сценариев использования находятся в папке examples.
Начало работы
WebLLM предлагает минималистичный и модульный интерфейс для работы с чат-ботом в браузере. Пакет спроектирован так, чтобы легко подключаться к любым UI-компонентам.
Установка
Через менеджер пакетов
# npm
npm install @mlc-ai/web-llm
# yarn
yarn add @mlc-ai/web-llm
# или pnpm
pnpm install @mlc-ai/web-llm
Затем импортируйте модуль в своём коде:
// Импортировать всё
import * as webllm from "@mlc-ai/web-llm";
// Или только то, что нужно
import { CreateMLCEngine } from "@mlc-ai/web-llm";
Через CDN
Благодаря jsdelivr.com WebLLM можно импортировать напрямую по URL — он сразу работает на облачных платформах разработки, таких как jsfiddle.net, Codepen.io и Scribbler:
import * as webllm from "https://esm.run/@mlc-ai/web-llm";
Также можно использовать динамический импорт:
const webllm = await import("https://esm.run/@mlc-ai/web-llm");
Создание MLCEngine
Большинство операций в WebLLM выполняется через интерфейс MLCEngine. Создать экземпляр MLCEngine и загрузить модель можно с помощью фабричной функции CreateMLCEngine().
(Обратите внимание: загрузка моделей требует скачивания, что при первом запуске без кэша может занять значительное время. Правильно обрабатывайте этот асинхронный вызов.)
import { CreateMLCEngine } from "@mlc-ai/web-llm";
// Callback-функция для отображения прогресса загрузки модели
const initProgressCallback = (initProgress) => {
console.log(initProgress);
};
const selectedModel = "Llama-3.1-8B-Instruct-q4f32_1-MLC";
const engine = await CreateMLCEngine(
selectedModel,
{ initProgressCallback: initProgressCallback }, // engineConfig
);
Под капотом эта фабричная функция выполняет следующие шаги: сначала создаёт экземпляр движка (синхронно), а затем загружает модель (асинхронно). При необходимости эти шаги можно разделить:
import { MLCEngine } from "@mlc-ai/web-llm";
// Синхронный вызов, возвращается немедленно
const engine = new MLCEngine({
initProgressCallback: initProgressCallback,
});
// Асинхронный вызов, может занять длительное время
await engine.reload(selectedModel);
Политика кэширования
WebLLM поддерживает четыре бэкенда кэширования через AppConfig.cacheBackend:
-
"cache": браузерный Cache API (по умолчанию). -
"indexeddb": браузерный IndexedDB. -
"opfs": браузерная Origin Private File System (OPFS). -
"cross-origin": экспериментальный бэкенд на основе расширения Chrome Cross-Origin Storage API. Для использования установите расширение Cross-Origin Storage. (Если расширение не установлено, WebLLM автоматически переключается на стандартный кэш.)
Пример:
import { CreateMLCEngine, prebuiltAppConfig } from "@mlc-ai/web-llm";
const appConfig = { ...prebuiltAppConfig, cacheBackend: "cross-origin" };
const engine = await CreateMLCEngine("Llama-3.1-8B-Instruct-q4f32_1-MLC", {
appConfig,
});
Примечания:
-
Если выбрать
"opfs"в среде без поддержки OPFS, операции с кэшем завершатся ошибкой доступности OPFS. -
При использовании
"opfs"можно задатьappConfig.opfsAccessModeравным"auto"(использовать синхронные дескрипторы доступа OPFS там, где они поддерживаются) или"sync"(требовать синхронных дескрипторов). По умолчанию установлено"async". -
Бэкенд
"cross-origin"требует установки и активации совместимого браузерного расширения. -
Бэкенд cross-origin в настоящее время не поддерживает программное удаление тензорного кэша — очистка управляется расширением.
Запрос завершения чата
После успешной инициализации движка можно отправлять запросы на завершение чата через интерфейс engine.chat.completions в стиле OpenAI API. Полный список параметров и их описание смотрите в разделе о совместимости с OpenAI и в справочнике OpenAI API.
(Примечание: параметр model здесь не поддерживается и будет проигнорирован. Вместо него используйте CreateMLCEngine(model) или engine.reload(model), как показано в разделе Создание MLCEngine.)
const messages = [
{ role: "system", content: "You are a helpful AI assistant." },
{ role: "user", content: "Hello!" },
];
const reply = await engine.chat.completions.create({
messages,
});
console.log(reply.choices[0].message);
console.log(reply.usage);
Потоковая передача
WebLLM поддерживает потоковую генерацию ответов. Чтобы её включить, достаточно передать stream: true в вызов engine.chat.completions.create.
const messages = [
{ role: "system", content: "You are a helpful AI assistant." },
{ role: "user", content: "Hello!" },
];
// chunks — объект типа AsyncGenerator
const chunks = await engine.chat.completions.create({
messages,
temperature: 1,
stream: true, // <-- Включить потоковую передачу
stream_options: { include_usage: true },
});
let reply = "";
for await (const chunk of chunks) {
reply += chunk.choices[0]?.delta.content || "";
console.log(reply);
if (chunk.usage) {
console.log(chunk.usage); // usage есть только в последнем чанке
}
}
const fullReply = await engine.getMessage();
console.log(fullReply);
Расширенное использование
Использование воркеров
Тяжёлые вычисления можно вынести в воркер-скрипт, чтобы повысить производительность приложения. Для этого нужно:
-
Создать обработчик в воркер-потоке, который взаимодействует с основным потоком и обрабатывает запросы.
-
Создать Worker Engine в основном приложении, который под капотом передаёт сообщения обработчику в воркер-потоке.
Подробные реализации различных видов воркеров описаны в следующих разделах.
Выделенный Web Worker
WebLLM поддерживает API для WebWorker — это позволяет перенести процесс генерации в отдельный рабочий поток, чтобы вычисления не мешали работе интерфейса.
Создаём обработчик в воркер-потоке, который взаимодействует с основным потоком:
// worker.ts
import { WebWorkerMLCEngineHandler } from "@mlc-ai/web-llm";
// Обработчик, работающий в воркер-потоке
const handler = new WebWorkerMLCEngineHandler();
self.onmessage = (msg: MessageEvent) => {
handler.onmessage(msg);
};
В основной логике создаём WebWorkerMLCEngine, реализующий тот же интерфейс MLCEngineInterface. Всё остальное остаётся без изменений:
// main.ts
import { CreateWebWorkerMLCEngine } from "@mlc-ai/web-llm";
async function main() {
// Используем WebWorkerMLCEngine вместо MLCEngine
const engine = await CreateWebWorkerMLCEngine(
new Worker(new URL("./worker.ts", import.meta.url), {
type: "module",
}),
selectedModel,
{ initProgressCallback }, // engineConfig
);
// всё остальное — без изменений
}
Использование Service Worker
WebLLM поддерживает API для ServiceWorker (сервис-воркера) — это позволяет перенести процесс генерации в сервис-воркер, избежав повторной загрузки модели при каждом посещении страницы, и улучшить работу приложения в офлайн-режиме.
(Примечание: жизненный цикл Service Worker управляется браузером, и он может быть завершён в любой момент без уведомления веб-приложения. ServiceWorkerMLCEngine будет периодически отправлять heartbeat-события, чтобы не дать сервис-воркеру завершиться, однако приложение также должно содержать соответствующую обработку ошибок. Подробнее о параметрах keepAliveMs и missedHeatbeat читайте в ServiceWorkerMLCEngine.)
Создаём обработчик в воркер-потоке. Инициализируйте его на верхнем уровне скрипта воркера, чтобы слушатель сообщений был зарегистрирован при первоначальном выполнении скрипта. Не создавайте его внутри слушателей activate или message: браузер может перезапустить уже активный воркер без повторной отправки события activate.
// sw.ts
import { ServiceWorkerMLCEngineHandler } from "@mlc-ai/web-llm";
new ServiceWorkerMLCEngineHandler();
console.log("Service Worker is ready");
В основной логике регистрируем сервис-воркер и создаём движок с помощью функции CreateServiceWorkerMLCEngine. Всё остальное остаётся без изменений:
// main.ts
import {
MLCEngineInterface,
CreateServiceWorkerMLCEngine,
} from "@mlc-ai/web-llm";
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register(
new URL("sw.ts", import.meta.url), // скрипт воркера
{ type: "module" },
);
}
const engine: MLCEngineInterface = await CreateServiceWorkerMLCEngine(
selectedModel,
{ initProgressCallback }, // engineConfig
);
Полный пример запуска WebLLM в сервис-воркере находится в examples/service-worker.
Расширение Chrome
Примеры создания расширений Chrome с WebLLM доступны в examples/chrome-extension и examples/chrome-extension-webgpu-service-worker. Второй вариант использует сервис-воркер, что обеспечивает постоянную работу расширения в фоне. Также можно изучить полноценный проект расширения Chrome — WebLLM Assistant, построенный на базе WebLLM.
Полная совместимость с OpenAI
WebLLM разработан с полной совместимостью с OpenAI API. Помимо создания простого чат-бота, доступны следующие возможности:
-
streaming (потоковая передача): вывод результата по частям в реальном времени в виде объекта AsyncGenerator;
-
json-mode (режим JSON): гарантированный вывод в формате JSON; подробнее в справочнике OpenAI;
-
seed-to-reproduce: использование начального зерна генерации (поле
seed) для воспроизводимых результатов; -
function-calling (вызов функций, в разработке): вызов функций через поля
toolsиtool_choice(предварительная поддержка) или ручной вызов функций безtoolsиtool_choice(максимальная гибкость).
Проверка целостности
WebLLM поддерживает опциональную проверку целостности артефактов модели с помощью хэшей SRI (Subresource Integrity). Если в ModelRecord указано поле integrity, WebLLM будет проверять скачанные файлы конфигурации, WASM и токенизатора по предоставленным хэшам перед загрузкой.
import { CreateMLCEngine } from "@mlc-ai/web-llm";
const appConfig = {
model_list: [
{
model: "https://huggingface.co/mlc-ai/Llama-3.2-1B-Instruct-q4f16_1-MLC",
model_id: "Llama-3.2-1B-Instruct-q4f16_1-MLC",
model_lib:
"https://raw.githubusercontent.com/user/model-libs/main/model.wasm",
integrity: {
config: "sha256-<base64-hash-of-mlc-chat-config.json>",
model_lib: "sha256-<base64-hash-of-wasm-file>",
tokenizer: {
"tokenizer.json": "sha256-<base64-hash-of-tokenizer.json>",
},
onFailure: "error", // "error" (по умолчанию) выбрасывает IntegrityError, "warn" — логирует и продолжает
},
},
],
};
const engine = await CreateMLCEngine("Llama-3.2-1B-Instruct-q4f16_1-MLC", {
appConfig,
});
Сгенерировать SRI-хэши для файлов модели можно следующими командами:
# SHA-256
openssl dgst -sha256 -binary <file> | openssl base64 -A | sed 's/^/sha256-/'
# SHA-384
openssl dgst -sha384 -binary <file> | openssl base64 -A | sed 's/^/sha384-/'
# SHA-512
openssl dgst -sha512 -binary <file> | openssl base64 -A | sed 's/^/sha512-/'
Если хэш не совпадает, выбрасывается исключение IntegrityError (или выводится предупреждение при onFailure: "warn"). Все поля в integrity необязательны — проверяются только явно указанные артефакты. Если поле integrity не задано вовсе, WebLLM работает как прежде — без какой-либо проверки.
Полный рабочий пример доступен в examples/integrity-verification.
Пользовательские модели
WebLLM является компаньоном MLC LLM и поддерживает пользовательские модели в формате MLC. Он повторно использует артефакты моделей и процесс сборки MLC LLM. Чтобы скомпилировать и использовать собственные модели с WebLLM, обратитесь к документации MLC LLM — там описана компиляция и развёртывание новых весов моделей и библиотек для WebLLM.
Здесь изложим общую концепцию. В пакете WebLLM есть два элемента, обеспечивающих поддержку новых моделей и вариантов весов:
-
model: URL до артефактов модели — весов и метаданных. -
model_lib: URL до библиотеки на WebAssembly (wasm-файла) с исполняемым кодом для ускорения вычислений модели.
Оба параметра настраиваются в WebLLM:
import { CreateMLCEngine } from "@mlc-ai/web-llm";
async main() {
const appConfig = {
"model_list": [
{
"model": "/url/to/my/llama",
"model_id": "MyLlama-3b-v1-q4f32_0",
"model_lib": "/url/to/myllama3b.wasm",
}
],
};
// Переопределение параметров чата
const chatOpts = {
"repetition_penalty": 1.01
};
// Загружаем предсобранную модель с переопределением параметров чата
// и пользовательской конфигурацией приложения.
// Под капотом модель будет загружена с myLlamaUrl
// и закэширована в браузерном кэше.
// Также будет загружена библиотека модели из "/url/to/myllama3b.wasm",
// при условии её совместимости с моделью по myLlamaUrl.
const engine = await CreateMLCEngine(
"MyLlama-3b-v1-q4f32_0",
{ appConfig }, // engineConfig
chatOpts,
);
}
Во многих случаях нужно лишь указать вариант весов модели, не меняя саму библиотеку модели (например, NeuralHermes-Mistral может использовать библиотеку Mistral). Примеры совместного использования библиотеки модели разными вариантами весов смотрите в webllm.prebuiltAppConfig.
Сборка пакета WebLLM из исходников
ПРИМЕЧАНИЕ: сборка из исходников нужна только если вы хотите изменить пакет WebLLM. Для использования npm-пакета просто следуйте разделу Начало работы или любому из примеров.
Чтобы собрать из исходников, выполните:
npm install
npm run build
Затем, чтобы проверить изменения на примере, откройте examples/get-started/package.json и замените "@mlc-ai/web-llm": "^0.2.85" на "@mlc-ai/web-llm": ../...
После этого выполните:
cd examples/get-started
npm install
npm start
Иногда может потребоваться переключаться между file:../.. и ../.., чтобы npm заметил новые изменения. В крайнем случае выполните:
cd examples/get-started
rm -rf node_modules dist package-lock.json .parcel-cache
npm install
npm start
Если нужно собрать TVMjs из исходников
Среда выполнения WebLLM в значительной мере опирается на TVMjs: https://github.com/apache/tvm/tree/main/web
Он также доступен как npm-пакет: https://www.npmjs.com/package/@mlc-ai/web-runtime, однако при необходимости его можно собрать из исходников, следуя шагам ниже.
-
Установите emscripten — компилятор на базе LLVM, преобразующий исходный код C/C++ в WebAssembly.
-
Следуйте инструкции по установке для установки последней версии emsdk.
-
Подключите
emsdk_env.shкомандойsource path/to/emsdk_env.sh, чтобыemccстал доступен в PATH и командаemccработала.Успешность установки можно проверить, запустив
emccв терминале.Примечание: недавно была обнаружена проблема совместимости с последними версиями
emcc. Пока что используйте./emsdk install 3.1.56вместо./emsdk install latest. Ошибка выглядит примерно так:Init error, LinkError: WebAssembly.instantiate(): Import #6 module="wasi_snapshot_preview1" function="proc_exit": function import requires a callable
-
-
В
./package.jsonзамените"@mlc-ai/web-runtime": "0.18.0-dev2",на"@mlc-ai/web-runtime": "file:./tvm_home/web",. -
Подготовьте необходимое окружение.
Установите все зависимости для веб-сборки:
./scripts/prep_deps.shНа этом шаге, если переменная
$TVM_SOURCE_DIRне задана в окружении, будет выполнена следующая команда для сборки зависимостиtvmjs:git clone https://github.com/mlc-ai/relax 3rdparty/tvm-unity --recursiveЭто клонирует текущий HEAD репозитория
mlc-ai/relax, однако он не всегда будет нужной веткой или коммитом. Чтобы собрать конкретную npm-версию из исходников, обратитесь к PR с обновлением версии — там указано, из какой ветки (mlc-ai/relaxилиapache/tvm) и какого коммита собирается данная версия WebLLM. Например, версия 0.2.52 согласно соответствующему PR собирается из коммита e6476847 репозиторияapache/tvm, а не из HEADmlc-ai/relax.Флаг
--recursiveобязателен. Без него могут возникать ошибки видаfatal error: 'dlpack/dlpack.h' file not found. -
Соберите пакет WebLLM:
npm run build -
Проверьте некоторые подпакеты.
Перейдите в подпапки в examples и проверьте работу подпакетов. Для бандлинга используется Parcel v2. Parcel иногда плохо отслеживает изменения в родительских директориях. При изменении пакета WebLLM попробуйте отредактировать и сохранить
package.jsonсоответствующей подпапки — это заставит Parcel пересобрать проект.
Ссылки
-
Для запуска LLM в нативной среде выполнения смотрите MLC-LLM
-
Возможно, вас также заинтересует Web Stable Diffusion
Благодарности
Проект инициирован участниками CMU Catalyst, UW SAMPL, SJTU, OctoML и сообщества MLC. Мы намерены продолжать его развитие и поддержку в интересах сообщества открытого машинного обучения.
Проект стал возможным благодаря экосистеме открытого программного обеспечения, на которую мы опираемся. Мы благодарим сообщество Apache TVM и разработчиков TVM Unity. Участники сообщества открытого машинного обучения сделали эти модели общедоступными. PyTorch и Hugging Face сделали их удобными в использовании. Отдельная благодарность командам, стоящим за Vicuna, SentencePiece, LLaMA и Alpaca. Также хотим поблагодарить сообщества WebAssembly, Emscripten и WebGPU и, наконец, разработчиков Dawn и WebGPU.
Цитирование
Если проект оказался вам полезен, пожалуйста, укажите следующую ссылку:
@misc{ruan2026webllmhighperformanceinbrowserllm,
title={WebLLM: A High-Performance In-Browser LLM Inference Engine},
author={Charlie F. Ruan and Yucheng Qin and Akaash R. Parthasarathy and Xun Zhou and Ruihang Lai and Hongyi Jin and Yixin Dong and Bohan Hou and Meng-Shiun Yu and Yiyan Zhai and Sudeep Agarwal and Hangrui Cao and Siyuan Feng and Tianqi Chen},
year={2026},
eprint={2412.15803},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2412.15803},
}