WebLLM是一个可在浏览器中实现高性能LLM推理的引擎,支持在网页端直接运行大语言模型推理,无需服务器端支持。
高性能浏览器内 LLM 推理引擎。
文档 | 博客文章 | 论文 | 示例
WebLLM 是一个高性能的浏览器内 LLM 推理引擎,可将语言模型推理直接带到 Web 浏览器中,并借助硬件加速实现。所有操作均在浏览器内完成,无需服务器支持,并可通过 WebGPU 进行加速。
WebLLM 完全兼容 OpenAI API。也就是说,你可以在任何开源模型上本地使用相同的 OpenAI API,功能包括流式输出、JSON 模式、函数调用(开发中)等。
这带来了很多有趣的机会:为每个人构建 AI 智能体,享受 GPU 加速的同时保护隐私。
你可以将 WebLLM 作为基础 npm 包,按照下面的示例在其上构建自己的 Web 应用。本项目是 MLC LLM 的配套项目,后者实现了 LLM 在各种硬件环境下的通用部署。
立即体验 WebLLM Chat!
浏览器内推理:WebLLM 是一个高性能的浏览器内语言模型推理引擎,利用 WebGPU 进行硬件加速,使强大的 LLM 操作直接在 Web 浏览器中运行,无需服务端处理。
浏览器内推理:WebLLM 是一个高性能的浏览器内语言模型推理引擎,利用 WebGPU 进行硬件加速,使强大的 LLM 操作直接在 Web 浏览器中运行,无需服务端处理。
完全兼容 OpenAI API:使用 OpenAI API 无缝集成你的应用到 WebLLM,功能包括流式输出、JSON 模式、logit 级控制、seeding 等。
完全兼容 OpenAI API:使用 OpenAI API 无缝集成你的应用到 WebLLM,功能包括流式输出、JSON 模式、logit 级控制、seeding 等。
结构化 JSON 生成:WebLLM 支持最先进的 JSON 模式结构化生成,在模型库的 WebAssembly 部分实现以获得最佳性能。访问 HuggingFace 上的 WebLLM JSON Playground 试用自定义 JSON schema 生成 JSON 输出。
结构化 JSON 生成:WebLLM 支持最先进的 JSON 模式结构化生成,在模型库的 WebAssembly 部分实现以获得最佳性能。访问 HuggingFace 上的 WebLLM JSON Playground 试用自定义 JSON schema 生成 JSON 输出。
广泛支持模型:WebLLM 原生支持多种模型,包括 Llama 3、Phi 3、Gemma、Mistral、Qwen(通义千问)等,让它在各种 AI 任务中用途广泛。完整支持模型列表请查看 MLC Models。
广泛支持模型:WebLLM 原生支持多种模型,包括 Llama 3、Phi 3、Gemma、Mistral、Qwen(通义千问)等,让它在各种 AI 任务中用途广泛。完整支持模型列表请查看 MLC Models。
自定义模型集成:轻松将 MLC 格式的自定义模型集成和部署,允许你根据特定需求和场景调整 WebLLM,增强模型部署的灵活性。
自定义模型集成:轻松将 MLC 格式的自定义模型集成和部署,允许你根据特定需求和场景调整 WebLLM,增强模型部署的灵活性。
即插即用集成:通过 NPM、Yarn 等包管理器或直接通过 CDN 轻松将 WebLLM 集成到项目中,配备全面的示例和模块化设计,可连接 UI 组件。
即插即用集成:通过 NPM、Yarn 等包管理器或直接通过 CDN 轻松将 WebLLM 集成到项目中,配备全面的示例和模块化设计,可连接 UI 组件。
流式与实时交互:支持流式聊天补全,允许实时输出生成,增强聊天机器人和虚拟助手等交互式应用体验。
流式与实时交互:支持流式聊天补全,允许实时输出生成,增强聊天机器人和虚拟助手等交互式应用体验。
Web Worker 与 Service Worker 支持:通过将计算卸载到独立的 worker 线程或 service worker 来优化 UI 性能并高效管理模型生命周期。
Web Worker 与 Service Worker 支持:通过将计算卸载到独立的 worker 线程或 service worker 来优化 UI 性能并高效管理模型生命周期。
Chrome 扩展支持:通过使用 WebLLM 的自定义 Chrome 扩展来扩展 Web 浏览器功能,提供基础和高级扩展的构建示例。
Chrome 扩展支持:通过使用 WebLLM 的自定义 Chrome 扩展来扩展 Web 浏览器功能,提供基础和高级扩展的构建示例。
在 MLC Models 上查看完整可用模型列表。WebLLM 支持这些可用模型的子集,列表可通过 prebuiltAppConfig.model_list 访问。
以下是当前支持的主要模型系列:
Llama:Llama 3、Llama 2、Hermes-2-Pro-Llama-3
Phi:Phi 3、Phi 2、Phi 1.5
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 将大语言模型集成到你的应用中并生成聊天补全:
对于更大更复杂项目的高级示例,请查看 WebLLM Chat。
更多不同用例的示例可在 examples 文件夹中找到。
WebLLM 提供了极简且模块化的接口来访问浏览器中的聊天机器人。该包采用模块化设计,可与任何 UI 组件挂钩。
# npm
npm install @mlc-ai/web-llm
# yarn
yarn add @mlc-ai/web-llm
# or pnpm
pnpm install @mlc-ai/web-llm
然后在你的代码中导入该模块。
// 导入全部
import * as webllm from "@mlc-ai/web-llm";
// 或只导入你需要的内容
import { CreateMLCEngine } from "@mlc-ai/web-llm";
得益于 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");
WebLLM 中的大多数操作都通过 MLCEngine 接口调用。你可以通过调用 CreateMLCEngine() 工厂函数创建 MLCEngine 实例并加载模型。
(注意:加载模型需要下载,首次运行且没有缓存的情况下可能需要较长时间。你应该妥善处理这个异步调用。)
import { CreateMLCEngine } from "@mlc-ai/web-llm";
// 回调函数用于更新模型加载进度
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 跨域存储 API 扩展后端。需要安装跨域存储扩展才能使用。(如果未安装扩展,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" 后端需要安装并启用兼容的浏览器扩展。
跨域后端目前不支持编程式的 tensor-cache 删除;清理工作由扩展管理。
引擎成功初始化后,现在可以通过 engine.chat.completions 接口使用 OpenAI 风格的聊天 API 来调用聊天补全。有关参数及其描述的完整列表,请参阅下文和 OpenAI API 参考文档。
(注意:model 参数在此处不受支持,会被忽略。请改为按上面创建 MLCEngine 所示的那样调用 CreateMLCEngine(model) 或 engine.reload(model)。)
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); // 只有最后一个 chunk 包含 usage
}
}
const fullReply = await engine.getMessage();
console.log(fullReply);
你可以将重型计算放在 Web Worker 脚本中来优化应用性能。要做到这一点,你需要:
在工作线程中创建一个处理器,在处理请求的同时与前端通信。
在你的主应用中创建一个 Worker Engine,它在底层向工作线程中的处理器发送消息。
有关不同类型 Worker 的详细实现,请参阅以下章节。
WebLLM 提供了 WebWorker 的 API 支持,因此你可以将生成过程挂接到一个独立的工作线程中,这样工作线程中的计算就不会干扰 UI。
我们在工作线程中创建一个处理器,在处理请求的同时与前端通信。
// worker.ts
import { WebWorkerMLCEngineHandler } from "@mlc-ai/web-llm";
// 一个位于工作线程中的处理器
const handler = new WebWorkerMLCEngineHandler();
self.onmessage = (msg: MessageEvent) => {
handler.onmessage(msg);
};
在主逻辑中,我们创建一个实现 MLCEngineInterface 的 WebWorkerMLCEngine。其余逻辑保持不变。
// 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
);
// 其他所有逻辑保持不变
}
WebLLM 提供了 ServiceWorker 的 API 支持,因此你可以将生成过程挂接到一个服务 Worker 中,以避免在每次页面访问时重新加载模型,并优化应用的离线体验。
(注意:Service Worker 的生命周期由浏览器管理,可以随时在不知会 Web 应用的情况下被终止。ServiceWorkerMLCEngine 会通过定期发送心跳事件来尝试保持服务 Worker 线程存活,但你的应用也应该包含适当的错误处理。详情请参阅 ServiceWorkerMLCEngine 中的 keepAliveMs 和 missedHeatbeat。)
我们在工作线程中创建一个处理器,在处理请求的同时与前端通信。在 worker 脚本顶层实例化处理器,这样它的消息监听器会在初始脚本评估期间注册。不要从 activate 或 message 监听器中实例化它:浏览器可以重新启动一个已处于活跃状态的 Worker 而不再发送另一个 activate 事件。
// sw.ts
import { ServiceWorkerMLCEngineHandler } from "@mlc-ai/web-llm";
new ServiceWorkerMLCEngineHandler();
console.log("Service Worker is ready");
然后在主逻辑中,我们注册服务 Worker 并使用 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), // worker 脚本
{ type: "module" },
);
}
const engine: MLCEngineInterface = await CreateServiceWorkerMLCEngine(
selectedModel,
{ initProgressCallback }, // engineConfig
);
你可以在 examples/service-worker 中找到一个关于如何在服务 Worker 中运行 WebLLM 的完整示例。
你还可以在 examples/chrome-extension 和 examples/chrome-extension-webgpu-service-worker 中找到使用 WebLLM 构建 Chrome 扩展的示例。后者利用了服务 Worker,因此扩展会在后台持久运行。此外,你还可以探索另一个使用 WebLLM 的完整 Chrome 扩展项目 WebLLM Assistant。
完整的 OpenAI 兼容性
WebLLM 的设计目标是与 OpenAI API 完全兼容。因此,除了构建一个简单的聊天机器人,你还可以通过 WebLLM 实现以下功能:
streaming:以 AsyncGenerator 的形式实时返回 chunk 形式的输出
json-mode:高效确保输出为 JSON 格式,详见 OpenAI 参考文档。
seed-to-reproduce:使用随机种子确保可复现的输出,包含 seed 字段。
function-calling(WIP):通过 fields tools 和 tool_choice 进行函数调用(有初步支持);或手动函数调用(不使用 tools 或 tool_choice,保持最大灵活性)。
完整性验证
WebLLM 支持使用 SRI(子资源完整性)哈希对模型制品进行可选的完整性验证。当在 ModelRecord 上设置了 integrity 字段时,WebLLM 会在加载之前验证下载的 config、WASM 和 tokenizer 文件是否与提供的哈希匹配。
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-<mlc-chat-config.json 的 base64 哈希>",
model_lib: "sha256-<wasm 文件的 base64 哈希>",
tokenizer: {
"tokenizer.json": "sha256-<tokenizer.json 的 base64 哈希>",
},
onFailure: "error", // "error"(默认)抛出 IntegrityError,"warn" 记录日志并继续
},
},
],
};
const engine = await CreateMLCEngine("Llama-3.2-1B-Instruct-q4f16_1-MLC", {
appConfig,
});
你可以使用以下命令为模型文件生成 SRI 哈希:
openssl dgst -sha256 -binary <file> | openssl base64 -A | sed 's/^/sha256-/'
openssl dgst -sha384 -binary <file> | openssl base64 -A | sed 's/^/sha384-/'
openssl dgst -sha512 -binary <file> | openssl base64 -A | sed 's/^/sha512-/'
这些 openssl 命令需要在类 Unix shell 下运行(macOS/Linux)。在 Windows 上,通过 Git Bash 或 WSL 来运行 openssl。
如果哈希值不匹配,则会抛出 IntegrityError(在 onFailure: "warn" 时会记录警告)。integrity 中的所有字段都是可选的——只有指定的产物会被校验。当完全省略 integrity 字段时,WebLLM 的行为与之前完全相同(不进行校验)。
完整的可运行演示请参见 integrity-verification 示例。
WebLLM 作为 MLC LLM 的配套项目而运作,支持以 MLC 格式的自定义模型。它复用了 MLC LLM 的模型产物并构建了其工作流程。如需了解如何将自定义模型编译并部署到 WebLLM,请参阅 MLC LLM 文档。
这里我们概述一下高层思路。WebLLM 包中有两个元素使新模型和权重变体成为可能。
model:包含模型产物的 URL,例如权重和元数据。
model_lib:指向 WebAssembly 库(即 wasm 文件)的 URL,其中包含用于加速模型计算的可执行文件。
在 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",
}
],
};
// override default
const chatOpts = {
"repetition_penalty": 1.01
};
// load a prebuilt model
// with a chat option override and app config
// under the hood, it will load the model from myLlamaUrl
// and cache it in the browser cache
// The chat will also load the model library from "/url/to/myllama3b.wasm",
// assuming that it is compatible to the model in myLlamaUrl.
const engine = await CreateMLCEngine(
"MyLlama-3b-v1-q4f32_0",
{ appConfig }, // engineConfig
chatOpts,
);
}
在很多场景下,我们只想提供模型权重变体,而不一定是新模型(例如 NeuralHermes-Mistral 可以复用 Mistral 的模型库)。关于模型库如何被不同模型变体共享的示例,请参阅 webllm.prebuiltAppConfig。
注意:除非你想修改 WebLLM 包,否则不需要从源码构建。要使用 npm 包,直接遵循入门指南或任意示例即可。
从源码构建,只需运行:
npm install
npm run build
然后,如需在示例中测试代码变更的效果,在 examples/get-started/package.json 中,将 "@mlc-ai/web-llm": "^0.2.84" 改为 "@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
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。通过 source path/to/emsdk_env.sh 来 source 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
安装 emscripten。这是一个基于 LLVM 的编译器,用于将 C/C++ 源代码编译为 WebAssembly。
按照安装说明安装最新的 emsdk。
通过 source path/to/emsdk_env.sh 来 source 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"。
在 ./package.json 中,将 "@mlc-ai/web-runtime": "0.18.0-dev2" 改为 "@mlc-ai/web-runtime": "file:./tvm_home/web"。
准备必要的环境
准备 web 构建所需的所有依赖:./scripts/prep_deps.sh
在这一步中,如果 $TVM_SOURCE_DIR 未在环境中定义,我们将执行以下行来构建 tvmjs 依赖:
git clone https://github.com/mlc-ai/relax 3rdparty/tvm-unity --recursive
这会克隆 mlc-ai/relax 的当前 HEAD。但是,它未必总是要克隆的正确分支或提交。如需从源码构建特定的 npm 版本,请参阅版本变更 PR,其中指明了当前 WebLLM 版本依赖的分支(即 mlc-ai/relax 或 apache/tvm)以及具体的提交。例如,0.2.52 版本,根据其版本变更 PR #521,是通过在 apache/tvm 中检出以下提交构建的:https://github.com/apache/tvm/commit/e6476847753c80e054719ac47bc2091c888418b6,而不是 mlc-ai/relax 的 HEAD。此外,--recursive 是必要且重要的。否则你可能会遇到如下错误:fatal error: 'dlpack/dlpack.h' file not found。
准备必要的环境