[控场AI]
· 8 分钟阅读· 4,399 字

浏览器里跑RAG:小语言模型的实测与反思

浏览器里跑RAG:小语言模型的实测与反思

浏览器端RAG链路已跑通,但小模型忠实度极低,检索质量决定上限。

文章记录了一次把完整RAG链路搬到浏览器的工程实验:检索、门控、提示构造与生成全部在客户端完成,模型经transformers.js在WebGPU或WASM上运行,数据不出本机。作者用30道可回答问题加15道陷阱题评测了SmolLM2、Gemma 3 270M、Qwen3-0.6B等小模型,并加入Gemma 4 E2B与Haiku作对照。结论是350MB以下的现成模型几乎不可用,30题中最多仅3次忠实,且几乎不主动拒答;相关性门控只能拦明显跑题,擦边问题分数反而更高;允许输出更多句子会进一步拉低忠实度。成本上API远优于自托管云GPU。

在浏览器中运行语言模型已经不算新鲜事,把检索增强生成(RAG)的整条链路也搬到客户端,却是一次有趣的工程实验。一位开发者在自己的博客上做了这件事:搜索在你的浏览器里找段落,一个不到600MB的小模型在你的GPU上读这些段落并生成两句摘要,全程不联网、不上传任何数据。

这篇文章不打算复述“太酷了”的赞叹,而是拆开看它在技术上怎么跑通,以及为什么小模型做RAG的 faithfulness(忠实度)低得惊人。

RAG 如何在浏览器里跑起来

浏览器端RAG流程示意

整个流程完全在客户端运行,分为四步。检索:用户的问题先经过一个基于静态嵌入的搜索,命中四段最相关的段落。这个搜索本身只用一张约4MB的查找表,无需服务器。门控:如果最高分段落低于某个阈值,就不调用模型,直接提示“博客里找不到这个内容”。提示构造:把四段编号后的段落加进系统提示,要求模型最多用两句话回答,且只能用这些段落,若无法回答就直说。生成:用一个Web Worker在WebGPU上跑模型,不支持WebGPU的浏览器则退回到WASM在CPU上跑,结果流式输出,凑满两句就停。

整个过程不需要API密钥、不需要账户,模型下载几百MB后缓存在本地,之后不再重复下载。作者也提供了清除缓存的按钮,把选择权留给用户。

WebGPU 与 WASM 的区别值得展开:WebGPU 是浏览器暴露的现代图形与计算 API,能让 JavaScript 直接调用 GPU 做并行矩阵运算,适合大模型的推理加速;WASM(WebAssembly)则是可在浏览器里运行的二进制指令格式,主要跑在 CPU 上,兼容性更广但速度慢得多。文章中的回退策略正是基于这一现实:支持 WebGPU 就用 GPU,不支持则退到 CPU 跑 WASM,代价是生成速度显著下降。

Web Worker 是浏览器提供的后台线程机制,用来把模型推理这类重任务从主线程剥离,避免页面卡死。模型在 Worker 内加载权重、执行推理,通过消息通道把 token 流式回传主线程渲染。这也是为什么整个流程能做到“边生成边显示”,而不必等整段回答算完。

模型选型:小体积不等于可用

作者列出了一批有ONNX浏览器构建的候选模型:SmolLM2(135M和360M参数)、Gemma 3 270M、LFM2.5-350M、Qwen2.5-0.5B和Qwen3-0.6B。作为参照,还加入了两个“绝不会上线”的选项:需要3.1GB下载的Gemma 4 E2B,以及走API的Claude Haiku 5.5。

选型时先撞上一个反直觉的发现:对其中若干模型,标注为“4-bit”(q4)的版本反而比q4f16版本更大,因为q4导出把嵌入表保留在完整的32位精度。以SmolLM2-360M为例,q4是390MB,q4f16只有275MB,而两者输出完全一致。于是所有实测都用q4f16。

评估设计

评估复用了此前语义搜索实验的30个问题,改写成真正的疑问句,并额外加入15个博客确实回答不了的问题。这些“陷阱题”大多不是完全跑题,而是擦边:比如“本地跑Llama 70B该买哪块GPU”“BM25相比TF-IDF好在哪”“怎样微调Kokoro用自己的声音说话”。博客讨论过相关话题,但并没有给出这些问题的答案。

每个模型拿到相同的四段段落和同样的提示。Opus 5.5作为裁判,把每个答案标为忠实(所有断言都能在段落中找到)、无依据(至少有一句不在段落中,即便碰巧为真)或未作答。作者在不知道裁判结论的情况下自行标注了20条,其中16条关于“是否忠实”的判断与裁判一致。

ONNX(Open Neural Network Exchange) 是一种跨框架的模型交换格式,PyTorch、TensorFlow 等训练出的模型可以导出为 ONNX 图,再被不同运行时加载。浏览器端的 transformers.js 正是通过 ONNX Runtime Web 来执行这些模型,这也是候选模型必须“有 ONNX 浏览器构建”的原因。

q4 与 q4f16 是两种量化配置。q4 通常指将权重压到 4 位整数,但部分导出实现会保留嵌入表为 FP32;q4f16 则在此基础上把嵌入表也转成 FP16,因此文件更小。嵌入表是词表到向量的映射,参数量可观,它的精度选择会直接决定模型体积。这也解释了文中“标注为 4-bit 的版本反而更大”的反直觉现象。

小模型的表现:答案错得理直气壮

