最近一直在折腾一个挺有意思的方向:把网站的 AI 能力直接塞到用户浏览器里跑。起因是客户那边嫌服务器账单太烫手,问能不能让 AI 在网页端自己算,别全挤在云端。当时我第一反应是“这不就是 WebGPU 那套东西嘛”,但真动手做起来才发现,省钱和省钱之间,隔着一大堆细节。
先说结论:这条路走得通,但前提是你得搞清楚自己的场景适合“纯端侧”,还是“端云混合”。这篇文章不是讲 PPT 架构,是我自己从部署模型、调 WebGPU、改前端交互一路踩过来的实操记录。里面会涉及技术选型、成本量化、踩坑清单这些实打实的东西,适合被服务器账单追着跑的独立开发者,也适合公司里正纠结 AI 落地方案的技术负责人。
1. 内容整体设计与思路拆解
1.1 为什么要把 AI 塞进浏览器
以前提到“让 AI 跑在浏览器里”,大家第一反应都是玩具。老黄历里的 TensorFlow.js 跑个手写数字识别就算不错了,真要跑个对话模型,Chrome 能直接把 Tab 给你杀了。但这两年情况完全变了,WebGPU 让浏览器能调动显卡,WebAssembly 让量化后的模型权重跑出接近原生的速度,再加上各种 4-bit、8-bit 量化模型的普及,现在完全可以在浏览器里跑一个 7B 参数量级、经过 INT4 量化的对话模型。
从成本角度看,这个思路的诱惑力很强。你有两类用户,一类是高频调用 AI 的活跃用户,一类是偶尔点开页面尝鲜的普通用户。前者如果全走服务器推理,那 GPU 账单就是按小时往上飙的;后者单次推理虽然便宜,但架不住量大。把算力胡到用户设备上,等于把这两类用户的推理成本直接砍掉一大截。前提是你能接受模型的响应时间比云端多那么一两秒,并且受设备性能差异影响很大。
1.2 省钱之前先想清楚要付出什么
我第一次跟朋友聊这个方案时,他问:“模型放浏览器里跑,那模型文件从哪来,不还是得从服务器下载吗?”问得很对。端侧推理省的是“算力费”,但带宽成本、模型分发的成本、前端工程化的维护成本,都是新增的。还有一点不能忽略:模型权重的安全性和知识产权的保护。你辛苦微调出来的行业模型,直接打包丢到用户浏览器里,别人用开发者工具一扒就能整个拿走。所以整体方案选型的时候,不能只盯着“服务器成本降低”这一个指标,得做一整套权衡。
我这里的整体设计思路是:默认走端侧推理,把整套 Transformer 推理加载进浏览器;遇到端侧跑不动的超大模型或超复杂任务(比如一次要处理几十页 PDF 的长文档解析),自动降级回云端接口。这个“端云降级”机制,才是真正既不牺牲用户体验、又能省钱的核心。
2. 核心细节解析与实操要点
2.1 模型选型:不是所有模型都能上浏览器
目前能在浏览器里跑出体验的模型,基本集中在 0.5B 到 7B 这个区间。太小了智商不在线,太大了浏览器内存直接爆炸。我实测下来比较稳的组合是:Qwen2.5 0.5B / 1.5B 负责轻量对话和意图理解,Llama 3.2 3B 做摘要和改写,如果用户设备够好,可以尝试 Qwen2.5 7B INT4 版跑更复杂的分析和生成任务。
模型大小和内存占用的关系一定要心里有数。以 INT4 量化模型为例,每 10 亿参数大约占 0.5GB 内存。1.5B 模型大概占 0.75GB,加上运行时开销,1GB 出头;3B 模型要 1.5GB 到 2GB;7B 模型就得往 4GB 走了。手机上 8GB 内存跑 7B 会非常勉强,桌面端的 16GB 内存机器才比较稳。所以模型选型这一步,其实是在“能力上限”和“用户设备分布”之间找平衡点。
2.2 WebGPU 和 WebAssembly:浏览器的两条腿
WebAssembly 负责把模型的计算图跑起来,WebGPU 负责把矩阵运算塞给 GPU。这俩缺一不可。早期浏览器端推理只能走 CPU 的 WebAssembly 路线,放现在看速度确实不够看,一个 1.5B 模型生成 20 个字可能要等十几秒。WebGPU 普及之后,只要用户显卡支持,推理速度能翻好几倍,算得快的话能和云端 CPU 打个平手。
实操层面的第一个难点,就是 WebGPU 的兼容性。Chrome 和 Edge 的较新版本都默认支持了,Safari 在 2024 年底之后的版本也开始支持,Firefox 还在琢磨。这意味着你写推理代码之前得先做能力检测。我的做法是封装一层“环境检测器”,在页面加载后先跑个快速的 GPU 能力测试,把不支持的浏览器直接导流到云端接口。用户基本无感,只会觉得“这网站 AI 好快”,其实他根本没用到端侧推理。
如果 WebGPU 不可用,也别直接放弃,可以退一步用 WebAssembly 跑 CPU 推理。虽然慢一些,但总比完全不能用强。这一步降级逻辑做扎实了,用户体感会稳很多。
2.3 模型加载策略:省流和省时的博弈
这是整个方案里最影响体感的地方。模型文件从 400MB 到 2GB 不等,第一次加载不可能让用户干等。我用的是“渐进式加载 + 流式推理”的组合策略。
把模型权重放到 CDN 上,用浏览器缓存把文件缓存住,这样第二次访问基本就从本地缓存读取了。然后用流式加载的方式,先加载模型的前几层权重,让模型能快速吐出第一个字,后面的权重边生成边下载。配合上能把首 token 延迟压到 1.5 秒以内,用户几乎感觉不到模型文件还在补全。
另一个细节是模型切分。一个大模型文件拆成几十个 10MB 左右的切片,根据用户交互路径决定优先加载哪个切片。比如页面主要功能是“智能摘要”,那就先加载摘要模型的切片;如果后面用户想聊天,再加载对话模型的切片。这种按需加载的方式,从产品层面规避了“为了一个微不足道的功能让用户下载 1GB 文件”的尴尬。
3. 实操过程与核心环节实现
3.1 技术选型:ONNX Runtime Web 还是 Transformers.js
目前社区里最成熟的方案有两个:ONNX Runtime Web 和 Transformers.js。前者是微软的 ONNX 运行时在浏览器端的移植,对模型格式有比较好的支持;后者是 Hugging Face 的 JS 库,对开箱即用的模型很友好,内置了分词和预处理逻辑。
我自己的项目用的是基于 Transformers.js 搭建的,因为它的 API 设计几乎和 Python 版的 Hugging Face 一致,团队里的算法工程师无缝上手。它底层自动调用 WebGPU 加速,WebGPU 不可用的时候自动 fallback 到 WASM 的 CPU 推理。虽然它的自定义性不如直接调 ONNX Runtime Web,但开发效率真是高不少。如果你要搞非常复杂的模型结构,那就得上 ONNX Runtime Web,它不是开箱即用的,但胜在灵活。
Transformers.js 有很详细的环境能力检测 API。初始化时类似这样:
import { env } from '@huggingface/transformers'; // 关闭远程模型托管,改用自建 CDN env.allowLocalModels = false; env.backends.onnx.wasm.wasmPaths = 'https://cdn.example.com/wasm/'; // 检查 WebGPU 支持情况 const gpuAvailable = navigator.gpu !== undefined; console.log('WebGPU 状态:', gpuAvailable ? '可用' : '不可用');这个检测要在任何模型加载前完成,方便提前决定走哪条链路。在 WebGPU 可用时,Transformers.js 的加载参数里加上device: 'gpu',否则改成device: 'cpu'走 WASM。
3.2 模型加载与推理的完整流程
模型文件自托管是个很容易被忽略的坑。Hugging Face 默认是从他们的 CDN 拉取权重,但在国内访问速度和稳定性都堪忧。我把模型转成 ONNX 格式之后,直接用他们的模型转换工具切片,然后放到自己的对象存储和 CDN 上,配合缓存策略,效果好了不止一个级别。
加载代码大概是这样的:
import { pipeline } from '@huggingface/transformers'; const classifier = await pipeline('text-generation', 'your-cdn/model-name', { device: gpuAvailable ? 'gpu' : 'cpu', dtype: 'q4', use_quantized: true, cache_dir: 'your-chosen-cache' }); // 推理 const result = await classifier('Summarize this article in three points: ...', { max_new_tokens: 100, temperature: 0.7 });注意dtype参数。q4是 4-bit 量化,速度和文件体积的平衡点;q8质量高一点但体积几乎翻倍。我上线前专门做过 A/B 对比,在文本摘要场景里q4和q8的输出质量差别几乎感知不到,所以默认用量化更狠的q4模式,模型文件直接小一半。
3.3 端云降级机制的工程实现
这是整个项目里最重要的架构决策。不是所有用户都能顺利跑起端侧模型的,也总有些场景端侧搞不定。降级链路的代码结构可以这样设计:
const AIEngine = { async init() { this.gpu = navigator.gpu !== undefined; this.memory = navigator.deviceMemory || 4; // 单位 GB this.canRunLocal = this.gpu && this.memory >= 8; // 简单阈值 }, async generate(prompt, taskType) { // 降级判断策略 const tooComplex = taskType === 'long-doc' && docLength > 5000; if (!this.canRunLocal || tooComplex) { return this.callCloudAPI(prompt, taskType); } try { return await this.localInference(prompt, taskType); } catch (err) { console.warn('Local inference failed, falling back to cloud:', err); return this.callCloudAPI(prompt, taskType); } } };阈值可以动态调。用户首次访问加载模型失败,就把canRunLocal标成false,之后走云端;要是云端也请求失败,再降级为简单的规则匹配兜底。这个链路保证“功能永远可用”,只是服务质量有差异,这对用户信任感至关重要。
3.4 模型切片的懒加载与前端触达
为了让首屏快,模型加载绝对不能阻塞页面渲染。我采用 Worker 线程来做模型加载和推理,主线程只负责 UI 交互。Transformers.js 依赖 Web Worker 环境还需要单独处理onnx路径问题。
基本做法是:
- 页面主进程只负责发送消息给 Worker,包括用户输入的 prompt 和参数。
- Worker 内部负责加载模型、执行推理,然后把 token 逐个通过
postMessage传回主线程。 - 主线程接收到 token 后实时渲染到对话流里,这就是流式输出的核心。
内置 Worker 的初始化逻辑事先写好,用户点击“开启 AI 助手”按钮之后,立刻拉起 Worker 并预热模型。在实际使用中,这个“预热”操作能把用户首次感知的等待时间缩短一半左右,绝对值得做。
4. 常见问题与排查技巧实录
4.1 浏览器兼容性与崩溃处理
你写了 WebGPU 的代码,不代表所有浏览器都认。我自己在测试中发现的最常见问题是:用户的 Chrome 版本不够新,或者显卡驱动太老,导致设备枚举失败。代码里必须对requestAdapter做异常捕获,一旦异常直接降级到 WASM 模式。
async function isWebGPUActuallyUsable() { if (!navigator.gpu) return false; try { const adapter = await navigator.gpu.requestAdapter(); return adapter !== null; } catch (e) { return false; } }这个检测比单纯判断navigator.gpu是否存在更可靠。不能只看“有没有这个 API”,得看“能不能真正拿到适配器”。很多人的浏览器版本明明支持 WebGPU,但因为硬件太老或驱动有问题,适配器创建失败,这时候你要是直接走 WebGPU 推理,页面就得白屏崩溃了。
浏览器崩溃这个问题,我之前踩过一次。一个 7B 模型在 8GB 内存的 Mac 上把整个 Tab 干崩了。这不是代码 bug,是内存墙。后续我加了一套内存保护逻辑:加载模型前检测navigator.deviceMemory,小于 8GB 的设备默认只加载 1.5B 模型,小于 4GB 的就直接放弃端侧推理。别跟用户设备硬碰硬,体验崩一次再拉回来就难了。
4.2 模型加载慢与白屏排查
最坑的情况是 CDN 加载模型文件的时候,进度条没做好,用户盯着空白页面以为网站坏了。这里有一个“伪进度条”的技巧:先用 XMLHttpRequest 或 fetch 获取模型文件的 Content-Length,然后监听加载进度,把实时百分比画给用户。
async function loadModelWithProgress(modelUrl, onProgress) { const response = await fetch(modelUrl); const total = Number(response.headers.get('content-length')) || 0; const reader = response.body.getReader(); let loaded = 0; while (true) { const { done, value } = await reader.read(); if (done) break; loaded += value.length; onProgress(Math.round((loaded / total) * 100)); } }这一段逻辑虽然简单,但在实际运营数据里,有进度条和没进度条的用户跳出率能差七八个百分点。人性就是这样,能看见进度条,等待就变得可以忍受了。
4.3 多浏览器适配心得
我试过在 Chrome、Edge、Firefox、Safari 上分别跑同一套代码。实测经验是 Chrome 和 Edge 基本无脑过,Safari 需要额外处理 WebGPU 的“不稳定”状态,Firefox 直接放弃端侧走云端。Safari 上还要注意:Safari 的 WebGPU 实现默认在低内存设备上不怎么开放,即便是 M 系列芯片,如果内存低于 8GB,也会频繁出现适配器创建失败。所以 Safari 用户的端侧开启率,我设得比 Chrome 保守得多。
还有一个小细节:Web Worker 和主线程之间的通信别传太频繁。每生成一个 token 就 postMessage 一次,在高频生成时会卡顿。我改成每三个 token 批量传一次,配合 UI 的 requestAnimationFrame 做节流,页面流畅度立刻提升了。这个细节不大,但在体验上感知非常明显。
5. 成本量化:到底省了多少
5.1 算力账和流量账
这一章才是重点。先列一个我自己项目的真实数据做参考。那时候每天活跃用户约 3000 人,每人平均调用 5 次 AI 功能,单次请求大约消耗 1000 个 token。云端推理方案,用的按量付费 GPU 实例,平摊下来每千 token 成本大约 0.02 元到 0.04 元,单日成本约 300 到 600 元。
改造为端侧推理后,每日大约 35% 到 50% 的请求成功在浏览器端完成推理,这些完全不再产生云端算力成本。按 40% 计算,每天能省 120 到 240 元,接近五成。如果用户设备更好,端侧成功率更高,这个比例还能上涨。
新增的成本主要是带宽和存储:模型文件 1GB 左右,放在 CDN 上,假设用户平均下载一次、缓存命中率 80%,每天流量大概新增 600GB 到 800GB。按 0.25 元/GB 的 CDN 价格计算,新增成本约 150 到 200 元/天。
算下来,端侧推理的日净省金额约 0 到 90 元。你没看错,一开始我算完也是这个结果——把成本项拉齐之后,端侧不是“卧槽省大钱了”,而是“省了一点但没省特别多”。主要原因就是模型文件分发的 CDN 流量费把我的算力账吃回去了大半。如果用户模型文件能被浏览器缓存住,第二次访问不再下载,那省的钱才会真正凸显出来。
5.2 什么场景真正值得端侧化
从成本和体验综合评估,真正收益显著的场景有三类:
第一,高频、低延迟要求的轻量交互,比如输入框的实时纠错、智能回复建议。这些请求如果都走云端,一次几厘钱,一天几百万次也扛不住。端侧推理能做到 50ms 响应,体验还好过云端。
第二,需要保护业务逻辑和隐私数据的场景,比如用户上传的文档、病历、合同等信息。直接在用户浏览器里做摘要和分类,数据不出设备,对合规和隐私保护都是大加分项。这是客户最愿意买单的理由。
第三,离线场景。比如用户在公司断了网或者信号差,端侧模型照样能提供一部分 AI 功能,哪怕只是简单的要点提取,价值也远超那点算力成本。
反过来,长文本生成、超大上下文窗口、需要调用外部工具或联网检索的任务,目前还是老老实实走云端。硬要让浏览器端扛下所有,用户体验和成本都会翻车。
5.3 成本估算的建模思路
这里分享一个自己用的简单估算模型。先把核心变量列成一张表,再套进业务数据里跑一遍:
成本变量表:
| 变量 | 说明 | 取值示例 |
|---|---|---|
| 日活用户数 | 实际使用 AI 功能的人数 | 3000 人 |
| 人均日调用次数 | 平均每次会话触发 AI 的次数 | 5 次 |
| 单次 token 数 | 输入加输出 token 总量 | 1000 tokens |
| 云端单位成本 | 每千 token 推理成本 | 0.03 元 |
| 端侧成功比例 | 能在本地跑起来的请求占比 | 40% |
| 模型文件大小 | 部署到 CDN 的总权重体积 | 1 GB |
| CDN 流量单价 | 按 GB 计的流出费用 | 0.25 元 |
| 缓存命中率 | 部分用户重复访问命中缓存的占比 | 80% |
每天云端成本 = 日活 × 人均调用 × (单次 token / 1000) × 云端单位成本 × (1 - 端侧成功比例),把上表数字带进去就是 3000 × 5 × 1 × 0.03 × 0.6 = 270 元。CDN 新增成本 = 日活 × 人均调用 × 模型文件大小 × (1 - 缓存命中率) × 单价,即 3000 × 5 × 1 × 0.2 × 0.25 = 750 元?这个数字明显不对,因为一台设备只需要下载一次模型,不能按每次调用算。
所以更合理的模型应该是:当天新增设备的比例是多少。假设每天只有 10% 的设备是全新访问,那模型文件下载量就是 3000 × 5 × 10% = 1500 次?这个数字也不对,模型文件是按“设备/浏览器”维度缓存,每个人每天多次访问不会反复下载。所以更准确的 CDN 流量估算还得看 UV 数和当天新用户的比例。把 UV 设为 2000 人,新用户比例 15%,则当天模型下载次数 = 2000 × 15% = 300 次,CDN 流量 = 300 × 1GB = 300GB,以单价 0.25 元/GB 计算,成本为 75 元。这个数就对上了。这也是我反复强调的关键点——模型文件一定要做好浏览器缓存,否则流量成本分分钟吃掉所有算力节省。
6. 项目上线后的实际效果与分析
6.1 用户设备分布带来的现实落差
项目上线头一个月,我拉了一下用户设备的性能分布数据。结果多少有点意外:超过 60% 的用户用的是中低端安卓机,内存 8GB 以下,大部分连 WebGPU 都不支持。这意味着我的端侧成功比例远没达到实验室里用主力机测出来的 70%,实际只有 35% 到 40%。
这里有个残酷的现实:你精心设计的端侧方案,可能只对拿着高端手机或性能本的用户有效。很多人说“浏览器跑 AI 是未来”,但“未来”的分布并不均匀。所以做这个方案的兄弟姐妹,一定要把“端云降级”当成核心机制去做,而不是锦上添花的备用方案。没有降级机制,端侧方案在真实用户面前很容易变成“高级用户专属功能”,这其实是某种程度上的不公平——你省的还是那批配置最好的用户的钱。
6.2 业务指标的意外收获
成本没省得特别夸张,但有几个业务指标反而给到了惊喜。端侧推理模式下,平均首字延迟降低到了 0.8 秒以内(云端模式通常是 1.2-1.8 秒),用户对 AI 功能的“快”感知明显增强。其次,端侧推理不受云端限流影响,高峰时段不会再出现“AI 繁忙,请稍后重试”的提示,用户流失率显著降低。
我在用户回访问卷里看到好几条真实反馈,都在说“这个网站的 AI 感觉比别家快”。说句实在话,这未必是纯速度的功劳,更多是一种“连接稳定性”带来的心理体感。端侧推理不受弱网环境影响,信号差的时候也能快速出结果,这种“稳”的价值,有时候比那点“快”更值钱。
6.3 后续迭代方向
这套方案上线之后,后续空间还很多。可以给用户配置模型选择面板,愿意等更高质量输出的用户手动选 7B 模型,默认用户用 1.5B 模型;可以把端侧模型升级为支持联网的 agent 形态,浏览器端负责会话逻辑和意图识别,云端只负责工具调用和 RAG 检索。可以做一个后台面板,实时看端侧成功率、降级率、设备分布,用真实数据持续调校模型阈值。
我现在正在尝试的方向,是把端侧推理能力做成一个可复用的前端 SDK,把模型管理、降级策略、缓存策略都封装好,那么接下一个新网站项目时,直接铺上去就行,不用再重复踩坑了。这个 SDK 未来还能支撑更多设备形态,比如 PC 桌面客户端、移动 App 内嵌 WebView 的 AI 功能,底层思路都是一样的。
7. 一些经验之谈
7.1 如果重新来一遍,我会怎么规划
如果让我再做一个类似项目,第一步不是去急着挑模型框架,而是先花两周时间搭好“成本-体验观测平台”。统计用户设备能力、模型加载耗时、端侧成功率、降级率、云端和 CDN 的实际花费。没有这些数据,所有优化方向都得靠猜。
第二步是把模型加载切得更碎。现在虽然做了模型切片,但顺序加载的比重偏高。后续应该做成按语义模块加载,用户在中英文之间切换时,优先只加载对应语言的词表,能省下几百 MB 的加载流量和内存开支。
第三步是主动管理浏览器缓存。给模型文件带上强缓存头,并预设 service worker 缓存策略,这样用户第二次回来时几乎不需要重新下载模型文件。模型一旦出入缓存,CDN 成本就像坐滑梯一样往下跌。
7.2 别被“省钱”两个字带偏
这个标题的问法本身带着一点诱导性。真想在浏览器里跑 AI 来省钱,要问的不是“能不能省”,而是“省了什么,多了什么”。省下来的是云端推理算力成本,多出来的是 CDN 流量成本、前端工程成本、模型保护成本、以及用户设备的 CPU/GPU 和电量开销。后者虽然在你的账单上不会以“元”的形式出现,但用户的设备发热、耗电变快、页面卡顿,都会以“产品和口碑”的形式,变成你暗地里支付的代价。
从实际结果来看,我觉得在端侧跑 AI 更大的价值不是省那点 GPU 钱,而是“让用户在弱网和高延迟环境下也能用上 AI”这种稳定体验,以及“数据不出端”的隐私安全感。省钱更像是这个方案的一种副产品,它当然重要,但拿它当唯一的决策指标,十有八九你会陷入 CDN 流量费和算力费之间的零和博弈。
7.3 现状与未来之间的平衡
从 WebGPU 刚普及那阵子,我就在关注浏览器端 AI 的进展。说实话,现在的生态还处在“能跑,但不够稳,选择也不够多”的阶段。API 更新频繁、模型格式兼容性差、Safari 和 Firefox 的支持还参差不齐。但方向已经很明确了,2025 年你再去看相关框架的更新日志,会发现设备端零拷贝推理、多模型流水线并行、分布式稀疏化这些技术都在花式往浏览器端移植。
如果你的网站需要 AI 能力,而你现在刚好在纠结是买 GPU 服务器还是租 API,我建议你把浏览器端推理放进考卷。它不是万能药,但在对的方向上,它省下来的不止是成本,还有一条更灵活的、更贴近用户的 AI 产品路径。