DEV Community

JH5
JH5

Posted on • Originally published at Medium

用 Pyodide 解鎖前端AI超能力

用 Pyodide 解鎖前端AI超能力

https://github.com/pyodide/pyodide

UpdatedMarch 24, 2026•3 min read

用 Pyodide 解鎖前端AI超能力

JJhihHao Wu**近期研究重點包含 AI Agent 的供應鏈攻擊、PII 偵測模型評估,以及醫療 AI 在臨床流程中的安全落地。

在這裡,我分享深度技術實測報告(如 NVIDIA NeMo, WildGuard)與職場技術成長心得,致力於在 AI 浪潮中打造具備資安韌性的解決方案。**Part of seriesAI 工具與模型評測

On this page

用 Pyodide 解鎖前端AI超能力實作:用鐵達尼號資料集訓練AI用Pyodide可以跑LLM/SLM嗎?瀏覽器裡跑Python,會不會有資安問題?

用 Pyodide 解鎖前端AI超能力

https://github.com/pyodide/pyodide

Pyodide是一個讓你能在瀏覽器中執行Python 程式碼的專案,背後的技術核心是WebAssembly,能讓瀏覽器執行接近原生速度程式碼的技術,像NumPy、Pandas、Scikit-learn這些我們平常常用的重量級套件,全部搬到了瀏覽器裡。

這樣有什麼好處?

  1. 零安裝、零設定:使用者不需要在自己的電腦上安裝Python或任何函式庫,想像一下,醫師只要打開一個網頁,就能使用最新的AI診斷工具,而不用去煩惱背後複雜的環境設定。

  2. 資料隱私與安全:所有運算都在使用者的瀏覽器中完成,數據完全不需要上傳到伺服器,對於處理高度敏感的數據來說,解決了隱私洩漏的風險。

  3. 離線運行:一旦網頁和必要的資料載入完成,即使斷網,應用程式依然可以繼續運作。

  4. 降低伺服器成本:傳統的AI應用,大量的運算都在後端伺服器上進行,特別是GPU的成本,如果可以把運算壓力部分轉移到使用者端,就可以大幅降低了後端伺服器的負擔與成本。

過去要開始一個AI的案子,光是協調伺服器規格、處理防火牆、確認網路,就大概去了半條命,而Pyodide提供新的的架構,好像可以讓我們想想看未來是不是能夠有不同的架構應用在AI產品的開發流程中。

實作:用鐵達尼號資料集訓練AI

首先,你需要一個基本的HTML檔案結構來載入Pyodide並執行我們的Python腳本。

<!DOCTYPE html>  
<html>  
<head>  
    <title>Pyodide AI in Browser</title>  
    <script src="https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.js"></script>  
</head>  
<body>  
    <h2>在瀏覽器中用Pyodide訓練鐵達尼號生存預測模型</h2>  
    <p>請打開瀏覽器的開發者工具(F12)來看Python腳本的輸出結果。</p>  
    <div id="output"></div>  

    <script type="text/python">  
        import pandas as pd  
        import numpy as np  
        from sklearn.model_selection import train_test_split  
        from sklearn.ensemble import RandomForestClassifier  
        from sklearn.metrics import accuracy_score  
        import micropip  

        # 由於瀏覽器環境的限制,我們需要從一個URL來載入資料  
        url = 'https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv'  

        print("--- 1. 載入資料 ---")  
        # 直接用pandas從URL讀取CSV檔  
        df = pd.read_csv(url)  
        print("資料載入成功,前五筆資料:")  
        print(df.head())  

        print("\n--- 2. 資料前處理 ---")  
        # 選擇我們要用的特徵欄位  
        features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare']  
        target = 'Survived'  

        df_processed = df[features + [target]].copy()  

        # 處理缺失值:用中位數填補年齡  
        df_processed['Age'] = df_processed['Age'].fillna(df_processed['Age'].median())  

        # 將性別轉換為數值 (0: male, 1: female)  
        df_processed['Sex'] = df_processed['Sex'].map({'male': 0, 'female': 1})  

        # 再次檢查是否有缺失值  
        print("缺失值處理後:")  
        print(df_processed.isnull().sum())  

        print("\n--- 3. 切分訓練集與測試集 ---")  
        X = df_processed[features]  
        y = df_processed[target]  

        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  
        print(f"訓練集大小: {X_train.shape}")  
        print(f"測試集大小: {X_test.shape}")  

        print("\n--- 4. 訓練隨機森林模型 ---")  
        # 建立模型  
        model = RandomForestClassifier(n_estimators=100, random_state=42)  

        # 訓練模型  
        model.fit(X_train, y_train)  
        print("模型訓練完成!")  

        print("\n--- 5. 評估模型 ---")  
        # 進行預測  
        y_pred = model.predict(X_test)  

        # 計算準確率  
        accuracy = accuracy_score(y_test, y_pred)  
        print(f"模型在測試集上的準確率: {accuracy:.4f}")  

        # 將結果顯示在網頁上  
        from pyodide.ffi import to_js  
        from js import document  
        output_div = document.getElementById("output")  
        output_div.innerHTML += f"<p><b>模型訓練完成!</b></p>"  
        output_div.innerHTML += f"<p>測試集準確率: <b>{accuracy:.4f}</b></p>"  

    </script>  
    <script>  
        async function main() {  
            let pyodide = await loadPyodide();  
            console.log("Pyodide is ready.");  
            // 執行 <script type="text/python"> 中的程式碼  
            await pyodide.runPythonAsync(document.querySelector('script[type="text/python"]').textContent);  
        }  
        main();  
    </script>  
