第 2 部分:建構用戶端 AI 有害內容偵測機制

Maud Nalpas
Maud Nalpas

發布日期:2024 年 11 月 13 日

仇恨言論、騷擾和網路霸凌已成為網路上普遍存在的問題。有害的評論會扼殺重要聲音導致使用者和客戶離開。有害內容偵測功能可保護使用者,並打造更安全的線上環境。

在這個兩部分系列中,我們將探討如何使用 AI 偵測並減輕有害內容的來源:使用者的鍵盤。

第一部分中,我們討論了這種做法的用途和優點。

在第二部分,我們將深入探討實作方式,包括程式碼範例和使用者體驗提示。

示範和程式碼

試用示範,並研究 GitHub 上的程式碼

留言發布示範。
當使用者停止輸入時,我們會分析其留言是否有害。如果系統將留言歸類為有害內容,我們會即時顯示警告。

瀏覽器支援

我們的示範內容可在最新版本的 Safari、Chrome、Edge 和 Firefox 中執行。

選取模型和程式庫

我們使用 Hugging Face 的 Transformers.js 程式庫,該程式庫提供在瀏覽器中使用機器學習模型的工具。我們的示範程式碼源自這個文字分類範例

我們選擇toxic-bert 模型,這是一種預先訓練的模型,可用於識別有害的語言模式。這是 unitary/toxic-bert 的網頁相容版本。如要進一步瞭解模型的標籤和身分攻擊分類方式,請參閱 Hugging Face 模型頁面

toxic-bert 的下載大小為 111 MB。

模型下載完成後,推論速度就會加快。

舉例來說,在我們測試的 Android 中階裝置 (一般 Pixel 7 手機,而非效能更高的 Pro 機型) 上,Chrome 通常會在 500 毫秒內完成啟動。執行代表使用者族群的基準測試。

實作

以下是實作過程中的重點步驟:

設定有害內容門檻

我們的有害內容分類器會提供 01 之間的有害內容分數。在該範圍內,我們需要設定閾值,以判斷何謂有害的評論。常用的門檻值為 0.9。這樣一來,您就能攔截明顯惡意留言,同時避免過度敏感,導致出現太多誤判 (也就是將無害留言歸類為惡意留言)。

export const TOXICITY_THRESHOLD = 0.9

匯入元件

我們會從 @xenova/transformers 程式庫匯入必要元件。我們也會匯入常數和設定值,包括毒性門檻。

import { env, pipeline } from '@xenova/transformers';
// Model name: 'Xenova/toxic-bert'
// Our threshold is set to 0.9
import { TOXICITY_THRESHOLD, MODEL_NAME } from './config.js';

載入模型並與主執行緒進行通訊

我們會載入 toxic-bert 惡意內容偵測模型,並用於準備分類器。最簡單的版本是 const classifier = await pipeline('text-classification', MODEL_NAME);

建立管道 (如程式碼範例所示) 是執行推論工作的第一步。

管道函式會採用兩個引數:任務 ('text-classification') 和模型 (Xenova/toxic-bert)。

關鍵字:在 Transformers.js 中,管道是一種高階 API,可簡化執行機器學習模型的程序。處理模型載入、符記化和後處理等工作。

我們的示範程式碼除了準備模型之外,還會將耗用大量運算資源的模型準備步驟卸載至網路工作站。這可讓主執行緒保持回應。進一步瞭解如何將耗用資源的任務卸載至網路工作者

我們的 worker 需要與主執行緒通訊,使用訊息表示模型狀態和毒性評估結果。請查看我們建立的訊息代碼,這些代碼會對應至模型準備和推論生命週期的不同狀態。

let classifier = null;
(async function () {
  // Signal to the main thread that model preparation has started
  self.postMessage({ code: MESSAGE_CODE.PREPARING_MODEL, payload: null });
  try {
    // Prepare the model
    classifier = await pipeline('text-classification', MODEL_NAME);
    // Signal to the main thread that the model is ready
    self.postMessage({ code: MESSAGE_CODE.MODEL_READY, payload: null });
  } catch (error) {
    console.error('[Worker] Error preparing model:', error);
    self.postMessage({ code: MESSAGE_CODE.MODEL_ERROR, payload: null });
  }
})();

將使用者輸入內容分類

classify 函式中,我們使用先前建立的分類器來分析使用者留言。我們會傳回毒性分類器的原始輸出內容:標籤和分數。

// Asynchronous function to classify user input
// output: [{ label: 'toxic', score: 0.9243140482902527 },
// ... { label: 'insult', score: 0.96187334060668945 }
// { label: 'obscene', score: 0.03452680632472038 }, ...etc]
async function classify(text) {
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  let results = await classifier(text, { topk: null });
  return results;
}

當主執行緒要求 worker 執行時,我們會呼叫分類函式。在示範中,我們會在使用者停止輸入時觸發分類器 (請參閱 TYPING_DELAY)。發生這種情況時,主執行緒會傳送訊息給 worker,其中包含要分類的使用者輸入內容。

