在 Chrome 擴充功能中使用 Transformers.js
在 Chrome 擴充功能中使用 Transformers.js
Hugging Face 已發布一個由 Gemma 4 E2B 驅動的示範瀏覽器擴充功能,以示範如何在 Chrome 擴充功能內執行本地 AI 功能。該實作在 Manifest V3 條件下利用 Transformers.js,採用去耦合架構,其中背景服務工作者負責模型編排,而 UI 和內容腳本則保持為薄客戶端。
Chrome 擴充功能架構 (Manifest V3)
核心架構策略是將關注點分離到三個主要的 Chrome 執行階段環境,以確保 UI 響應性並避免重複載入模型。
執行階段環境與入口點
如在 manifest.json 中所定義,該擴充功能使用三個入口點:
- 背景服務工作者 (
background.js): 作為控制平面,負責代理生命週期、模型初始化及工具執行。 - 側邊面板 (
sidebar.html): 作為聊天輸入/輸出與串流更新的互動層。 - 內容腳本 (
content.js): 作為頁面橋樑,負責 DOM 提取與標記動作。
訊息與編排
由於這些執行階段是隔離的,一個型別化的訊息合約(透過 enum 定義)協調動作。背景服務工作者充當單一協調者:
- 側邊面板發送一個請求(例如
AGENT_GENERATE_TEXT)。 - 背景工作者將訊息附加到對話歷史中,執行推論並執行工具。
- 背景工作者發出一個更新(例如
MESSAGES_UPDATE)回傳給側邊面板以進行渲染。
Transformers.js 整合細節
模型角色與職責
該擴充功能採用兩種不同的模型來平衡推理與檢索:
- 文字生成 (LLM):
onnx-community/gemma-4-E2B-it-ONNX(q4f16) 負責推理與工具呼叫決策。 - 向量嵌入:
onnx-community/all-MiniLM-L6-v2-ONNX(fp32) 產生用於歷史與網站內容語義相似度搜尋的嵌入向量。
推論與快取
所有推論均在背景服務工作者內使用 pipeline("text-generation", ...) 並搭配 DynamicCache 類別以實現一致的 KV 快取,以及使用 pipeline("feature-extraction", ...) 進行嵌入提取。
在背景工作者中託管推論可確保模型構件被快取在擴充功能來源 (chrome-extension://<extension-id>) 下,而非每個網站來源,從而在整個安裝中提供共享快取。開發者必須考量 Manifest V3 生命週期,因為服務工作者可能會被暫停並重新啟動,這需要模型執行時狀態可被恢復。
代理與工具執行迴路
工具呼叫機制
Transformers.js 使用模型特定的聊天模板來格式化提示。對於 Gemma 4,當模型決定呼叫工具時,會發出一個特殊的工具呼叫標記區塊(例如 <|tool_call>call:getWeather{location:<|">Bern<|">}<tool_call|>)。擴充功能使用一個標準化層 (webMcp) 和一個解析器 (extractToolCalls) 將這些模型輸出轉換為確定性執行。
迴路設計 (Agent.runAgent)
該擴充功能將內部模型逐字稿與面向使用者的聊天訊息分開:
- 內部逐字稿: 包含用於
generator(...)函數的系統、使用者、工具與助理回合。 - UI 逐字稿: 包含串流的助理文字、工具執行元資料與效能指標。
執行流程遵循以下迴路:使用者輸入被加入 $ ightarrow$ 權杖被串流 $ ightarrow$ 工具呼叫在背景中被解析並執行 $ ightarrow$ 結果被饋送回提示詞 $ ightarrow$ 迴路重複,直至不再有工具呼叫。
資料邊界與持久性
狀態會根據生命週期與存取模式進行分配,以最佳化效能與耐久性:
- 對話狀態: 儲存在背景記憶體 (
Agent.chatMessages) 中,以實現快速編排。 - 工具偏好: 在
chrome.storage.local中跨會話持久化。 - 語義歷史向量: 儲存在 IndexedDB (
VectorHistoryDB) 中,以進行本地檢索。 - 擷取的頁面內容: 由背景快取 (
WebsiteContentManager) 管理,以當前 URL 為鍵。
建置與封裝
為滿足 Manifest V3 需求,該專案透過 Vite 使用多入口建置,確保每個 Chrome 入口點對應一個構件。內容腳本被保留為自包含輸出,以防止執行時區塊載入問題,且輸出名稱完全對應 manifest.json 中的定義。