:瀏覽器本地運行15億參數(shù)大模型處理Excel數(shù)據(jù))
1. 為什么要把大模型塞進瀏覽器里跑1.1 一個真實的需求場景先說清楚這件事的來龍去脈。我手頭有一批Excel文件大概三百多個每個文件里是不同區(qū)域的銷售流水字段結(jié)構(gòu)基本一致但列名有細微差異有的叫“客戶名稱”有的叫“客戶名”有的還帶空格。每個月末要做的事情就是把這些表合并、清洗、按客戶維度匯總?cè)缓笊梢环莘治鰣蟾妗R郧暗淖龇ㄊ菍慞ython腳本用pandas批量讀規(guī)則寫死遇到列名不一致就手動改腳本。后來試過調(diào)云端大模型API來做字段映射和異常檢測效果確實好但有兩個問題一直繞不過去第一數(shù)據(jù)要傳到別人的服務(wù)器上財務(wù)那邊合規(guī)過不了第二網(wǎng)絡(luò)一斷或者API限流整個流程就卡住了。于是我開始琢磨一件事能不能把模型直接放在本地跑而且不裝Python環(huán)境、不配CUDA、不折騰命令行打開瀏覽器就能用這就是“把15億參數(shù)大模型塞進瀏覽器”這個項目的起點。核心思路是利用WebGPU在瀏覽器里做本地推理把模型權(quán)重下載到本地緩存通過一個瀏覽器插件在Excel頁面?zhèn)冗厵诶镏苯诱{(diào)用數(shù)據(jù)從頭到尾不出電腦斷網(wǎng)也能用。這件事適合什么人參考如果你經(jīng)常用Excel做批量數(shù)據(jù)處理對數(shù)據(jù)隱私有要求又不想學一整套深度學習部署流程那這套方案值得一看。如果你本身是前端或者全棧開發(fā)者想了解WebGPU在實際業(yè)務(wù)里怎么落地里面的工程細節(jié)也有參考價值。哪怕你只是好奇“瀏覽器里跑大模型”到底靠不靠譜我也會把實測數(shù)據(jù)和踩過的坑都擺出來。1.2 為什么是15億參數(shù)這個量級模型參數(shù)量的選擇不是拍腦袋定的。我試過三個量級3B、1.5B和0.5B。3B的模型在WebGPU上跑顯存占用大概在2.2GB左右推理一條500字的輸入需要8到12秒對于批量處理三百個文件來說太慢了。0.5B的模型速度快單條推理1到2秒但在字段映射這種需要理解語義的任務(wù)上準確率明顯不夠經(jīng)常把“客戶名稱”和“聯(lián)系人”搞混。1.5B這個量級是一個比較舒服的平衡點。量化到INT4之后模型文件大概在900MB到1.1GB之間瀏覽器緩存完全放得下。推理時顯存占用在1.3GB左右主流核顯和獨顯都能扛住。單條推理時間在3到5秒三百個文件如果每個文件抽10條樣本做字段推斷總共3000次推理大概兩個半小時能跑完。這個速度對于月末批量處理來說完全可以接受而且是后臺跑不耽誤你干別的。注意這里說的“顯存”在WebGPU里其實是GPU內(nèi)存集顯會共享系統(tǒng)內(nèi)存。如果你的電腦只有8GB內(nèi)存同時開著Excel和瀏覽器可能會有點吃緊建議16GB起步。1.3 WebGPU到底解決了什么問題以前在瀏覽器里跑模型只能用WebAssembly加CPU推理速度慢得讓人想砸鍵盤。WebGPU的出現(xiàn)改變了這個局面它讓JavaScript能直接調(diào)用GPU做并行計算推理速度比純CPU快了大概8到15倍。更關(guān)鍵的是WebGPU是瀏覽器原生支持的不需要裝任何驅(qū)動或者運行時Chrome 113之后默認開啟Edge和Firefox也在陸續(xù)跟進。我用下來最直觀的感受是以前在瀏覽器里跑1.5B模型一條推理要等半分鐘現(xiàn)在3到5秒就出結(jié)果。這個速度差距決定了它能不能用在真實業(yè)務(wù)里。另一個好處是WebGPU的API設(shè)計比WebGL更貼近現(xiàn)代GPU編程模型寫compute shader的時候心智負擔小很多調(diào)試也方便。2. 整體架構(gòu)與核心組件拆解2.1 三層結(jié)構(gòu)插件層、推理層、數(shù)據(jù)層整個方案我拆成了三層。最上面是瀏覽器插件層負責和Excel頁面交互讀取單元格數(shù)據(jù)、展示推理結(jié)果、管理任務(wù)隊列。中間是推理層基于WebGPU加載量化后的模型提供文本生成和語義理解能力。最下面是數(shù)據(jù)層負責Excel文件的解析、字段提取、結(jié)果寫回以及本地緩存管理。這三層之間通過消息傳遞通信。插件的內(nèi)容腳本注入到Excel頁面里通過chrome.runtime.sendMessage和后臺Service Worker通信后臺再調(diào)用Offscreen Document里的WebGPU推理引擎。為什么要繞這么一圈因為Service Worker里不能直接訪問DOM也不能穩(wěn)定持有WebGPU上下文而Offscreen Document可以。這個架構(gòu)是試了好幾種方案之后定下來的后面會詳細說。2.2 模型選型為什么選1.5B的指令微調(diào)模型模型選型上我對比了幾個方向。首先是基座模型和指令微調(diào)模型的選擇做字段映射和異常檢測需要模型能理解自然語言指令所以必須用指令微調(diào)過的版本。其次是中文能力Excel里的字段名和備注基本都是中文英文模型直接排除。我最終選的是一個1.5B參數(shù)的中文指令微調(diào)模型具體名字就不說了市面上有好幾個可選項選哪個主要看你的任務(wù)類型。選它的理由有三個第一參數(shù)量適中量化后體積可控第二中文語義理解在同類模型里屬于第一梯隊第三社區(qū)有現(xiàn)成的ONNX導出腳本省去了自己轉(zhuǎn)換的麻煩。量化方案用的是INT4具體是GPTQ還是AWQ取決于模型本身支持哪種。INT4量化后模型精度損失大概在2%到5%之間對于字段映射這種任務(wù)來說完全夠用。如果你要做更復(fù)雜的推理比如從流水描述里判斷交易類型可能需要INT8或者FP16但那樣模型體積和推理時間都會翻倍。2.3 瀏覽器插件開發(fā)的關(guān)鍵技術(shù)點插件開發(fā)這塊有幾個坑值得單獨說。首先是Manifest V3的限制Service Worker是事件驅(qū)動的隨時可能被瀏覽器回收所以不能把模型加載這種耗時操作放在Service Worker里。我的做法是創(chuàng)建一個Offscreen Document在里面初始化WebGPU設(shè)備和模型Service Worker只負責轉(zhuǎn)發(fā)消息。其次是內(nèi)容腳本和頁面腳本的隔離。Excel Online的頁面結(jié)構(gòu)比較復(fù)雜直接操作DOM容易出問題。我的做法是通過chrome.scripting.executeScript注入一個函數(shù)在頁面上下文里讀取選區(qū)數(shù)據(jù)然后通過postMessage傳回內(nèi)容腳本。這樣既能拿到數(shù)據(jù)又不會污染頁面環(huán)境。還有一個細節(jié)是跨域問題。模型文件如果放在遠程服務(wù)器上需要配置CORS頭。我的做法是把模型文件打包進插件資源里通過chrome.runtime.getURL訪問這樣完全避免了跨域問題而且斷網(wǎng)也能用。代價是插件包體積會大一些1.5B INT4模型大概1GB左右但現(xiàn)在的網(wǎng)絡(luò)條件下載一次也不算什么事。3. 核心細節(jié)解析與實操要點3.1 WebGPU初始化與模型加載流程WebGPU的初始化流程比WebGL要嚴謹一些需要按順序請求適配器和設(shè)備。下面是我實際用的代碼骨架你可以直接參考async function initWebGPU() { if (!navigator.gpu) { throw new Error(當前瀏覽器不支持WebGPU請升級到Chrome 113); } const adapter await navigator.gpu.requestAdapter({ powerPreference: high-performance }); if (!adapter) { throw new Error(無法獲取GPU適配器請檢查顯卡驅(qū)動); } const device await adapter.requestDevice({ requiredLimits: { maxStorageBufferBindingSize: 1024 * 1024 * 1024, maxBufferSize: 1024 * 1024 * 1024 } }); return { adapter, device }; }這里有幾個參數(shù)需要根據(jù)你的模型調(diào)整。maxStorageBufferBindingSize和maxBufferSize默認值比較小加載大模型的時候會報錯需要顯式請求更大的值。但也不能隨便設(shè)成無限大要先通過adapter.limits查詢設(shè)備實際支持的上限取一個不超過上限的值。模型加載用的是ONNX Runtime Web的WebGPU后端。加載流程分兩步先下載模型文件到瀏覽器緩存然后用ort.InferenceSession.create創(chuàng)建推理會話。第一次加載會比較慢1GB的模型大概需要20到30秒之后從緩存讀取就快很多5秒左右能完成初始化。實操心得模型加載過程中瀏覽器可能會提示“頁面無響應(yīng)”這是正常的因為主線程被占用了。我的做法是把加載邏輯放在Web Worker里通過postMessage匯報進度這樣頁面不會卡死用戶能看到加載百分比。3.2 Excel數(shù)據(jù)讀取與字段提取Excel數(shù)據(jù)的讀取分兩種情況。如果是Excel Online可以通過Office.js的API直接讀取選區(qū)和工作表數(shù)據(jù)。如果是本地Excel文件我的做法是讓用戶把文件拖到插件面板里用SheetJS解析成JSON。兩種方式最終都歸一化成同樣的數(shù)據(jù)結(jié)構(gòu)方便后續(xù)處理。字段提取的核心邏輯是先讀取表頭行把每個列名和該列的前若干條樣本數(shù)據(jù)一起打包成一個提示詞讓模型判斷這個列的實際語義。提示詞模板大概長這樣你是一個數(shù)據(jù)字段分析助手。請根據(jù)以下列名和樣本數(shù)據(jù)判斷該列的實際含義并從候選類別中選擇最匹配的一個。 列名客戶名稱 樣本數(shù)據(jù)張三、李四、王五貿(mào)易有限公司、趙六 候選類別客戶姓名、公司名稱、聯(lián)系人、產(chǎn)品名稱、金額、日期、備注 請只輸出類別名稱不要解釋。這個提示詞我調(diào)了好幾版。最早的時候讓模型直接輸出字段含義結(jié)果它經(jīng)常自由發(fā)揮輸出一長串解釋。后來改成從候選類別里選準確率明顯提升。候選類別是根據(jù)我實際業(yè)務(wù)場景預(yù)定義的大概二十多個覆蓋了常見的銷售流水字段。3.3 批量任務(wù)隊列與并發(fā)控制三百個文件如果一個個串行處理用戶體驗很差。我的做法是建一個任務(wù)隊列同時跑2到3個推理任務(wù)。為什么不是越多越好因為WebGPU的顯存有限同時跑太多任務(wù)會導致顯存溢出瀏覽器直接崩潰。實測下來1.5B INT4模型同時跑3個任務(wù)是上限再多就不穩(wěn)定了。隊列的實現(xiàn)用了一個簡單的信號量模式class TaskQueue { constructor(concurrency 2) { this.concurrency concurrency; this.running 0; this.queue []; } async add(task) { return new Promise((resolve, reject) { this.queue.push({ task, resolve, reject }); this.next(); }); } async next() { if (this.running this.concurrency || this.queue.length 0) return; this.running; const { task, resolve, reject } this.queue.shift(); try { const result await task(); resolve(result); } catch (err) { reject(err); } finally { this.running--; this.next(); } } }這個隊列看起來簡單但實際用的時候要注意錯誤處理。如果某個任務(wù)拋異常了不能讓整個隊列卡死所以finally里一定要調(diào)next()。另外任務(wù)結(jié)果要實時寫回Excel不能等全部跑完再寫否則用戶看不到進度會以為程序卡了。3.4 結(jié)果寫回與格式保持結(jié)果寫回Excel的時候有個坑直接改單元格值會丟失原有格式。比如原來單元格是日期格式你寫個字符串進去格式就亂了。我的做法是只改值不改格式用Office.js的range.values賦值而不是重建整個工作表。如果是本地文件用SheetJS寫回的時候要注意保留原有的樣式信息。SheetJS的社區(qū)版對樣式支持有限我的做法是只更新數(shù)據(jù)區(qū)域其他部分原樣保留。具體操作是先讀取整個工作簿修改目標單元格的值然后整體寫回。這樣雖然會丟失一些高級樣式但至少不會把表格搞亂。4. 實操過程與核心環(huán)節(jié)實現(xiàn)4.1 環(huán)境準備與插件骨架搭建先說一下開發(fā)環(huán)境。你需要Node.js 18以上Chrome 113以上以及一個支持WebGPU的顯卡。我用的是一臺帶RTX 3060的筆記本后來在MacBook M1上也測過都能跑。核顯的話Intel Iris Xe實測也能跑但速度慢一些單條推理大概6到8秒。插件骨架用Vite加CRXJS來搭這樣開發(fā)的時候有熱更新調(diào)試方便。目錄結(jié)構(gòu)大概是這樣src/ background/ # Service Worker content/ # 內(nèi)容腳本 offscreen/ # WebGPU推理引擎 popup/ # 插件彈窗 shared/ # 公共工具函數(shù) public/ models/ # 模型文件 manifest.jsonManifest V3的配置里要特別注意offscreen權(quán)限和webgpu相關(guān)的設(shè)置。offscreen文檔的創(chuàng)建需要在Service Worker里調(diào)用chrome.offscreen.createDocument傳入reasons: [WORKERS]和justification。4.2 模型轉(zhuǎn)換與量化實操模型轉(zhuǎn)換是整個流程里最耗時的環(huán)節(jié)。我用的方案是先把原始模型導出成ONNX格式然后用ONNX Runtime的量化工具做INT4量化。具體命令大概是這樣python -m onnxruntime.transformers.optimizer \ --input model.onnx \ --output model_optimized.onnx \ --model_type bert python -m onnxruntime.quantization.preprocess \ --input model_optimized.onnx \ --output model_preprocessed.onnx python -m onnxruntime.quantization.quantize \ --input model_preprocessed.onnx \ --output model_int4.onnx \ --weight_type int4量化過程中要注意校準數(shù)據(jù)的選擇。校準數(shù)據(jù)應(yīng)該從你的實際業(yè)務(wù)數(shù)據(jù)里采樣而不是用通用語料。我用了一百條真實的Excel字段名和樣本數(shù)據(jù)做校準量化后的模型在字段映射任務(wù)上的準確率比用通用校準數(shù)據(jù)高了大概7個百分點。注意INT4量化對模型結(jié)構(gòu)有要求不是所有模型都能直接量化。如果遇到不支持的算子可以嘗試混合量化把部分層保持FP16其余層用INT4。ONNX Runtime的文檔里有詳細說明。4.3 推理性能實測數(shù)據(jù)我在三臺設(shè)備上做了性能測試測試任務(wù)是字段映射輸入長度平均80個token輸出長度平均5個token。結(jié)果如下設(shè)備GPU模型加載時間單條推理時間顯存占用筆記本RTX 306022秒3.2秒1.3GBMacBookM1 8核GPU28秒4.1秒1.5GB輕薄本Intel Iris Xe35秒7.8秒1.8GB從數(shù)據(jù)可以看出獨顯和蘋果芯片的表現(xiàn)最好核顯也能用但速度慢一倍左右。顯存占用都在2GB以內(nèi)主流設(shè)備都能承受。模型加載時間第一次比較長之后從緩存讀取會快很多大概5到8秒。批量處理三百個文件每個文件抽10條樣本總共3000次推理。在RTX 3060上加上隊列調(diào)度和數(shù)據(jù)讀寫開銷總耗時大概2小時40分鐘。這個時間是在后臺跑的你可以正常用電腦干別的只是別同時跑大型游戲或者視頻渲染。4.4 斷網(wǎng)環(huán)境下的完整驗證斷網(wǎng)測試是我最看重的環(huán)節(jié)。具體做法是先把模型加載好然后斷開網(wǎng)絡(luò)再執(zhí)行批量處理任務(wù)。實測下來只要模型已經(jīng)加載到內(nèi)存里斷網(wǎng)完全不影響推理。Excel文件的讀取和寫回也都是本地操作不依賴網(wǎng)絡(luò)。但有一個細節(jié)要注意如果瀏覽器緩存被清了模型文件就沒了下次打開需要重新下載。我的做法是在插件里加了一個“模型管理”頁面顯示模型緩存狀態(tài)并提供手動清理和重新下載的按鈕。另外如果用戶用的是Excel Online斷網(wǎng)后頁面本身就無法訪問了所以這個方案更適合本地Excel文件。5. 常見問題與排查技巧實錄5.1 WebGPU初始化失敗怎么辦這是最常見的問題表現(xiàn)是navigator.gpu返回undefined或者requestAdapter返回null。排查思路按順序來第一確認瀏覽器版本Chrome 113以上才默認開啟WebGPU低版本需要在chrome://flags里手動開啟。第二確認顯卡驅(qū)動是最新的老驅(qū)動可能不支持WebGPU。第三檢查是否在chrome://gpu里看到WebGPU被禁用如果是看看禁用原因是什么。還有一個隱蔽的問題某些企業(yè)的組策略會禁用WebGPU。如果你在公司電腦上跑不起來先問問IT部門有沒有相關(guān)限制。我遇到過一臺電腦所有配置都正常就是requestAdapter返回null最后發(fā)現(xiàn)是組策略里禁用了硬件加速。5.2 模型加載到一半卡住模型加載卡住通常有兩個原因。一是顯存不足加載到一半顯存溢出瀏覽器直接崩潰或者卡死。解決辦法是降低量化精度或者換更小的模型。二是模型文件損壞下載過程中斷了。解決辦法是清理瀏覽器緩存重新下載或者在插件里加一個文件完整性校驗。我遇到過一次比較詭異的情況模型加載到90%卡住等了十分鐘也沒動靜。后來發(fā)現(xiàn)是ONNX Runtime在編譯shader這個過程在有些顯卡上特別慢。解決辦法是提前預(yù)熱在插件啟動的時候先跑一次空推理把shader編譯好后續(xù)加載就快了。5.3 推理結(jié)果不穩(wěn)定怎么調(diào)推理結(jié)果不穩(wěn)定表現(xiàn)為同樣的輸入有時候輸出正確有時候輸出亂七八糟的東西。這個問題通常和提示詞有關(guān)。我的經(jīng)驗是第一提示詞要盡可能明確給出候選類別比讓模型自由發(fā)揮要穩(wěn)定得多。第二溫度參數(shù)調(diào)到0.1以下減少隨機性。第三如果還是不穩(wěn)定可以在提示詞里加幾個示例做少樣本學習。還有一個容易被忽略的點輸入文本的格式。如果樣本數(shù)據(jù)里有特殊字符或者換行符可能會干擾模型。我的做法是在拼接提示詞之前先把樣本數(shù)據(jù)做一次清洗去掉多余的空格和換行。5.4 Excel數(shù)據(jù)讀取的兼容性問題Excel的版本和格式差異很大xlsx、xls、csv各有各的坑。我的經(jīng)驗是第一優(yōu)先用Office.js讀取Excel Online的數(shù)據(jù)兼容性最好。第二本地文件用SheetJS解析但要注意xls格式的支持有限建議用戶另存為xlsx。第三CSV文件的編碼問題很常見UTF-8和GBK要自動識別否則中文會亂碼。還有一個坑是合并單元格。如果表頭有合并單元格讀取出來的列名可能是空的。我的做法是檢測合并區(qū)域把合并單元格的值填充到所有子單元格。這個邏輯用Office.js實現(xiàn)比較方便SheetJS的話需要手動處理merge屬性。5.5 常見問題速查表問題現(xiàn)象可能原因排查方法解決方案WebGPU不可用瀏覽器版本低檢查Chrome版本升級到113適配器獲取失敗驅(qū)動過舊查看chrome://gpu更新顯卡驅(qū)動模型加載卡住顯存不足查看任務(wù)管理器降低量化精度推理結(jié)果亂碼提示詞不明確檢查提示詞模板增加候選類別Excel讀取失敗文件格式不支持檢查文件擴展名另存為xlsx批量處理中斷隊列異常查看控制臺日志加錯誤重試機制6. 這套方案還能怎么擴展6.1 從字段映射擴展到數(shù)據(jù)清洗字段映射只是第一步同樣的架構(gòu)可以擴展到數(shù)據(jù)清洗。比如檢測異常值、填充缺失值、標準化日期格式這些任務(wù)都可以用本地模型來做。我最近在試的一個場景是讓模型判斷某條流水記錄是否可疑比如金額異常大或者客戶名稱和備注不匹配。初步測試下來1.5B模型在二分類任務(wù)上的準確率能到85%左右雖然不如云端大模型但勝在數(shù)據(jù)不出本地。6.2 多模型協(xié)同的可能性單個1.5B模型的能力有限但可以多個模型協(xié)同。比如用一個模型做字段映射另一個模型做數(shù)據(jù)校驗還有一個模型生成匯總報告。WebGPU支持同時加載多個模型只要顯存夠用。我試過同時加載兩個1.5B模型顯存占用2.6GBRTX 3060完全扛得住。這種多模型協(xié)同的思路可以在不增加單模型參數(shù)量的前提下提升整體處理能力。6.3 插件分發(fā)的注意事項如果你想把插件分享給同事用有幾個事情要提前考慮。第一模型文件太大不適合放在Chrome Web Store上我的做法是插件本體很小模型文件放在內(nèi)部服務(wù)器上首次使用時下載。第二企業(yè)環(huán)境可能需要配置代理這個要提前和IT溝通。第三插件的權(quán)限要最小化只申請必要的權(quán)限否則審核和安裝都會遇到阻力。我個人在實際操作中的體會是這套方案最大的價值不是技術(shù)本身而是它改變了數(shù)據(jù)處理的邊界。以前必須把數(shù)據(jù)傳到云端才能用大模型現(xiàn)在在本地就能完成這對于有數(shù)據(jù)合規(guī)要求的場景來說意義很大。當然它也有局限1.5B模型的能力上限就在那里復(fù)雜的推理任務(wù)還是得靠更大的模型。但對于字段映射、數(shù)據(jù)清洗這類結(jié)構(gòu)化任務(wù)來說它已經(jīng)足夠好用了。