结果很直接:350MB以下的现成模型,基本都不可用。它们不是稍差一点,而是在30道可回答的问题中最多只有3次做到忠实,同时对几乎任何问题都乐于给出答案。

问“本地跑Llama 70B该买哪块GPU”,喂给它的却是四段关于嵌入和MacBook编码代理的段落,于是有了这些回答:

"...the best option to run Llama 70B locally is likely to be a NVIDIA GTX 960 or GTX 970."(SmolLM2-360M)

"...a high-performance graphics card (GPU) such as a NVIDIA A100 series (e.g., RTX 3090, RTX 3080, 3070, 3080, 3070M, 3080M)"(Gemma 3 270M)

"...popular options include RTX 3090, RTR 5900, or newer generations like TensorRT 60+"(LFM2.5-350M)

Gemma 4 E2B则正确地指出“提供的段落不包含本地运行Llama 70B该买哪块GPU的信息”。

即便在博客确实回答得了的问题上,小模型也常把内容搅乱。LFM2.5-350M解释Bloom filter时说得又快又流畅,却把位数组说成哈希表,内容基本是编的。这里也要替模型说句公道话:搜索并没有把解释Bloom filter原理的那段递给它,拿到的是关于使用场景和交互演示的段落。摘要的质量上限,就是检索给它的段落质量。

卡壳与重复惩罚

首次运行时,多数小模型的回答与其说是错,不如说是卡住了。SmolLM2-135M被问到如何给网站添加OpenSearch支持时,输出变成了“Search from your URL bar”的无限重复;Gemma 3 270M干脆吐出一长串数字直到耗尽token。

这是小模型在“永远选最可能的下一个token”时容易陷入的循环。简单的修法是加入重复惩罚(本例为1.15),但作者明确指出:它只让模型写出更长、更多样的胡话,并不会改善忠实度或质量。

重复惩罚(repetition penalty) 是解码阶段的一种采样修正:对已经出现过的 token 下调其概率,从而抑制循环。它通常与温度、top-p 等参数协同工作,值设得过高会让输出变得生硬甚至破坏语义。文中设为 1.15 属于温和档位,所以作者才会说它只是让模型“写出更长、更多样的胡话”——它改变的是表面多样性,而非模型是否依据段落作答。

token 耗尽指的是模型达到设定的最大生成长度后被迫停止。小模型陷入数字或短语循环时,往往会在耗尽全部 token 预算后才停下,表现为一段毫无信息量的长输出。

相关性门控的局限

用相关性分数做门控来拦截胡编乱造,看起来是廉价的解法。对远距离的跑题问题它确实有效:“如何在家烤酸面团面包”得到0.25分,低于0.45的阈值,直接被拦下——这很必要,因为Gemma 3对这个问题的回答是一份面包配方。

但擦边问题会拿到0.54到0.63的分数,比博客确实能回答的若干问题还高,因为它们命中了同主题的文章。若要把这些也拦下,阈值将不得不误杀30道真实问题中的13道。

门控只能挡住明显跑题的输入,剩下的全压到模型身上。这正是模型体积在这里重要的原因:Gemma 4和Haiku会说“段落没有覆盖这个问题”,而小模型从不会主动拒答。

租GPU还是用API

从成本看,绝大多数情况下用API更划算。按当时价格,云上最便宜的合适GPU(Google Cloud的NVIDIA L4)约每小时0.71美元,整月不停运行约516美元。以该博客的月访问量估算,即便每位读者都问一个问题,单次问答成本也超过一美元。而Haiku答完全部45道评测题只花了0.006美元。

作者的建议很直白:如果有真实用例,从Haiku开始。只有在合规、隐私或离线部署等硬性约束下,自托管才有理由。另一个实际提醒是,不要把API密钥放进静态站点里,避免被人薅走账单。

静态站点指只包含 HTML、CSS、JavaScript 等静态资源、由 CDN 直接分发的网站,没有可以安全保存密钥的服务端。把 API 密钥写进这类站点的前端代码,等于把密钥公开给任何打开开发者工具的人,可能被冒用并产生高额账单。这也是浏览器端方案强调“不联网、不上传数据”的另一层动机:它天然规避了密钥托管问题。

回答越长越不安全

如果Qwen3的两句话只有一半是对的,那让它多说几句会不会更好?作者用Qwen3-0.6B和Gemma 4 E2B做了对比,允许回答2句、4句或6句。

两者都随着空间变宽而更不忠实,但小模型跌得更陡:Qwen3的忠实答案从15降到9再降到5(满分30)。多一句就多一次胡编的机会。到6句时,它索性不再拒答GPU问题,而是把每段都总结一遍,最后来一句“答案取决于用户需要高性能GPU还是普通GPU”。Gemma 4也略有下滑(28、26、24),但它几乎不用多余空间(允许6句时实际约2.8句),且始终不对博客未覆盖的问题编造答案。

下一步与总结

作者的下一步是让300MB级别的模型把这件单一任务做得更好:不需要知道一切,只需要读四段并总结或诚实地说“回答不了”。这更像一个微调问题。另一个想法是把已加载的模型悄悄用于首页搜索,进一步减少额外下载。

这次实验给出的结论朴素但重要:浏览器端RAG的工程链路已经跑得通,但检索质量决定了上限,小模型的忠实度决定了可信度。对这类页面的正确用法,是先看检索到的段落,再决定要不要相信那两句摘要。

#浏览器端RAG#小语言模型#transformers.js#WebGPU推理#检索增强生成忠实度#本地LLM部署
分享:

相关推荐