見出し画像

【検証】NGワードチェックもLLMの時代?


はじめに

今回はゲームではないのですが、検証です。
検証内容はNGワードチェックをLLMでできるかというものです。
NGワードチェックとはゲームなどでユーザー名をつける際などに下ネタ的なワードを含めると、「その名前はつけられません。」などとエラーメッセージが表示されるものです。
私も以前、ソシャゲの開発チームにいたので、NGワードチェックは開発したことがありますが、これは単純に考えられる範囲のNGワードのマスターデータが準備されていて、単純にそのデータとの突き合わせで判断しています。
よって、当たり前ですがそのデータにはない単語はそのチェックをくぐり抜けてしまうのです。
そこでLLMに判断させれば、そういった考慮もれによる抜け道を防げるのではないかというものです。


Function CallingによるNGワードチェックの処理

テスト的にGoogleAppScriptで書いてみました。
ユーザーからの入力に下記をチェックします。
1. 差別的な表現が含まれているか
2. 暴力的な表現が含まれているか
3. 性的な表現が含まれているか

function ngwordChecker(userPrompt){

  // ■ プロンプトの指定
  var systemPrompt = "Userからのメッセージに応じた関数を教えてください。";
  var messagesRequest = [
    {"role": "system", "content": systemPrompt},
    {"role": "user", "content": userPrompt},
  ];

  // ■ リクエストパラメータの指定
  var requestOptions = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer "+ props2.getProperty('OPENAI_APIKEY')
    },
    "payload": JSON.stringify({
      "model": 'gpt-4o-2024-05-13',
      'max_tokens' : 2048,
      'temperature' : 0.1, // ★ 出力の再現性を高めるために低い値を採用
      "messages": messagesRequest,
      "functions": [
        // ① 「差別的な表記」 の呼び出し
        {
          "name": "DetectDiscriminatoryExpression", // 関数名
          "description": "人種や性別、その他の過激な差別的表現を検知する", //関数の説明
          "parameters": {
            "type": "object",
            "properties": {
              "discriminatoryWord": {
                "type": "string",
                "description": "人種や性別、その他の差別的な表現として検知した単語",
              }
            },
            "required": ["discriminatoryWord"], // 引数の中で必須なものを指定
          },
        },
        // ② 「暴力的な表記」 の呼び出し
        {
          "name": "DetectViolentExpression", // 関数名
          "description": "グロテスクや暴力、その他の過激な暴力的表現を検知する", //関数の説明
          "parameters": {
            "type": "object",
            "properties": {
              "violentWord": {
                "type": "string",
                "description": "グロテスクや暴力、その他の暴力的な表現として検知した単語",
              }
            },
            "required": ["violentWord"],
          }
        },
        // ③ 「性的な表記」 の呼び出し
        {
          "name": "DetectSexualExpression", // 関数名
          "description": "アダルトや下ネタ、その他の過激な性的表現を検知する", //関数の説明
          "parameters": {
            "type": "object",
            "properties": {
              "sexualWord": {
                "type": "string",
                "description": "アダルトや下ネタ、その他の性的な表現として検知した単語",
              }
            },
            "required": ["sexualWord"],
          }
        }
      ]
    })
  }

  // ■ APIのレスポンスを取得
  const response = UrlFetchApp.fetch("https://api.openai.com/v1/chat/completions", requestOptions)
  const responseText = response.getContentText();
  const json = JSON.parse(responseText);

  // ■ 戻り値の初期化
  var result = {
    "status" : "",
    "detail" : ""
  };

  // ■ レスポンスから該当の関数を呼び出す
  // ★ この分岐に入ったら弾く対象
  if(json.choices[0].message.function_call) {

    // 呼び出す関数名とパラメータを取得
    const function_name = json.choices[0].message.function_call.name;
    const function_arguments = JSON.parse(json.choices[0].message.function_call.arguments);

    // ① 差別的な表現を検知した場合
    if(function_name === 'DetectDiscriminatoryExpression'){
      result["status"] = `NG`;
      result["detail"] = `① 差別的な表現\n禁止単語 : ${function_arguments.discriminatoryWord}`;
    }
    // ② 暴力的な表現を検知した場合
    else if(function_name === 'DetectViolentExpression'){
      result["status"] = `NG`;
      result["detail"] = `② 暴力的な表現\n禁止単語 : ${function_arguments.violentWord}`;
    }
    // ③ 性的な表現を検知した場合
    else if(function_name === 'DetectSexualExpression'){
      result["status"] = `NG`;
      result["detail"] = `③ 性的な表現\n禁止単語 : ${function_arguments.sexualWord}`;
    }
  }
  // ④ 該当なし
  else {

    // ★ 今まで通りの処理を実行

    result["status"] = `OK`;
    result["detail"] = `④ 該当なし`;
  }

  return result;
}

ChatGPTAPIのFunctionCallingを使用して分類しています。
同じ入力に対して結果が変わりにくいように、temperatureリクエストを低く設定しています。モデルはgpt-4oを使用しています。

Function CallingによるNGワードチェックの結果

YoutubeでポケモンのゲームでNGワードになるかという実況をされている動画がありましたので、そこでNGワードとして弾けていなかったようなものを実際に試してみました。

⏬YoutubeでポケモンのゲームでNGワードになるかという実況動画

⏬LLMのチェックの結果。しっかり弾けています。すばら!

ベクトルの内積計算によるチェックという提案

もう一つはLLMを使用するものではないですが、マスターデータのワードとユーザー入力のワードをベクトル化させて、その類似度で判断する方法というものもあります。
少し汚いですが「うんこ」というワードはマスターデータにあるが「う◯こ」はない場合、直接的な文字列の比較だとTRUEにはなりません。
しかし例えば「二つのワードの類似度が0.95以上」とかだとTRUEになると思います。という提案。

最後に

ここまで読んでいただきありがとうございます☀️
普段はAI機能、特に画像認識や音声認識の機能をUIにしたゲーム開発の過程や成果物、技術的な発見も発信していきます!
Xで情報発信も始めました。
「AI×ゲーム開発」にご興味ある方はフォローしていただけると嬉しいです!

この記事が気に入ったらサポートをしてみませんか?