WebView里跑端侧AI模型——浏览器内LLM推理实战
最近几年,端侧AI越来越火,从手机上的NPU到浏览器的WebGPU,都在努力把AI能力带到离用户更近的地方。但你有没有想过:在App内嵌的WebView里,也能直接跑大语言模型(LLM)吗?答案是肯定的。本文将带你实操,在Android/iOS的WebView中运行本地LLM推理,无需服务器,完全离线。
一、为什么要在WebView里跑LLM?
在移动端App中,Hybrid架构依旧流行,很多页面直接内嵌WebView展示。如果我们能直接在WebView里完成AI推理,将带来几点好处:
- 完全离线:不依赖网络,用户隐私数据不会离开设备。
- 降低服务器成本:推理发生在客户端,无需维护昂贵的GPU集群。
- 跨平台复用:一套Web代码,同时跑在Android、iOS甚至桌面端的WebView中。
- 快速迭代:模型和UI更新无需发版,走Web发布流程即可。
当然,挑战也很明显:WebView的算力、内存受限,JS单线程容易阻塞UI。但随着WebGPU的普及和WebAssembly的成熟,浏览器内运行小型LLM(如LLaMA-2-7B的量化版本)已成为可能。
我这里只是简单介绍下,我的尝试体验,乐意和大家做进一步的交流,欢迎评论区了见。
二、技术选型:让浏览器跑起LLM的三驾马车
要在WebView里跑LLM,当前主流技术栈有三个:
1. WebGPU + ONNX Runtime Web
ONNX Runtime Web 支持通过WebGPU后端执行ONNX模型,能利用GPU进行加速。你需要将LLM转换为ONNX格式,借助其提供的JavaScript API加载并推理。优点是成熟度高,支持多种模型;缺点是需要自行处理分词器(Tokenizer)逻辑。
2. Transformers.js
Hugging Face推出的Transformers.js 让你直接在浏览器里使用和Python版接口几乎一致的库。底层基于ONNX Runtime Web,并内置了Tokenizer、Pipeline等组件。一行代码即可加载模型并开始生成文本,极大降低了门槛。
3. WebLLM / MLC-LLM
这类方案专门针对浏览器内LLM推理优化,比如WebLLM直接通过WebGPU运行LLaMA、Mistral等模型,内部使用Apache TVM编译,性能很强。但生态相对封闭,需要模型按照其格式转换。
综合考量:对于大多数开发者,推荐从Transformers.js入手,它隐藏了复杂的转换细节,上手最快。本文实战也将基于此库。
三、实战:在WebView里运行Gemma-2B模型
我们选择Google的轻量模型 gemma-2-2b-it 的量化版本(约1.3GB),目标是:用户在WebView的输入框提问,模型实时流式输出回答,就像和服务端通信一样,但全程在本地运行。
3.1 环境准备
确保你的App内嵌的WebView支持WebGPU。以Android为例,需要系统WebView版本 ≥ 121,并开启相关flag。iOS同理,需要15.0+,WKWebView默认支持。
首先,创建一个简单的HTML页面,引入Transformers.js:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>WebView LLM Demo</title>
<script type="module">
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.2';
// 你的代码将写在这里
</script>
</head>
<body>
<textarea id="input" placeholder="输入你的问题..."></textarea>
<button id="submit">发送</button>
<div id="output"></div>
</body>
</html>
3.2 加载模型并创建生成器
Transformers.js提供了 pipeline API,类似Python版的体验。我们使用 text-generation pipeline,并指定模型为 Xenova/gemma-2-2b-it(一个ONNX量化版本)。同时,为了能在WebView的有限内存中跑起来,需要做一些配置:
const generator = await pipeline(
'text-generation',
'Xenova/gemma-2-2b-it',
{
// 使用WebGPU加速,若不可用则回退到CPU(极慢)
device: 'webgpu',
// 模型缓存到浏览器IndexedDB,下次加载更快
cache_dir: './models',
// 量化类型,进一步减少内存
dtype: 'q4f16',
}
);
首次加载会下载约1.3GB的模型文件,需要给用户一个进度提示:
const generator = await pipeline(..., {
progress_callback: (progress) => {
console.log(`加载中: ${progress.loaded}/${progress.total}`);
// 更新UI进度条
}
});
3.3 流式生成(关键)
为了做到打字机效果,我们需要开启流式输出。Transformers.js支持在 generate 时传入回调函数,不断获取新token:
document.getElementById('submit').addEventListener('click', async () => {
const inputText = document.getElementById('input').value;
const outputDiv = document.getElementById('output');
outputDiv.textContent = '';
// 构建对话模板(Gemma-2-it格式)
const messages = [
{ role: 'user', content: inputText }
];
const stream = await generator(messages, {
max_new_tokens: 512,
temperature: 0.7,
do_sample: true,
// 关键:流式回调
callback_function: (token, tokens, generationComplete) => {
// token是当前生成的文本片段
outputDiv.textContent += token;
// 自动滚动到底部
window.scrollTo(0, document.body.scrollHeight);
}
});
// 完成后,stream是完整的生成文本
console.log('生成完成:', stream[0].generated_text);
});
注意:不同模型的对话模板不同,这里的Gemma-2-it模型需要 messages 数组格式,库内部会自动拼接成Prompt。
3.4 优化体验:Service Worker缓存模型
模型文件较大,每次打开页面都下载是不可接受的。我们可以注册Service Worker,拦截模型请求并缓存到CacheStorage,实现“一次下载,永久离线”。Transformers.js内部使用fetch加载模型,所以SW可以透明接管:
// sw.js
const CACHE_NAME = 'llm-models-v1';
self.addEventListener('fetch', (event) => {
const url = event.request.url;
if (url.includes('huggingface') || url.includes('onnx')) {
event.respondWith(
caches.open(CACHE_NAME).then(cache =>
cache.match(event.request).then(res =>
res || fetch(event.request).then(response => {
cache.put(event.request, response.clone());
return response;
})
)
)
);
}
});
这样,即使App进入后台或被杀死,再次打开WebView时模型依然从本地缓存加载,速度飞快。
四、WebView特定适配与性能调优
在原生App的WebView中,我们还能做一些特殊处理来提升体验:
- Android WebView 可开启硬件加速,并在
onPageFinished中注入JavaScript调优参数,比如增大GPU内存限制(尝试--enable-unsafe-webgpuflag)。 - iOS WKWebView 默认开启WebGPU,但建议将模型放在
IndexedDB中持久化,而非内存缓存,避免被系统清理。 - 温度控制:移动端容易发热,可适当降低生成速度(如调整
max_new_tokens和do_sample),或在检测到温度升高时暂停推理。
实测:在骁龙8Gen2手机上,Gemma-2B-q4的推理速度约10-15 token/s,完全满足对话交互。
五、避坑指南
-
不支持WebGPU怎么办?
可回退到WebAssembly(CPU)模式,但速度慢5-10倍。建议检测支持性,给用户明确提示。 -
内存溢出
2B量化的模型占用内存约1.5GB,加上WebView本身开销,低端机可能闪退。可在加载前评估可用内存,或提供更小的模型(如Phi-3-mini)。 -
Token生成乱码
很可能是Tokenizer配置不匹配,确保使用模型卡上config.json和tokenizer.json对应的版本。 -
跨域问题
本地开发时,WebView加载本地HTML文件可能遇到跨域限制,建议通过原生代码将HTML注入或使用本地服务器(如http://localhost:8080)。
六、总结与展望
通过 Transformers.js,我们轻松在 App 的 WebView 里跑起了 LLM,实现了真正的离线智能。这种方案尤其适用于隐私敏感的问答助手、本地知识库检索等场景。未来,随着 WebGPU 规范的进一步成熟和更小更强的模型涌现(如 MobileLLM、Phi 系列),浏览器端 AI 将不再只是玩具,而会成为混合架构的关键一环。
趁现在,赶紧在你的App里尝试吧!如果觉得有帮助,欢迎点赞收藏~ 🚀
本文首发于CSDN,转载请注明出处。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)