前端开发 · 2026年2月23日

浏览器里跑大模型:WebLLM + WebGPU前端AI推理实战

做前端的都知道,AI能力基本都在服务端。你的代码补全、智能搜索、聊天机器人,背后全是API调用。但有些场景就是不想把数据发到服务端——隐私敏感数据、离线环境、或者单纯不想付API费用。

WebGPU + WebLLM给了一个不一样的答案:直接在浏览器里跑大模型,零服务端依赖。

我花了两天时间把这套东西跑通了,记录一下真实体验。

WebGPU是什么,为什么现在才行

WebGL搞了十几年,能力一直停留在图形渲染。通用计算(GPGPU)虽然能用WebGL hack出来,但开发体验极差,性能也打折。

WebGPU是W3C搞的新标准,2023年Chrome 113开始支持。和WebGL最大的区别:它原生支持Compute Shader,可以直接在GPU上跑通用计算任务。这意味着矩阵乘法、向量运算这些LLM推理的核心操作,终于能在浏览器里用GPU加速了。

目前的浏览器支持情况:

浏览器 WebGPU支持 备注
Chrome 113+ ✅ 默认开启 推荐,最稳定
Edge 113+ ✅ 默认开启 和Chrome一样的内核
Firefox ⚠️ Nightly 需要手动开flag
Safari 18+ ✅ 默认开启 macOS 15 / iOS 18

WebLLM:把LLM搬进浏览器的工具链

WebLLM是MLC AI团队做的开源项目,核心思路:用TVM编译器把LLM模型编译成WebGPU可以执行的格式,然后在浏览器里加载运行。

API设计完全兼容OpenAI的Chat Completions格式,这一点很聪明。意味着你现有的代码几乎不用改,把API endpoint从OpenAI换成本地的WebLLM engine就行。

安装:

npm install @mlc-ai/web-llm

实战:5分钟跑一个本地AI聊天

我搭了一个最简单的demo来测试实际效果。

import { CreateMLCEngine } from "@mlc-ai/web-llm";

// 初始化引擎,选择模型
const engine = await CreateMLCEngine("Llama-3.1-8B-Instruct-q4f16_1-MLC", {
  initProgressCallback: (progress) => {
    console.log(`加载进度: ${progress.text}`);
  },
});

// 和OpenAI一模一样的调用方式
const response = await engine.chat.completions.create({
  messages: [
    { role: "system", content: "你是一个前端技术专家" },
    { role: "user", content: "解释一下React Server Components的工作原理" },
  ],
  temperature: 0.7,
  stream: true,
});

// 流式输出
for await (const chunk of response) {
  const delta = chunk.choices[0]?.delta?.content || "";
  process.stdout.write(delta);
}

代码很简单,但第一次跑的时候有个坑:模型下载

踩坑记录

坑1:首次加载巨慢

Llama-3.1-8B的q4f16量化版大概4.3GB。首次加载要从HuggingFace下载完整模型到浏览器的IndexedDB里。我50Mbps的网络跑了大概15分钟。

好消息是只需要下载一次,后续刷新页面直接从IndexedDB读取,几秒钟就能加载完成。

如果你的用户在国内,HuggingFace的下载速度大概率会很痛苦。目前没有官方的国内镜像方案,只能自己搭CDN代理。

坑2:显存占用超出预期

8B模型q4f16量化后虽然文件只有4.3GB,但运行时GPU显存占用大概5-6GB。我台式机的RTX 3060(12GB显存)跑起来没问题,但在集显笔记本上直接崩了——共享内存不够。

实测不同模型的显存需求:

模型 量化 文件大小 运行显存 推理速度
Qwen2-0.5B q4f16 350MB ~1GB ~45 tok/s
Phi-3.5-mini-3.8B q4f16 2.2GB ~3GB ~25 tok/s
Llama-3.1-8B q4f16 4.3GB ~6GB ~15 tok/s
Mistral-7B q4f16 3.9GB ~5GB ~18 tok/s

速度数据是在RTX 3060上测的。集显或者核显的话速度大概只有这个的1/3到1/5。

坑3:Safari的WebGPU实现有差异

虽然Safari 18宣布支持WebGPU,但实际跑起来有些shader编译会报错。MLC团队在持续适配,但目前最稳的还是Chrome。如果你的应用要兼容Safari,建议先用小模型测一遍。

坑4:Web Worker是必须的

千万别在主线程跑推理。模型加载和推理过程会完全阻塞UI,页面直接卡死。必须用Web Worker:

// worker.ts
import { MLCEngineWorkerHandler, MLCEngine } from "@mlc-ai/web-llm";

const engine = new MLCEngine();
const handler = new MLCEngineWorkerHandler(engine);
self.onmessage = (msg) => handler.onmessage(msg);

// main.ts
import { WebWorkerMLCEngine } from "@mlc-ai/web-llm";

const engine = await WebWorkerMLCEngine(
  new Worker(new URL("./worker.ts", import.meta.url), { type: "module" }),
  "Phi-3.5-mini-instruct-q4f16_1-MLC"
);