</body>  
</html>
Enter fullscreen mode Exit fullscreen mode

這段程式碼做了什麼?

  1. 載入Pyodide:透過CDN載入了Pyodide。

  2. 安裝與載入套件:在<script type="text/python">標籤中,像在本地端一樣import pandas, numpy, sklearn等套件

  3. 讀取資料:因為在瀏覽器中沒有本機檔案系統的概念,我們直接用Pandas從一個公開的URL讀取鐵達尼號的CSV資料。

  4. 資料前處理:我們進行了標準的資料清理步驟,包括選擇特徵、用中位數填補年齡的缺失值,以及將性別(字串)轉換為數值,大部分的步驟都跟你在Jupyter Notebook裡做的一模模一樣樣。

  5. 模型訓練:使用Scikit-learn中的RandomForestClassifier(隨機森林分類器)。

  6. 評估與輸出:訓練完成後,我們在測試集上進行預測,並計算準確率。最後,透過pyodide.ffi這個橋樑,我們能將Python中計算出的結果(準確率),直接傳遞給JavaScript,並將結果顯示在畫面上。

用Pyodide可以跑LLM/SLM嗎?

理論上可以在Pyodide裡安裝PyTorch或TensorFlow.js來跑模型,但試了幾個小模型的組合,效能都不是太好XD

主要原因我猜應該是多了幾層導致的,這邊我們改由Hugging Face所出的Transformers.js,由Hugging Face的團隊維護,可以讓你用極其簡單的方式,在瀏覽器裡直接載入並運行Hugging Face Hub上成千上萬個預訓練好的模型。

底層同樣是WebAssembly(使用ONNX Runtime Web),所以我們前面談到的所有優點,它都具備。

我們來實作一個現在利用LLM在醫療院所常見的案例「AI病歷摘要助理」,用一個小模型幫他快速生成摘要。

