大家好,我是一名深耕前端多年的老程序员。最近本地大模型、端侧 AI 特别火,很多人都觉得跑 LLM 必须靠高性能显卡、云端服务器,浏览器这种环境根本不可能跑起来几十亿参数的模型。
但今天这篇文章,就带大家完整复现:如何在浏览器里,仅依靠 WebGPU,本地运行 17B 级参数大语言模型。不讲空话,全是原理、踩坑、代码、优化方案,看完你可以直接在自己项目里落地。
一、先搞懂:为什么以前浏览器跑不了大模型?
在 WebGPU 普及之前,前端想跑 AI 模型基本只有两条路:
- WASM 纯 CPU 推理:速度极慢,超过 1B 参数基本就无法对话级响应
- WebGL 模拟计算:API 设计初衷是绘图,强行做 GPGPU 开发成本极高、效率低下
再加上模型本身体积问题:
- 一个 17B 浮点模型,原始大小动辄 30GB+
- 就算 4bit 量化,也要 8.5GB 左右浏览器根本不可能加载、缓存、推理这种体量的权重。
所以想在浏览器跑 17B 模型,必须同时满足两个条件:
- 极致压缩模型权重(1bit 量化、三元权重、结构化稀疏)
- 浏览器拥有真正通用并行计算能力(WebGPU)
二、核心技术基础:WebGPU 到底强在哪?
WebGPU 不是 WebGL 的升级版,而是为通用计算重新设计的现代图形计算 API,对 LLM 推理至关重要的能力:
1. 真正的计算管线
- 独立的 Compute Pass,专门用于通用计算
- 支持自定义 WGSL 计算着色器
- 精细的显存 / 内存缓冲区控制
- 多工作组并行调度,适合矩阵运算
2. 对大模型推理的关键优势
- 低开销内存映射,可直接加载权重二进制
- 支持大批量并行矩阵乘(LLM 核心就是矩阵乘法)
- 可直接操作 f16、f32、int 等类型
- 现代浏览器默认支持,无需插件
3. 浏览器支持情况
- Chrome / Edge 最新版:完整支持
- Firefox:需开启标志
- Safari:逐步支持
文章所有代码基于 Chrome + WebGPU 稳定版 实现。
三、模型侧关键:17B 模型如何塞进浏览器?
一个 17B 模型想在浏览器跑,必须做极端量化。
1. 传统量化不够用
- FP16:17B ≈ 34GB
- 8bit:17GB
- 4bit:8.5GB
浏览器加载、显存占用都完全不现实。
2. 1bit / 2bit 三元权重(Ternary Weight)
目前浏览器端可行方案:
- 权重仅使用
-1、0、+1三个值 - 2bit 即可存储一个权重
- 配合结构化剪枝、层融合
- 17B 模型可压缩到 1GB~2GB 区间对现代电脑来说,浏览器完全可以承载。
3. 模型格式要求
- 必须是 分块存储的 .bin/.gguf/ 自定义二进制
- 不能是 PyTorch 的 .pth 或 safetensors 直接用
- 需要提前做 权重打包、对齐、量化表剥离
四、完整实现流程(从 0 到可运行)
下面进入真正工程实现部分,按步骤走即可复现。
步骤 1:环境检测与 WebGPU 初始化
任何 WebGPU 应用第一步都是能力检测,否则直接白屏。
javascript
运行
async function initWebGPU() {
// 1. 判断浏览器是否支持 WebGPU
if (!navigator.gpu) {
alert("当前浏览器不支持 WebGPU,请使用最新版 Chrome/Edge");
throw new Error("WebGPU not supported");
}
// 2. 请求 GPU 适配器
const adapter = await navigator.gpu.requestAdapter({
powerPreference: "high-performance",
});
if (!adapter) {
throw new Error("无法获取 GPU 适配器");
}
// 3. 请求 GPU 设备
const device = await adapter.requestDevice({
requiredLimits: {
maxStorageBufferBindingSize: 2 ** 26, // 64MB,可根据模型调大
maxBufferSize: 2 ** 28,
},
});
device.lost.then((info) => {
console.error("GPU 设备丢失:", info);
});
console.log("WebGPU 初始化成功");
return { device, adapter };
}
常见问题:
- 笔记本核显无法开启高性能模式 → 推理速度慢
- 浏览器限制缓冲区大小 → 直接崩溃解决:增大
maxStorageBufferBindingSize。
步骤 2:模型文件流式加载(关键)
17B 量化后模型依然很大,绝对不能一次性加载,必须流式加载 + 进度条。
javascript
运行
async function loadModelFile(url, onProgress) {
const resp = await fetch(url);
const total = +resp.headers.get("content-length");
const reader = resp.body.getReader();
let chunks = [];
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
loaded += value.length;
onProgress?.(loaded / total);
}
// 拼接完整 buffer
const buffer = new Uint8Array(loaded);
let off = 0;
for (let c of chunks) {
buffer.set(c, off);
off += c.length;
}
return buffer;
}
优化点:
- 使用
Cache API缓存模型,避免重复下载 - 模型分片加载,失败可断点续传
- 弱网环境做超时重试
步骤 3:创建 GPU 缓冲区,上传权重
LLM 推理本质是连续的矩阵 - 向量乘法,WebGPU 需要把权重放到 storage buffer。
javascript
运行
function createModelBuffer(device, data, label = "model-weight") {
const buffer = device.createBuffer({
label,
size: Math.ceil(data.length / 4) * 4, // 对齐 4 字节
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
mappedAtCreation: true,
});
new Uint8Array(buffer.getMappedRange()).set(data);
buffer.unmap();
return buffer;
}
坑点:
- 缓冲区必须 4 字节对齐,否则报错
- 显存不足会直接丢失设备解决:分批上传、分层加载、不用的层及时销毁。
步骤 4:编写 WGSL 计算着色器(核心推理逻辑)
浏览器端推理 17B 模型,核心就是批量矩阵乘法。下面是简化版的矩阵乘计算着色器,适用于量化后权重。
wgsl
struct MatrixParams {
M: u32,
N: u32,
K: u32,
};
@group(0) @binding(0) var<uniform> params: MatrixParams;
// 权重矩阵
@group(0) @binding(1) var<storage, read> A: array<f32>;
// 输入向量
@group(0) @binding(2) var<storage, read> B: array<f32>;
// 输出
@group(0) @binding(3) var<storage, read_write> C: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let row = global_id.x;
if (row >= params.M) { return; }
var sum: f32 = 0.0;
for (var k: u32 = 0u; k < params.K; k++) {
sum += A[row * params.K + k] * B[k];
}
C[row] = sum;
}
说明:
- A:模型权重矩阵
- B:隐状态向量
- C:下一层隐状态
真正 17B 模型会包含:
- 多头注意力
- FeedForward
- Norm 层
- RoPE 位置编码
- KV Cache
每一层都对应一个计算着色器。
步骤 5:绑定管线 & 执行推理
JS 侧调用计算管线:
javascript
运行
function createMatMulPipeline(device) {
const shaderModule = device.createShaderModule({
code: matMulWGSL, // 上面的着色器代码
});
return device.createComputePipeline({
layout: "auto",
compute: {
module: shaderModule,
entryPoint: "main",
},
});
}
执行推理:
javascript
运行
async function runInference(device, pipeline, bindGroup, M) {
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(M / 64));
pass.end();
device.queue.submit([encoder.finish()]);
}
步骤 6:Tokenizer 文本编码 & 解码
大模型不能直接吃文本,必须:
- 文本 → token ID(编码)
- token ID → 文本(解码)
浏览器端常用方案:
transformers.js现成 Tokenizer- 或 WASM 加速的 BPE
javascript
运行
import { AutoTokenizer } from "@xenova/transformers";
async function initTokenizer() {
return await AutoTokenizer.from_pretrained("Xenova/gpt2");
}
const tokens = tokenizer.encode("你好");
// [1234, 2345, ...]
**问题:**JS 分词器在长文本下很慢 → 解决方案:WASM 重写。
五、跑 17B 模型一定会遇到的问题 & 解决方案
这部分是实战最值钱的内容,你跑起来一定会遇到。
问题 1:浏览器显存溢出 / GPU 设备丢失
表现:加载到一半直接崩溃,控制台提示 device lost。原因:17B 模型即便量化,显存占用依然很高。解决方案:
- 模型分层加载,推理一层释放一层
- 限制上下文长度(512 / 1024)
- 降低 batch size 为 1
- 关闭浏览器其他占用显存的标签页
问题 2:推理速度极慢,几秒钟一个字
原因:
- 核显性能弱
- 工作组大小不合理
- 着色器未优化
- KV Cache 未复用
优化:
- workgroup_size 设为 64 / 128 / 256
- 复用缓冲区,不重复创建
- KV Cache 用 f16 存储
- 注意力计算向量化
问题 3:模型加载太久,用户直接关闭页面
解决方案:
- 做预加载、进度条、加载动画
- 使用 Service Worker 后台下载
- 模型分片,优先加载解码器
问题 4:数值精度错误,输出乱码、重复
原因:
- 量化误差累积
- 缓冲区对齐错误
- 位置编码实现错误
修复:
- 严格对齐 4/16 字节
- 先跑小模型验证流程正确
- 对比 PyTorch 输出逐层调试
问题 5:Firefox / Safari 不兼容
方案:
- 做能力降级
- WebGPU 不可用时,切换到 WASM 小模型
- 或提示用户使用 Chrome
六、性能与限制(必须提前知道)
在浏览器跑 17B 模型,不是为了媲美本地 Ollama,而是为了:
- 纯隐私
- 无需安装客户端
- 开箱即用
实际表现:
- 高性能独显:可实现 3~8 token/s
- 核显:1~3 token/s
- 上下文越长,速度越慢
适用场景:
- 隐私对话助手
- 本地文档摘要
- 浏览器插件 AI
- 离线可用工具
不适合:
- 高并发
- 长文本生成
- 低延迟要求场景
七、工程化优化建议(上线必备)
- 模型预压缩:提前用 Python 脚本量化、打包、对齐
- CDN 分发:模型放高速 CDN,支持断点续传
- 缓存策略:IndexedDB + Cache API 双重缓存
- 错误兜底:WebGPU 不可用则切云端 API
- 内存监控:实时监测 buffer 大小,防止溢出
- 渐进式加载:先加载小模型占位,再后台加载完整权重
八、总结
在浏览器里跑 17B 参数大模型,不再是科幻:
- WebGPU 提供了真正的 GPGPU 能力
- 1bit/2bit 量化让模型体积降到可接受范围
- 前端工程优化可以保证可用性与稳定性
整套流程可以概括为:模型极致量化 → WebGPU 初始化 → 流式加载 → 分层显存上传 → WGSL 矩阵计算 → Token 编解码 → 推理迭代输出
未来随着浏览器优化、量化技术进步、端侧模型更小更快,纯浏览器本地大模型一定会成为常态,甚至成为前端标配能力。