Transformers.js 讓網頁開發者能透過任務專屬的管線,在網頁應用程式中輕鬆運用 Transformer 模型的力量。開發者只需建立 pipeline() 實例並指定任務,即可在瀏覽器中執行推論。以下程式碼片段展示如何設定自動語音辨識 (ASR) 管線的具體範例。
在原始碼中,我們指定了 Xenova/whisper-tiny.en 作為模型,這是常見英文自動語音辨識任務的絕佳選擇,甚至也是 Transformers.js 預設模型解析度中的預設模型。
當您在瀏覽器中執行此範例時,Transformers.js 會自動處理相關模型資源和 Wasm 檔案的下載與快取。下圖顯示造訪應用程式後 Chrome 開發者工具的快取儲存區塊。當您重新載入頁面時,資源會從快取 API 提供,模型幾乎能立即返回結果。
然而,Xenova/whisper-tiny.en 是一個熱門模型,您可能會造訪多個使用它的應用程式。為了模擬這種情況,我們將相同的範例應用程式從不同來源提供。當您造訪這個不同來源的應用程式時,瀏覽器必須再次下載並快取所有模型資源,即使它們與之前完全相同,也無法立即使用。即使在這個簡單的範例中,這也導致了 177 MB 的重複下載和儲存,您可以想像這種情況很快就會累積起來。
情況甚至更糟。讓我們在範例中加入第二個管線:情感分析。情感分析預設使用 Xenova/distilbert-base-uncased-finetuned-sst-2-english 模型。如果不指定模型,Transformers.js 的預設模型解析度會自動為您選擇。
這兩個完全不同的 AI 模型,卻都依賴於底層 ONNX Runtime 函式庫中相同的 4,733 kB ort-wasm-simd-threaded.asyncify.wasm WebAssembly (Wasm) 執行環境檔案。在不同來源開啟擴展的示範,您會在網路分頁中注意到 Wasm 執行環境也再次被下載和快取。
因此,即使您執行的應用程式不共享相同的 AI 模型,您的瀏覽器仍會對您已擁有的共享 Wasm 資源發出冗餘請求,並且再次快取它們,這會消耗您硬碟上的空間。
預設情況下,AI 模型資源來自 Hugging Face Hub,最終由 Hugging Face CDN 提供。瀏覽器會請求像 https://huggingface.co/Xenova/distilbert-base-uncased-finetuned-sst-2-english/resolve/main/config.json 這樣的資源,然後被重新導向到最終的 CDN URL。
Wasm 執行環境資源預設由 jsDelivr CDN 提供。例如,ort-wasm-simd-threaded.asyncify.wasm 來自 https://cdn.jsdelivr.net/npm/onnxruntime-web@1.26.0-dev.20260416-b7804b056c/dist/ort-wasm-simd-threaded.asyncify.wasm。
您可能會說,如果不同的應用程式,即使在不同來源運行,最終都從相同的 CDN URL 提供資源,只要最終 URL 相同,快取就不應該是問題。不幸的是,這與瀏覽器長期以來的快取運作方式不同。文章《透過分割快取來獲得安全與隱私》詳細解釋了所有細節,但本質上,快取是按來源隔離的,以防止時間攻擊。網站響應 HTTP 請求的時間可以揭示瀏覽器過去是否訪問過相同的資源,這使得瀏覽器容易受到安全和隱私洩露的影響。
具體實作可能因瀏覽器而異,但在 Chrome 中,快取資源除了資源 URL 外,還會使用網路隔離金鑰 (Network Isolation Key) 來作為鍵值。網路隔離金鑰由頂層網站和當前框架網站組成。以之前託管在 https://googlechrome.github.io 和 https://rawcdn.rawgit.net 來源的範例為例,如果它們都使用相同的 Wasm 執行環境,它們的快取鍵將會不同。
因此,即使資源 URL 完全相同,由於網路隔離金鑰不匹配,也不會發生快取命中,這意味著重複下載和重複儲存。這正是跨來源儲存提案旨在解決的挑戰。
跨來源儲存 (Cross-Origin Storage, COS) API 引入了一個專用的 navigator.crossOriginStorage 介面,透過該介面,網頁應用程式可以跨來源邊界儲存和檢索大型檔案,其識別方式不是透過 URL,而是透過加密雜湊。
關於加密雜湊的最後一點是關鍵。因為 COS 透過雜湊而不是 URL 或來源來識別檔案,所以您在造訪 https://googlechrome.github.io 時下載的相同 ort-wasm-simd-threaded.asyncify.wasm Wasm 執行環境,將被識別為與 https://rawcdn.rawgit.net 即將請求的檔案相同,無論這兩個來源是從何處獲取它。
如果資源存在於 COS 中,您會獲得一個 FileSystemFileHandle,您可以直接透過 getFile() 讀取 Blob。如果資源不在 COS 中,您會回退到網路下載,然後將資源儲存到 COS 中,供下次需要它的應用程式使用,這可能是您的應用程式,也可能是另一個不相關的應用程式,甚至可能在完全不同的來源上。
該 API 的設計刻意模仿了您可能從來源私有檔案系統 (Origin Private File System, OPFS) API 熟悉的檔案系統標準 FileSystemDirectoryHandle.getFileHandle()。
雜湊參數扮演的角色與 OPFS 中的名稱參數相同:唯一識別資源。options.create 旗標的運作方式也相同:讀取存取時為空或 false,當您打算寫入時為 true。
並非所有資源都應該全球共享。COS 透過儲存檔案時的 origins 選項,讓開發者能精確控制可見性。
設定 origins: '*' 使檔案全球可用,任何來源都可以透過雜湊找到它。這對於 Transformers.js 範例中的 AI 模型資源或 Wasm 執行環境是正確的選擇:重點是讓網路上每個應用程式都能從單一快取副本中受益。
傳遞特定來源列表,例如 origins: ['https://write.example.com', 'https://calculate.example.com'],將存取權限限制在這些網站。這適用於公司內部共享的專有資源,不應被其他人發現,例如商業辦公套件中使用的專有校對 AI 模型。
完全省略 origins 會使檔案僅對同站來源可用。這對於組織所有子網域之間共享但無意跨組織邊界的資源來說,是一個合理的預設值。
一個重要的規則是:可見性可以升級但永遠不能降級。如果一個檔案已經全球可用,之後嘗試以受限的 origins 列表儲存它將被靜默忽略。這可以防止惡意行為者重新儲存公共資源並縮小其可用性。
反之則可能:最初以受限 origins 列表儲存的檔案,之後可以變得更寬鬆。任何網站,不僅是原始儲存者,都可以使用 create: true 和更廣泛的 origins 值呼叫 requestFileHandle(),並且只要瀏覽器驗證雜湊匹配,該資源從那時起就可供更廣泛的受眾使用。
請注意,升級的網站仍必須透過返回的 handle 寫入完整檔案。此要求是為了防止網站利用升級路徑作為側通道來檢測特定檔案是否已儲存在 COS 中。
COS 一個微妙但重要的特性是,當您寫入檔案時,瀏覽器會驗證雜湊。如果您寫入的資料與聲明的雜湊不匹配,寫入將會失敗並出現錯誤。這使得完整性檢查自動化:從 COS 讀取檔案的應用程式可以確信它正在獲取預期的位元組。這與它在網路下載後自行計算雜湊所獲得的保證相同。
這在 Transformers.js 的情境中尤其有用。如今,下載模型權重後,大多數應用程式沒有實際方法來驗證 CDN 是否提供了正確的位元組。有了 COS,儲存中的每個檔案在寫入時都會隱式驗證,無論它來自何處,是官方的 Hugging Face CDN 還是隨機網站的自託管鏡像。
當然,跨來源共享快取提出了與分割 HTTP 快取相反的相同問題:如果任何網站都可以探測



