浏览器跑大模型:WebGPU 端侧推理的加载、回退与性能工程
浏览器跑大模型:WebGPU 端侧推理的加载、回退与性能工程
一、从云端到浏览器:端侧推理为何成为大模型前端的必答题
去年帮一个笔记应用做能力升级,原本的「一键润色」功能完全跑在云端。灰度上线两周,问题集中爆发:弱网下首字延迟高达 5 秒,老用户吐槽「还没等 AI 写完我自己都改完了」。客服后台的退款申请里,3 成理由是「AI 太慢」。这事我见过太多团队栽进去——把端到端延迟当成了理所当然。
过去一年,越来越多产品把大模型能力塞进网页。最常见的做法,是把请求发到服务端,由远端 GPU 集群完成推理,再把结果流式回传。这种架构简单、起步快,但隐含三个绕不开的痛点。
第一个痛点是延迟。请求要穿越网络到达机房,排队等待显存调度,再返回结果。即便生成速度很快,网络往返也会吃掉几百毫秒。对实时交互场景,这种开销会被用户直接感知。
第二个痛点是成本。每一次对话都要消耗服务端算力。当用户规模增长,推理账单会线性放大。把一部分轻量任务放到用户设备执行,能显著摊薄服务端压力。某头部写作工具披露的复盘数据显示,端侧化后云端账单直降 6 成。
第三个痛点是隐私。用户输入的文本里常包含敏感信息。若能在本地完成推理,数据就不需要离开浏览器。这对医疗、金融等合规场景尤其关键。
于是端侧推理(On-device Inference)成了前端工程的新命题。它的主要目标,是在浏览器里直接运行神经网络前向计算。WebGPU 提供了接近原生的并行计算能力,让这件事首次具备生产可行性。
二、设备能力探测与计算后端选择:WebGPU、WASM 与回退链路
浏览器并不是统一的运行环境。有的设备支持 WebGPU,有的只支持老旧的 WebGL,还有的连这些都没有。直接调用 WebGPU 接口,在旧浏览器上会直接抛错。因此,能力探测与后端回退是端侧推理的第一道工程关卡。
探测逻辑需要分级。优先检测navigator.gpu是否存在,再尝试请求适配器(Adapter)。若适配器为空,说明硬件或驱动不支持,应回退到 WASM 后端。WASM 用 CPU 执行计算,速度慢但兼容性最好。再往下若 WASM 也不可用,则只能交由云端兜底。
后端选择依次经过能力探测、优先后端调用、降级回退与结果缓存。
这条链路的工程价值在于韧性。无论用户设备多旧,请求都不会因接口缺失而整体崩溃。回退确保了可用性,缓存避免了每次重复探测的开销。某翻译插件曾做过统计:开了三级回退后,整体可用率从 71% 升到 99.6%。
三、生产级端侧推理封装:模型加载、流式解码与显存管理
下面给出一个可复用的推理封装。它负责后端选择、模型懒加载、超时控制与异常兜底。这里以 transformers.js 为例,因为它同时支持 WebGPU 与 WASM 后端。
import { pipeline, env } from '@huggingface/transformers'; // 单例缓存,避免重复加载数百兆模型权重造成带宽浪费 let generator: any = null; let currentBackend = ''; async function selectBackend(): Promise<string> { // 先探测 WebGPU,失败再回退 WASM,保证任意设备都能跑通 if (typeof navigator !== 'undefined' && 'gpu' in navigator) { try { const adapter = await (navigator as any).gpu.requestAdapter(); if (adapter) return 'webgpu'; } catch { // 适配器请求可能抛异常,静默降级而非中断流程 } } return 'wasm'; } export async function loadGenerator(timeoutMs = 60000) { const backend = await selectBackend(); // 后端变化时必须重建管线,否则会混用不同计算上下文 if (generator && currentBackend === backend) return generator; const timer = setTimeout(() => { throw new Error('模型加载超时,请检查网络或切换网络环境'); }, timeoutMs); try { env.backends.onnx.wasm.proxy = true; // 用 Worker 承载计算,避免阻塞主线程 generator = await pipeline( 'text-generation', 'onnx-community/Qwen2.5-0.5B-Instruct', { device: backend === 'webgpu' ? 'webgpu' : 'wasm' } ); currentBackend = backend; return generator; } catch (err) { // 权重下载失败或格式不兼容时,明确抛出以便上层兜底 throw new Error(`端侧模型初始化失败:${(err as Error).message}`); } finally { clearTimeout(timer); } } export async function runInference(prompt: string, signal: AbortSignal) { const model = await loadGenerator(); const output = await model(prompt, { max_new_tokens: 128, // 监听中断信号,用户取消时及时释放计算资源 signal, }); return output; }关键点在于三处。其一,后端探测失败时静默降级,不让异常冒泡到交互层。其二,把 WASM 计算放到 Worker 代理,主线程才不会卡顿。其三,模型加载设置超时,避免弱网下无限等待。
四、端侧推理的代价:首包延迟、内存上限与适用边界
端侧推理并非银弹。它最大的代价是首次加载。一个量化后的小模型权重往往仍有数十到数百兆。在弱网环境,下载就可能耗时十几秒。首包延迟直接劝退耐心不足的用户。某浏览器插件曾因首屏加载 18 秒模型,激活率跌到 14%。
内存是第二道墙。浏览器标签页的内存上限受设备约束,移动端尤其紧张。大模型权重常驻显存或内存,会挤压页面其他资源。若同时打开多个标签页,系统可能触发回收,导致推理中途失败。
计算速度也远低于服务端 GPU。端侧模型通常要量化到 4 位甚至更低,精度损失不可避免。对于需要严谨推理的任务,本地模型的答案质量可能明显下降。
基于这些代价,适用边界应当明确。适合端侧的场景:离线可用的轻量补全、隐私敏感本地处理、服务端限流时的兜底。不适合的场景:超长上下文、强推理、需要最新知识的任务。此类需求仍应交由云端完成。
五、总结
端侧推理把大模型能力延伸到浏览器本地,主要价值在降低延迟、摊薄成本与保护隐私。落地建议:第一,建立分级后端探测,WebGPU 优先、WASM 回退、云端兜底,保证任意设备可用。第二,模型权重必须懒加载并单例缓存,设置超时与中断控制。第三,把重计算放入 Worker,避免阻塞主线程交互。第四,明确适用边界,仅在轻量、离线、隐私场景启用端侧,强推理任务仍走云端。最终在体验、成本与设备约束之间取得工程平衡。这条路在千万级调用下能跑通,回报是值得的。
