ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

浏览器内LLM本地推理:WebGPU与Transformers.js实战指南

浏览器内LLM本地推理:WebGPU与Transformers.js实战指南 在浏览器里运行大语言模型已经不止是前端圈的“技术玩具”了。现在常见的大模型本地部署方案有三类第一类是 llama.cpp、Ollama 这类本地推理框架第二类是直接调用云厂商的模型服务第三类就是把大模型直接塞进浏览器用 WebGPU 调用本地 GPU 完成推理整个过程不经过后端服务。今天要展开说的就是第三条路线。这类方案里比较有代表性的实现包括 Transformers.js、WebLLM以及 llama.cpp 的 WebAssembly 版本。它们的共同特点是不需要装 Python、不需要买云 GPU、不需要准备显存特别大的服务器只需要打开一个支持 WebGPU 的浏览器就能把中小参数的 LLM 模型加载进页面完成文本生成、对话、摘要、信息抽取等任务。对于内网环境、隐私敏感场景、以及没有独立 GPU 但想快速验证大模型能力的团队来说这条路线值得认真测一测。需要提前说明一点浏览器内推理不是一个单一项目而是一类技术方案。后面会提到的模型名、加载参数、调用方式都需要以你实际使用的开源库版本为准。文章给的是完整链路和验证思路不会把不确定的显存数字或适配器型号写成结论。这篇文章的操作目标非常清晰验证浏览器 WebGPU 是否可用完成一个浏览器内 LLM 本地推理示例然后总结批量调用、资源占用和排错方法。你不用先准备 GPU 服务器只要有一台装了现代浏览器的普通电脑就能开始。1. 核心能力速览先把浏览器内 LLM 本地推理的能力边界和门槛整理成一张表方便你判断是否需要继续往下看。能力项说明项目类型浏览器端 LLM 本地推理方案通过 WebGPU 调用本地 GPU/CPU典型开源实现Transformers.js、WebLLM、llama.cpp WebAssembly 等主要功能文本生成、对话、摘要、信息抽取取决于加载的模型运行时依赖支持 WebGPU 的现代浏览器Node.js 只在开发阶段使用模型格式ONNX 量化模型或 WebLLM 约定的模型格式例如 q4f16启动方式浏览器直接访问静态页面或用 Vite、Webpack、静态服务器加载接口能力提供浏览器内 JavaScript API可封装成页面按钮或本地工具入口批量任务可以在前端循环中批量发送提示词但受内存和推理耗时限制隐私边界推理数据默认留在本机不会主动上传到第三方服务适合场景内网工具、原型验证、轻量 AI 助手、隐私敏感场景、离线演示从这张表能看出浏览器内推理最大的优势不是跑大参数模型而是把“部署门槛”压到了最低。它适合跑 0.5B、1B、3B 这类中小参数模型也适合跑经过量化处理的更大模型但你要接受它在推理速度、内存占用和并发能力上的限制。2. 适用场景与使用边界这部分要讲清楚两件事这个方案适合谁不合适谁。适合的场景主要有三类。第一类是内网或离线环境。很多企业的数据不能出内网但业务方又想快速体验大模型能力。浏览器推理方案把模型权重放在本地页面里推理时即使断网也能继续运行只要浏览器和模型文件已经准备好。第二类是前端快速原型验证。你想知道某一个开源小模型的效果如何又不想为了跑一个 demo 去装一整套 Python 环境和 CUDA 工具链。用浏览器方案一个 HTML 文件加一个本地服务就能验证。第三类是隐私敏感的个人工具。比如本地笔记助手、文本改写、敏感信息脱敏检查直接在浏览器里完成不把正文内容发送到云端。数据不出设备这一点让它的隐私边界天然比其他方案更清晰。不适合的场景也很多。不适合跑参数量很大的模型。几十B级别的模型即使量化后也可能远超浏览器标签页可用的内存上限。更稳妥的选择是把这类重量级模型交给本地推理框架或云服务。不适合对并发有强要求的正式生产服务。浏览器页面的资源限制决定了它适合单用户或少量用户同时使用不适合做成高并发 API 网关。不适合用于未获授权的数据加工。如果你要处理的是他人的人脸照片、声音录音、版权文本或敏感个人信息必须在获得明确授权后再使用并做好数据删除和访问控制。本地推理降低了技术门槛但不等于可以绕过授权和隐私保护义务。3. 环境准备与 WebGPU 可用性验证浏览器内跑通 LLM 本地推理前置条件并不复杂但有一个硬门槛浏览器必须支持 WebGPU。3.1 浏览器与系统要求以 2025 年的实际情况来看WebGPU 已经在主流浏览器的正式版本中逐步开放。最稳妥的做法是使用最新版的 Chrome 或 Edge这两个浏览器对 WebGPU 的支持最稳定。Firefox 的 WebGPU 也处于可用状态但不同版本的默认策略不完全一致测试前先确认你用的版本是否打开 WebGPU。操作系统方面Windows、macOS、Linux 都能跑。GPU 不是硬性要求因为 WebGPU 在没有独立显卡时可以用软件适配器降级到 CPU但推理速度会明显变慢。从实际体验看有独立显卡或性能较好的核显推理速度会快很多。开发阶段还需要 Node.js建议安装 LTS 版本。如果你不想引入 Node.js也可以直接使用浏览器打开本地 HTML 文件但会碰到模块加载和跨域限制所以我更推荐起一个本地静态服务。3.2 用 navigator.gpu 验证 WebGPU验证浏览器 WebGPU 是否可用的方法很简单按 F12 打开开发者工具在 Console 里执行下面这段代码。// 在浏览器控制台执行验证 WebGPU API 是否存在 if (gpu in navigator) { const adapter await navigator.gpu.requestAdapter(); if (adapter) { console.log(WebGPU 可用已获取适配器); console.log(adapter.info || adapter); } else { console.log(存在 navigator.gpu但未获取到适配器); } } else { console.log(当前浏览器不支持 navigator.gpu); }如果输出WebGPU 可用说明硬件和浏览器层面的 WebGPU 路径已经打通。如果输出当前浏览器不支持 navigator.gpu优先考虑升级浏览器版本或者到浏览器的实验特性设置里确认 WebGPU 相关开关是否打开。3.3 从系统层面确认 GPU 状态在 Chrome 地址栏输入chrome://gpu可以看到浏览器对当前 GPU 的识别情况。关键看 WebGPU 和 WebGL 相关条目是否显示为Hardware accelerated。如果显示Software only说明浏览器没有启用硬件加速推理时会走软件路径速度会比较慢。如果已经启用硬件加速但navigator.gpu.requestAdapter()仍然返回空可以检查显卡驱动是否需要更新以及浏览器是否在省电模式下限制了 GPU 资源。部分远程桌面或虚拟机环境也会导致 WebGPU 适配器不可用遇到这种情况不用纠结换一台物理机再试。3.4 准备好模型文件浏览器内推理依赖量化后的模型权重。以 Transformers.js 为例它会从 Hugging Face 模型仓库中加载 ONNX 格式的模型文件你可以直接用公网仓库地址也可以把模型文件下载到本地静态服务目录下。更稳妥的做法是在第一次测试时使用公网仓库确认链路没问题后再把模型放到内网。需要注意同一个模型在不同运行时框架下需要的格式不一样不能把 llama.cpp 的 GGUF 文件直接放到 Transformers.js 里用反之亦然。4. 一键部署本地启动与模型加载下面用 Transformers.js 作为例子演示从零创建一个浏览器 LLM 本地推理页面。这套流程的核心是本地静态服务和模型加载 API。4.1 创建项目并安装依赖打开终端执行下面的命令。如果你已经有 Node.js 环境整个过程只需要几分钟。mkdir browser-llm-demo cd browser-llm-demo npm create vitelatest . -- --template vanilla npm install npm install huggingface/transformers这里使用 Vite 作为开发服务器。它速度快热更新稳定而且开箱即用地处理了静态资源和本地跨域问题。执行完成后项目目录下会有index.html和src目录。接下来把默认的src/main.js改成下面这种结构直接验证浏览器内推理链路。4.2 加载文本生成模型在src/main.js中写入以下代码。注意模型 ID 只是一个占位示例你需要替换成实际存在的 ONNX 模型仓库地址。初次加载时浏览器会按需下载模型文件所以页面会有一段等待时间。import { pipeline } from huggingface/transformers; // 创建一个文本生成管线 const generator await pipeline( text-generation, 你的模型仓库ID/模型名称, { device: webgpu, dtype: q4f16, } ); // 加载完成后输出提示 console.log(模型加载完成开始推理);这里有几个参数需要解释。device: webgpu表示优先使用 GPU 适配器如果不传Transformers.js 会使用默认的 WASM 后端也就是 CPU 推理。dtype: q4f16是量化参数意思是权重用 4 bit 量化计算时用 FP16 精度。这个参数不是所有模型都支持如果加载失败可以先去掉dtype配置让运行时使用默认精度。4.3 启动本地服务依赖安装和代码写好之后启动开发服务器。npm run dev启动成功后终端会输出一个本地地址通常是http://localhost:5173。在浏览器打开这个地址页面会在控制台输出模型加载状态。如果你的机器没有独立显卡或者 WebGPU 适配器不可用把第 4.2 节代码中的device改成wasm同样可以跑通本地推理。两者的差别是WASM 模式用 CPU 计算速度比 WebGPU 模式慢但兼容性更好。4.4 一个完整的页面示例下面是一个更完整的示例在页面里放一个输入框和一个生成按钮。用户在输入框输入文本点击按钮后调用文本生成管线输出结果展示到页面上。!DOCTYPE html html langzh-CN head meta charsetUTF-8 / title浏览器 LLM 本地推理示例/title /head body h1浏览器 LLM 本地推理/h1 textarea idprompt rows4 cols60介绍一下 WebGPU 在浏览器端的作用/textarea br / button idrun开始生成/button pre idoutput等待输入.../pre script typemodule src/src/main.js/script /body /html对应的src/main.js可以写成这样核心是等待模型初始化完成后串行处理用户请求。import { pipeline } from huggingface/transformers; const runBtn document.getElementById(run); const promptEl document.getElementById(prompt); const outputEl document.getElementById(output); const generator await pipeline( text-generation, 你的模型仓库ID/模型名称, { device: webgpu } ); runBtn.addEventListener(click, async () { const prompt promptEl.value.trim(); if (!prompt) return; outputEl.textContent 生成中...; const result await generator(prompt, { max_new_tokens: 256, }); outputEl.textContent result[0].generated_text; runBtn.disabled false; });按钮在处理过程中置灰可以避免用户重复点击造成并发调用。测试时先把max_new_tokens设置成 128 或 256等稳定后再调大。5. 功能测试与效果验证模型能加载只是第一步真正要看的是推理输出。下面给出几条可复用的测试用例每个用例包含测试目的、操作步骤和判断标准。5.1 基础文本生成测试测试目的确认模型能正常生成文本不是 blank 输出或重复死循环。输入示例介绍 WebGPU 的核心特性。操作步骤在页面输入框填入文本点击生成等待输出。预期结果输出一段通顺的中文或英文介绍内容与 WebGPU 相关。判断标准输出不为空且不包含大量重复的“n”或未初始化的 token。失败排查如果输出只有标点符号或重复字符优先检查模型 ID 是否正确、量化参数是否匹配、浏览器控制台是否出现 ERR 日志。5.2 中文提示词测试很多 ONNX 模型对中文的支持程度不同。测试时要专门跑几条中文提示词比如“写一封请假邮件”“总结这篇文章的要点”。如果模型输出英文或乱码说明模型本身不是针对中文语料优化的换一个中文支持更好的模型即可。5.3 长文本生成测试把max_new_tokens从 128 调到 512再运行一次相同的提示词。观察两个指标页面是否在长时间生成过程中出现卡死生成到 300 token 之后内容是否开始循环。浏览器端模型受上下文长度限制当生成 token 数接近模型最大上下文时输出质量会明显下降。这是正常现象不代表部署有误。5.4 多次调用稳定性测试连续点击生成按钮 10 次左右记录每次生成的结果和耗时。重点观察两点第一次生成需要下载模型所以明显更慢这是正常的从第二次开始如果每次都在同一位置报错说明模型或运行时存在稳定性问题需要看控制台具体报错。5.5 上下文窗口测试浏览器内推理的上下文窗口由模型本身和运行时共同决定。你可以测试模型在短提示词和长提示词下的表现差异。比如先提问一个简单问题再粘贴一段 2000 字文本让它总结。如果长文本导致内存占用过高或浏览器崩溃就要考虑使用更小的模型或更短输入。6. 接口 API 与批量任务思路浏览器端推理天然是 JavaScript API不是远程 HTTP API。但你可以把它封装成自己的工具函数也可以加上一层本地服务暴露给其他设备或脚本调用。6.1 封装推理函数在main.js里可以把推理逻辑抽成一个generate(prompt, options)函数这样页面按钮、控制台、批量任务都可以复用。async function generate(prompt, options {}) { const result await generator(prompt, { max_new_tokens: options.max_new_tokens || 128, }); return result[0].generated_text; } // 单条调用 await generate(写一句欢迎语); // 批量调用 const prompts [ 解释一下什么是 WebGPU, 写一段 Promise 使用示例, 给出一份浏览器端 LLM 的优缺点清单 ]; for (let i 0; i prompts.length; i) { const output await generate(prompts[i], { max_new_tokens: 128 }); console.log(第 ${i 1} 条, output); }批量任务最简单的实现方式就是for循环加await。它看起来不够花哨但对浏览器内推理来说却是最安全的形态因为所有请求都是串行执行的不会同时抢占 GPU 和内存。6.2 串行队列 vs 并发有人会想用Promise.all一次性提交多个提示词比如下面的写法。const results await Promise.all(prompts.map((p) generator(p)));这种写法在浏览器端很危险。一个标签页能使用的内存和 GPU 资源有限多个generator同时执行轻则导致系统卡顿重则直接让浏览器崩溃。除非你明确知道模型很小、输入文本很短否则推荐始终使用串行队列。如果要控制吞吐可以自己实现一个简单队列async function runBatch(prompts, concurrency 1) { const results []; for (let i 0; i prompts.length; i concurrency) { const batch prompts.slice(i, i concurrency); const batchResults await Promise.all( batch.map((p) generate(p)) ); results.push(...batchResults); } return results; }这个函数虽然用了Promise.all但批次大小为 1 时等同于串行执行。你可以按需调整concurrency但第一次测试请从 1 开始。6.3 通过本地服务暴露 HTTP 接口如果要在局域网内让其他设备访问可以在 Vite 项目里加一层后端代理或者单独用 Express 写一个轻量服务。下面是 Express 的伪代码模板实际路径和参数需要按你的代码结构调整。import express from express; const app express(); app.use(express.json()); app.post(/generate, async (req, res) { const { prompt, max_tokens 128 } req.body; // 这里调用你封装好的 generate 函数 const output await generate(prompt, { max_new_tokens: max_tokens }); res.json({ output }); }); app.listen(8787, () { console.log(推理服务已启动: http://127.0.0.1:8787); });这样封装后可以通过 curl 测试接口curl -X POST http://127.0.0.1:8787/generate \ -H Content-Type: application/json \ -d {prompt: 介绍一下 WebGPU}需要注意这个本地接口默认没有鉴权。如果你把它绑定到非 localhost 地址必须在前面加一层访问控制否则局域网内任何设备都能调用你的模型服务既浪费资源也有数据泄露风险。7. 资源占用与性能观察浏览器内 LLM 推理的资源占用非常直观但也很容易被忽略。下面给出三个观察入口和一套降负载思路。7.1 观察浏览器任务管理器Chrome 自带任务管理器打开方式是菜单进入“更多工具”再选“任务管理器”。在这里可以看到当前标签页的内存占用、CPU 使用率和 GPU 进程占用情况。推荐做两个对照测试第一次用device: wasm加载模型观察 CPU 占用第二次用device: webgpu加载模型观察 GPU 进程占用。两次对比可以很清楚地看到 WebGPU 是否真的生效。如果 WebGPU 模式下的 GPU 进程占用没有明显上升说明推理实际走了 CPU 或软渲染路径。7.2 显存和总内存浏览器端的“显存占用”数字不是固定的。它受以下因素影响模型参数量权重量化精度输入提示词长度max_new_tokens设置浏览器是否同时运行多个标签页。因此我不会给出一个固定显存数字。更实用的做法是在推理过程中观察任务管理器里的 GPU 进程内存记下你的模型在典型输入下的稳定值作为之后调参的基准。7.3 降低资源占用的方法如果推理过程中浏览器明显卡顿或者任务管理器显示内存占用接近上限按下面顺序优化换更小的模型比如把 3B 模型换成 1B 模型使用更积极的量化参数比如从 fp16 换成 q4f16减小max_new_tokens缩短单次生成长度减小输入文本裁剪不必要的上下文关闭不必要的浏览器标签页给模型任务腾出内存。7.4 日志与性能埋点在代码中加简单的计时逻辑能快速判断模型推理速度和网络加载速度的占比。const start performance.now(); const output await generate(prompt); const end performance.now(); console.log(生成耗时(ms), end - start);输出结果后同步记录提示词长度、生成 token 数和耗时。多次记录后你会得到一套针对当前机器的性能基线后续换模型或调参数时可以直接对比。8. 常见问题与排查方法浏览器端推理的报错类型比较集中我把最高频的问题整理成一张排查表。问题现象可能原因排查方式解决方案控制台报navigator.gpu is undefined浏览器版本过旧或 WebGPU 未开启检查chrome://gpu和浏览器版本升级浏览器或在实验特性设置中开启 WebGPUrequestAdapter()返回 null显卡驱动、远程桌面、虚拟化环境受限检查系统 GPU 状态换物理机测试升级显卡驱动关闭省电模式改用 WASM 后端模型下载失败或报Failed to fetch模型 ID 写错、网络不通、跨域受限打开网络面板查看具体请求确认模型仓库地址把模型放到本地静态目录首次加载特别慢模型文件需要按需下载观察 Network 面板提前下载模型到本地使用更小的量化模型生成输出只有乱码或重复 token量化参数与模型不匹配或模型与中文适配差去掉dtype参数再测换模型测试使用官方推荐的量化配置输入文本过长导致崩溃上下文超出模型限制或内存不足逐步减小输入加长度限制裁剪输入内容点击生成按钮没有任何反应JS 报错或模型尚未初始化完成打开控制台查看异常确认pipeline调用成功后绑定按钮事件多次生成的第一次特别慢模型权重缓存未生效看网络请求保留浏览器缓存不要频繁清缓存页面在多设备上表现不一致不同浏览器对 WebGPU 支持不一致在不同浏览器上运行 3.2 节的验证代码统一浏览器版本或提供 WASM 降级方案如果你遇到表格之外的错误一个通用排查方法是在控制台的 Network 面板看请求失败状态以及在 Console 面板看完整错误堆栈。浏览器内推理的问题绝大多数集中在模型加载和资源超限两类定位到这两类就能避免盲目尝试。9. 最佳实践与后续建议把浏览器内 LLM 本地推理从“能跑”推进到“能用”要掌握下面这些原则。9.1 第一轮测试永远用小模型和短文本第一次跑通链路时选参数量最小的模型比如 0.5B 或 1B 级别max_new_tokens设成 64 或 128。确认页面能完成“输入到输出”的全链路后再逐步增大模型和生成长度。这样定位问题最方便因为变量被控制在最小范围。9.2 保留一套最小可运行配置把成功跑通的配置固定下来包括浏览器版本、模型仓库 ID、device参数、dtype参数和 Node.js 版本。后续改动模型或升级依赖时先复制这套最小配置到新项目里验证不要直接在生产项目里升级。9.3 模型和素材分目录管理项目中建议用类似下面的目录结构browser-llm-demo/ public/ models/ # 本地模型文件 inputs/ # 测试素材 outputs/ # 生成结果 src/ main.js inference.js index.html package.json模型文件、输入素材、输出结果分开既方便调试也方便以后做批量任务和权限管理。9.4 给批量任务加日志和重试机制批量任务最容易出现的问题是跑到中间某一条失败后整个任务直接中断。更好的做法是把每一条的提示词、生成结果和失败原因写入日志失败的任务自动重试一次重试仍失败就跳过并标记最后统一汇总。9.5 接口服务必须限制访问范围如果按第 6.3 节的方式把推理方法封装成 HTTP 接口发布到内网或公网时一定要做三层控制绑定局域网 IP 而不是0.0.0.0、加简单鉴权、限制单次请求的输入长度。浏览器推理服务的资源本就有限不加限制很容易被并发请求打崩。9.6 合规和授权不能省略本地推理不等于可以随便处理他人数据。无论何时何地处理人脸照片、声音录音、版权文本或个人信息前都必须先确认来源是否合法、是否获得授权、是否满足隐私保护要求。涉及商用场景时还要复核模型权重和训练数据的开源协议避免把不明确授权的模型集成到商业产品里。10. 总结与下一步浏览器内跑通 LLM 本地推理最值得尝试的点是零后端、零 Python、数据不出本机。你只需要一个支持 WebGPU 的浏览器、一个量化模型和一段不到 50 行的前端代码。建议按这个顺序验证先执行第 3.2 节的navigator.gpu检测代码确认浏览器支持 WebGPU。用最小的量化模型跑通文本生成链路。完成单条测试后再试批量串行调用。最后根据资源占用情况决定是否换更大的模型。最容易踩的坑有三个模型 ID 写错导致加载失败量化参数与模型不匹配导致乱码Promise.all并发调用导致浏览器崩溃。这三点在文章里都有对应排查方案。下一步可以扩展的方向也很多把浏览器内模型接入 RAG 知识库在 Web Worker 中运行推理避免阻塞页面渲染加流式输出让生成过程更接近 ChatGPT 体验或者封装成浏览器插件打造一个完全离线的本地 AI 助手。浏览器端 LLM 方兴未艾先用这篇文章跑通第一条链路后面的事就顺理成章了。
返回列表