self.onmessage = async function (message) {
  // User input
  const textToClassify = message.data;
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  self.postMessage({ code: MESSAGE_CODE.GENERATING_RESPONSE, payload: null });

  // Inference: run the classifier
  let classificationResults = null;
  try {
    classificationResults = await classify(textToClassify);
  } catch (error) {
    console.error('[Worker] Error: ', error);
    self.postMessage({
      code: MESSAGE_CODE.INFERENCE_ERROR,
    });
    return;
  }
  const toxicityTypes = getToxicityTypes(classificationResults);
  const toxicityAssessement = {
    isToxic: toxicityTypes.length > 0,
    toxicityTypeList: toxicityTypes.length > 0 ? toxicityTypes.join(', ') : '',
  };
  console.info('[Worker] Toxicity assessed: ', toxicityAssessement);
  self.postMessage({
    code: MESSAGE_CODE.RESPONSE_READY,
    payload: toxicityAssessement,
  });
};

處理輸出內容

我們會檢查分類器的輸出分數是否超過閾值。如果是的話,我們會記下相關標籤。

如果列出任何惡意標籤,系統就會將留言標示為可能含有惡意內容。

// input: [{ label: 'toxic', score: 0.9243140482902527 }, ...
// { label: 'insult', score: 0.96187334060668945 },
// { label: 'obscene', score: 0.03452680632472038 }, ...etc]
// output: ['toxic', 'insult']
function getToxicityTypes(results) {
  const toxicityAssessment = [];
  for (let element of results) {
    // If a label's score > our threshold, save the label
    if (element.score > TOXICITY_THRESHOLD) {
      toxicityAssessment.push(element.label);
    }
  }
  return toxicityAssessment;
}

self.onmessage = async function (message) {
  // User input
  const textToClassify = message.data;
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  self.postMessage({ code: MESSAGE_CODE.GENERATING_RESPONSE, payload: null });

  // Inference: run the classifier
  let classificationResults = null;
  try {
    classificationResults = await classify(textToClassify);
  } catch (error) {
    self.postMessage({
      code: MESSAGE_CODE.INFERENCE_ERROR,
    });
    return;
  }
  const toxicityTypes = getToxicityTypes(classificationResults);
  const toxicityAssessement = {
    // If any toxicity label is listed, the comment is flagged as
    // potentially toxic (isToxic true)
    isToxic: toxicityTypes.length > 0,
    toxicityTypeList: toxicityTypes.length > 0 ? toxicityTypes.join(', ') : '',
  };
  self.postMessage({
    code: MESSAGE_CODE.RESPONSE_READY,
    payload: toxicityAssessement,
  });
};

顯示提示

如果 isToxic 為 true,我們會向使用者顯示提示。在示範中,我們並未使用更精細的毒性類型,但我們已將其提供給主執行緒 (toxicityTypeList) 使用。您可能會發現,這對您的用途很有幫助。

使用者體驗

在示範中,我們做出了以下選擇:

  • 一律允許發布。我們的用戶端有害內容提示不會阻止使用者發布內容。在我們的示範中,即使模型未載入 (因此無法提供毒性評估),使用者仍可張貼留言,即使留言遭偵測為有害內容也一樣。如建議,你應該要設立第二個系統來偵測惡意留言。如果您的應用程式適用於此,請考慮通知使用者,他們的留言在用戶端通過審查,但在伺服器或人工檢查期間遭到標記。
  • 留意偽陰性。如果留言未歸類為有害留言,我們的示範不會提供任何意見回饋 (例如「留言不錯!」)。除了雜訊問題外,提供正面回饋可能會傳遞錯誤信號,因為我們的分類器偶爾會遺漏一些有害的留言。
留言發布示範。
「張貼」按鈕一律處於啟用狀態:在我們的示範中,即使系統將留言歸類為有害留言,使用者仍可決定是否張貼留言。即使留言未歸類為有害留言,我們也不會顯示正面意見回饋。

強化功能和替代方案

功能上現有的不足與未來補強

  • 語言:我們使用的模型主要支援英文。如要支援多種語言,您需要進行微調。Hugging Face 上列出的多個有害內容模型確實支援非英語語言 (俄文、荷蘭文),但目前不支援 Transformers.js。
  • Nuance:雖然 toxic-bert 能有效偵測明顯的有害內容,但在處理較為微妙或取決於情境的情況 (例如反諷) 時,可能會遇到困難。有害性可能非常主觀且難以察覺。舉例來說,您可能會將特定字詞或表情符號歸類為有害內容。微調有助於改善這些區域的準確度。

我們即將推出一篇關於微調惡意內容模型的文章。

替代方案

結論

用戶端惡意行為偵測功能是一項強大的工具,可用於改善線上社群。

透過利用 toxic-bert 等 AI 模型,並透過 Transformer.js 在瀏覽器中執行,您就能導入即時意見回饋機制,以便禁止有害行為,並減少伺服器上的有害內容分類負載。

這個用戶端方法已可跨瀏覽器運作。不過,請注意相關限制,尤其是模型放送成本和下載大小。為用戶端 AI 採用效能最佳做法,並快取模型

如要全面偵測有害內容,請同時採用用戶端和伺服器端方法。