<!DOCTYPE html>  
<html>  
<head>  
    <title>Browser-based LLM Demo</title>  
    <style>  
        body { font-family: sans-serif; padding: 2em; }  
        #container { max-width: 800px; margin: auto; }  
        textarea { width: 100%; height: 150px; }  
        pre { background-color: #f0f0f0; padding: 1em; white-space: pre-wrap; word-wrap: break-word; }  
    </style>  
</head>  
<body>  
    <div id="container">  
        <h2>AI病歷摘要助理</h2>  
        <p>在下面的文字框中輸入或貼上病歷紀錄,然後點擊按鈕。AI模型將在您的瀏覽器中運行,並生成摘要,您的資料完全不會被上傳。</p>  

        <p id="status">狀態:點擊按鈕開始載入模型...</p>  

        <textarea id="inputText">  
Patient presents with a two-week history of a persistent dry cough and progressive shortness of breath, especially on exertion. Patient denies fever, chills, or night sweats. Past medical history is significant for hypertension, managed with Lisinopril. Patient is a non-smoker. On examination, mild crackles were noted at the lung bases. Oxygen saturation is 94% on room air. Plan to order a chest X-ray and basic blood work.  
        </textarea>  
        <br><br>  
        <button id="summarizeBtn">生成摘要</button>  

        <h3>模型生成的摘要:</h3>  
        <pre id="outputText">...等待生成...</pre>  
    </div>  

    <script type="module" src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.1"></script>  

    <script>  
        // 設定讓 Transformers.js 不會從 Hugging Face 下載重複的模型檔案  
        // 這在開發時很有用  

        const status = document.getElementById('status');  
        const inputText = document.getElementById('inputText');  
        const outputText = document.getElementById('outputText');  
        const summarizeBtn = document.getElementById('summarizeBtn');  

        let summarizer = null; // 用來存放我們的模型  

        summarizeBtn.addEventListener('click', async () => {  
            if (!summarizer) {  
                status.textContent = '狀態:正在從Hugging Face載入摘要模型 (只需一次)...';  
                // 這是神奇之處:直接從Hugging Face Hub載入一個預訓練好的摘要模型  
                // Xenova/distilbart-cnn-6-6 是一個輕量且效果不錯的模型  
                const { pipeline } = await import('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.1');  
                summarizer = await pipeline('summarization', 'Xenova/distilbart-cnn-6-6', {  
                    progress_callback: (progress) => {  
                        status.textContent = `狀態:模型載入中... ${Math.round(progress.progress)}%`;  
                    }  
                });  
                status.textContent = '狀態:模型已就緒!';  
            }  

            outputText.textContent = '...AI思考中...';  

            // 使用載入好的模型來執行摘要任務  
            const summary = await summarizer(inputText.value, {  
                max_length: 50, // 摘要的最大長度  
                min_length: 20  // 摘要的最小長度  
            });  

            outputText.textContent = summary[0].summary_text;  
        });  
    </script>  
</body>  
</html>
Enter fullscreen mode Exit fullscreen mode

medical summary result

好玩XD 且生成速度還滿快的。

醫師可以在完全離線的狀態下,使用這個工具來輔助他的日常工作,而不用擔心任何資料外洩的風險。同樣的模式,可以用在情緒分析(分析醫病對話的語氣)、問題回答(建立一個基於標準作業流程的問答機器人)各種NLP任務上,不過這個token數量還有待加強。

隨著Web GPU技術的普及和更多輕量化模型的出現,我們在瀏覽器裡能做的事情,應該會越來越超乎想像,也會重新定義我們開發AI應用思考脈絡。

瀏覽器裡跑Python,會不會有資安問題?

先說結論,在現代瀏覽器中,執行Pyodide的風險,遠低於你把資料上傳到一個不知名的雲端伺服器來的安全,主要是因為瀏覽器大多提供了沙盒(Sandbox)機制。

所有從網頁來的程式碼,不管是JavaScript還是透過WebAssembly執行的Python(也就是Pyodide),都被關在這個隔離室裡。它們可以使用的資源、可以存取的資料,都受到極其嚴格的控管。

大多數的沙盒都有下面這些限制:

  1. 無法存取本地檔案系統:在沙箱裡的Python程式碼,絕對無法跑去讀取你電腦的個人檔案、桌面上的文件或任何瀏覽器以外的資料。在前面的範例能讀取資料,是因為我們指定了一個公開的網路URL,再透過瀏覽器允許的網路請求(fetch)功能去做的,而不是本地端的檔案存取。

  2. 受限的網路通訊:沙箱裡的程式碼的所有的對外網路請求,都必須遵守瀏覽器的「同源政策(Same-Origin Policy)」,這是一個基礎且強大的安全屏障,防止惡意網站竊取你在其他網站的登入資訊。

  3. 與主機作業系統隔離:無法直接呼叫作業系統的底層API,想加密你的硬碟勒索比特幣?想打開你的攝影機?這些敏感操作的權限,都由瀏覽器掌控,並且需要使用者授權同意。

當然也不是完全沒有資安風險,最大的風險在於「阻斷服務攻擊(Denial of Service)」。惡意Python腳本可能會設計一個無限迴圈或消耗大量記憶體的計算,讓你當前的瀏覽器分頁卡死,不過目前的瀏覽器也大多丟這種惡億偵測,相對來說還是安全的,未來可以想見這樣的應用應該會冒出滿多的。

# ai# python

Top comments (0)