WebLLM官方提供了Worker封装,用起来还算方便。但如果你的项目用了Vite或者webpack,Worker的打包配置可能需要折腾一下。

JSON Mode和Function Calling

WebLLM支持JSON Mode结构化输出,这对前端应用很有用——你可以让模型直接输出符合特定schema的JSON,不需要自己解析自然语言。

const response = await engine.chat.completions.create({
  messages: [
    {
      role: "user",
      content: "分析这段用户反馈的情感倾向:'这个功能太难用了,每次都要点好几步'"
    }
  ],
  response_format: {
    type: "json_object",
    schema: JSON.stringify({
      type: "object",
      properties: {
        sentiment: { type: "string", enum: ["positive", "negative", "neutral"] },
        score: { type: "number", minimum: -1, maximum: 1 },
        keywords: { type: "array", items: { type: "string" } },
        suggestion: { type: "string" }
      },
      required: ["sentiment", "score", "keywords"]
    })
  },
  temperature: 0.1,
});

// 输出:
// {
//   "sentiment": "negative",
//   "score": -0.7,
//   "keywords": ["难用", "好几步"],
//   "suggestion": "简化操作流程,减少点击步骤"
// }

JSON Mode的实现是在WebAssembly层面做的约束解码,不是靠prompt engineering,所以输出格式是保证正确的。这比调API然后祈祷返回格式正确要靠谱得多。

实际能干什么

说实话,浏览器里跑8B模型的能力和GPT-4比差距还是很大的。但有几个场景确实合适:

1. 表单智能填充

用户输入一段自然语言描述,本地模型解析成结构化数据填入表单。数据不出浏览器,隐私问题直接解决。用Qwen2-0.5B这种小模型就够了,响应速度也快。

2. 离线文档助手

把文档问答能力内嵌到Web应用里。用户断网也能用。适合企业内部工具、敏感文档处理这些场景。

3. 实时文本处理

拼写检查、文本摘要、分类标签。这些不需要太强的模型能力,3B以下的模型就能做得不错,在浏览器里跑延迟比调API还低。

4. AI功能的降级方案

主路径走API,API挂了或者超时就降级到浏览器本地推理。体验虽然差一点,但至少功能还能用。

性能优化建议

如果你真的要在生产环境用,这几点需要注意:

模型预加载:在用户真正需要AI功能之前就开始后台加载模型。可以在Service Worker里做,或者在用户浏览其他页面的时候静默加载。

选对模型大小:不要上来就整8B。大多数文本处理任务0.5B-3B就够了,加载快、推理快、显存占用小。只有需要复杂推理能力的时候才上大模型。

做好降级:检测WebGPU支持,不支持就回退到API调用。代码大概长这样:

async function getAIEngine() {
  if (navigator.gpu) {
    try {
      const adapter = await navigator.gpu.requestAdapter();
      if (adapter) {
        return await createLocalEngine(); // WebLLM
      }
    } catch (e) {
      console.warn("WebGPU初始化失败,降级到API", e);
    }
  }
  return createAPIEngine(); // 远程API
}

缓存管理:IndexedDB里存的模型文件会一直占用磁盘空间。给用户提供清除缓存的选项,或者设置过期策略。

和其他方案的对比

方案 运行环境 模型大小 速度 隐私 易用性
WebLLM (WebGPU) 浏览器 0.5-8B 15-45 tok/s 完全本地 npm装一下就行
Transformers.js (WASM) 浏览器 主要小模型 较慢 完全本地 HuggingFace生态
Ollama + API 本地服务 不限 取决于硬件 本地网络 需装桌面软件
OpenAI API 云端 不限 很快 数据上传 最简单

WebLLM的核心优势就是零安装 + 完全本地。用户打开网页就能用,不需要装任何东西,数据不出浏览器。但代价是模型能力受限于浏览器环境和用户设备的GPU。

当前的局限

泼一盆冷水:

模型能力上限明显。浏览器能跑的最大就8B量化模型,和70B或者闭源大模型的差距是质的区别。复杂推理、长文本理解这些任务做不了。

用户设备差异巨大。你在RTX 4090上测得飞快,用户可能拿着5年前的集显笔记本,直接OOM。做好设备检测和降级是必须的。

首次加载体验差。下载几个GB的模型文件,对大多数用户来说是不可接受的等待时间。需要很好的进度提示和预加载策略。

调试困难。WebGPU的错误信息通常不太友好,模型推理过程是黑盒,出了问题很难定位。

值不值得现在用

如果你的场景刚好是:隐私敏感 + 不需要太强的模型能力 + 用户设备还行,那WebLLM是个很好的方案。JSON Mode和OpenAI兼容API让集成成本很低。

如果不是上面的场景,调API仍然是更稳妥的选择。不要为了用新技术而用新技术。

但趋势是明确的:WebGPU的浏览器覆盖率在快速提升,模型压缩技术在进步,小模型的能力在变强。浏览器端AI从”能跑”到”能用”的临界点,可能比大多数人预想的要近。

项目地址:https://github.com/mlc-ai/web-llm

在线体验:https://chat.webllm.ai/