AIコンテンツモデレーションシステム実践:Python + LLM + OpenCV エンタープライズ級ソリューション

技术架构本番環境の AI Agent

なぜコンテンツモデレーションがAIのキラーアプリなのか?

ByteDance は毎日数十億のコンテンツを処理しています。Douyin 動画から Toutiao 記事まで、すべてミリ秒単位で審査が必要です。これは AI の最もハードコアな実用シーン——「会話」ではなく「判断」です。

コンテンツモデレーションは単なる付加価値ではなく、コンプライアンスのレッドライン——見逃したコンテンツ1件がアプリの配信停止につながる可能性があります。

モデレーションの3つの次元

┌──────────────────────────────────────────────────┐
│              コンテンツモデレーション3層アーキテクチャ        │
├──────────────────────────────────────────────────┤
│  Layer 1: テキストモデレーション                       │
│  ├── センシティブワード検出(正規表現 + ACオートマトン)    │
│  ├── 意味理解(大規模言語モデル分類)                    │
│  └── 感情分析(ポジティブ/ネガティブ/ニュートラル)       │
├──────────────────────────────────────────────────┤
│  Layer 2: 画像モデレーション                          │
│  ├── OCRテキスト抽出 → テキストモデレーション             │
│  ├── 物体検出(暴力/アダルト/政治)                     │
│  └── 顔検出(公人/未成年)                            │
├──────────────────────────────────────────────────┤
│  Layer 3: 動画モデレーション                          │
│  ├── キーフレーム抽出 → 画像モデレーション               │
│  ├── 音声→テキスト変換 → テキストモデレーション           │
│  └── 行動認識(暴力的動作/危険行為)                    │
└──────────────────────────────────────────────────┘

テキストモデレーション:正規表現から大規模言語モデルへ

1.1 センシティブワード検出(ACオートマトン)

from pyahocorasick import Automaton

class SensitiveWordDetector:
    def __init__(self):
        self.automaton = Automaton()
        self._load_words()

    def _load_words(self):
        with open("sensitive_words.txt", "r") as f:
            for idx, word in enumerate(f):
                self.automaton.add_word(word.strip(), (idx, word.strip()))
        self.automaton.make_automaton()

    def detect(self, text: str) -> list:
        results = []
        for end_idx, (word_idx, word) in self.automaton.iter(text):
            start_idx = end_idx - len(word) + 1
            results.append({
                "word": word,
                "start": start_idx,
                "end": end_idx + 1,
                "category": self._get_category(word)
            })
        return results

detector = SensitiveWordDetector()
hits = detector.detect("この商品は最高です、強くおすすめします!")
# マッチしたセンシティブワードのリストを返す

1.2 大規模言語モデルによる意味的モデレーション

from openai import OpenAI

class SemanticModerator:
    def __init__(self):
        self.client = OpenAI()
        self.system_prompt = """あなたはコンテンツモデレーションの専門家です。
以下のコンテンツがポリシー違反かどうかを判断してください。
JSON形式で出力:
{
  "is_violation": true/false,
  "category": "政治的にセンシティブ|アダルト|暴力・テロ|虚偽情報|ヘイトスピーチ|正常",
  "confidence": 0.0-1.0,
  "reason": "判断理由"
}"""

    def moderate(self, text: str) -> dict:
        response = self.client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": self.system_prompt},
                {"role": "user", "content": text}
            ],
            response_format={"type": "json_object"},
            temperature=0
        )
        return json.loads(response.choices[0].message.content)

moderator = SemanticModerator()
result = moderator.moderate("今日は天気が良くて、散歩にぴったりですね")
# {"is_violation": false, "category": "正常", "confidence": 0.95, "reason": "日常会話、違反なし"}

1.3 ACオートマトン vs 大規模言語モデル 選定戦略

方式 速度 精度 リコール 適したシナリオ
ACオートマトン <1ms ~85% ~95% 第一段階スクリーニング、明確な禁止ワード
大規模言語モデル ~500ms ~95% ~90% 第二段階、意味的な違反の判断
組み合わせ(推奨) <1ms + 500ms ~98% ~99% 本番環境で最も推奨されるパターン

画像モデレーション:OpenCV + マルチモーダル大規模言語モデル

2.1 OCR + テキストモデレーション

import cv2
import easyocr

class ImageModerator:
    def __init__(self):
        self.ocr_reader = easyocr.Reader(['ch_sim', 'en'])
        self.text_moderator = SemanticModerator()

    def moderate(self, image_path: str) -> dict:
        # Step 1: OCRでテキスト抽出
        ocr_results = self.ocr_reader.readtext(image_path)
        text = " ".join([result[1] for result in ocr_results])

        # Step 2: テキストモデレーション
        if text.strip():
            text_result = self.text_moderator.moderate(text)
        else:
            text_result = {"is_violation": False, "category": "正常"}

        # Step 3: 画像内容検出
        image_result = self._detect_objects(image_path)

        return {
            "ocr_text": text,
            "text_moderation": text_result,
            "image_moderation": image_result,
            "is_violation": text_result["is_violation"] or image_result["is_violation"]
        }

    def _detect_objects(self, image_path: str) -> dict:
        # マルチモーダル大規模言語モデルで画像内容を検出
        with open(image_path, "rb") as f:
            response = self.client.chat.completions.create(
                model="gpt-4o",
                messages=[{
                    "role": "user",
                    "content": [
                        {"type": "text", "text": "この画像に違反コンテンツ(暴力/アダルト/政治的にセンシティブ)が含まれているか判断してください"},
                        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
                    ]
                }],
                temperature=0
            )
        return json.loads(response.choices[0].message.content)

2.2 画像モデレーションのパフォーマンス最適化

画像モデレーションのボトルネックは主に以下の2点です:

  1. OCR 処理:高解像度画像の OCR 抽出は時間がかかります。画像を最初にリサイズ(長辺最大 1920px)してから OCR を実行することで、精度をほぼ維持したまま処理時間を 60% 削減できます。

  2. マルチモーダルモデル呼び出し:API コストが高いため、OCR テキストが完全にクリーンな画像は LLM 呼び出しをスキップ可能です。


動画モデレーション:キーフレーム + 音声

3.1 キーフレーム抽出

import cv2
import subprocess

class VideoModerator:
    def __init__(self):
        self.image_moderator = ImageModerator()

    def extract_keyframes(self, video_path: str, interval: int = 30) -> list:
        cap = cv2.VideoCapture(video_path)
        fps = int(cap.get(cv2.CAP_PROP_FPS))
        frame_interval = fps * interval  # N秒ごとに1フレーム抽出

        keyframes = []
        frame_count = 0

        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break

            if frame_count % frame_interval == 0:
                frame_path = f"/tmp/keyframe_{frame_count}.jpg"
                cv2.imwrite(frame_path, frame)
                keyframes.append(frame_path)

            frame_count += 1

        cap.release()
        return keyframes

    def moderate(self, video_path: str) -> dict:
        # キーフレーム抽出
        keyframes = self.extract_keyframes(video_path, interval=10)

        # フレームごとにモデレーション
        violations = []
        for frame_path in keyframes:
            result = self.image_moderator.moderate(frame_path)
            if result["is_violation"]:
                violations.append(result)

        # 音声→テキスト変換してモデレーション
        audio_text = self._extract_audio_text(video_path)
        audio_result = self.text_moderator.moderate(audio_text) if audio_text else {"is_violation": False}

        return {
            "keyframe_count": len(keyframes),
            "violations": violations,
            "audio_moderation": audio_result,
            "is_violation": len(violations) > 0 or audio_result.get("is_violation", False)
        }

    def _extract_audio_text(self, video_path: str) -> str:
        # FFmpegで音声抽出 → Whisperで文字起こし
        audio_path = "/tmp/audio.wav"
        subprocess.run([
            "ffmpeg", "-i", video_path,
            "-vn", "-acodec", "pcm_s16le",
            "-ar", "16000", audio_path
        ], capture_output=True)

        result = whisper_model.transcribe(audio_path)
        return result["text"]

3.2 キーフレーム抽出戦略

戦略 説明 抽出フレーム数(5分動画) 適したシナリオ
固定間隔 30秒ごとに1フレーム 10フレーム 一般動画
シーンチェンジ検出 画面が大きく変わった時のみ 15-50フレーム トークショー/Vlog
適応型密度 動きの激しい区間は密度を上げる 動的に調整 アクション系コンテンツ

本番環境アーキテクチャ

マルチレベルモデレーションパイプライン

from concurrent.futures import ThreadPoolExecutor

class ModerationPipeline:
    def __init__(self):
        self.sensitive_detector = SensitiveWordDetector()
        self.semantic_moderator = SemanticModerator()
        self.image_moderator = ImageModerator()
        self.executor = ThreadPoolExecutor(max_workers=10)

    def moderate(self, content: dict) -> dict:
        content_type = content["type"]
        results = {}

        # Level 1: 高速ルールフィルタリング(<10ms)
        if content_type in ["text", "image", "video"]:
            text = content.get("text", "")
            sensitive_hits = self.sensitive_detector.detect(text)
            if sensitive_hits:
                return {
                    "is_violation": True,
                    "level": "high",
                    "category": "sensitive_word",
                    "details": sensitive_hits
                }

        # Level 2: AI意味モデレーション(<500ms)
        if content_type == "text":
            results["semantic"] = self.semantic_moderator.moderate(content["text"])
        elif content_type == "image":
            results["image"] = self.image_moderator.moderate(content["url"])
        elif content_type == "video":
            results["video"] = self.video_moderator.moderate(content["url"])

        # Level 3: 人間レビュー(低信頼度時に発動)
        for key, result in results.items():
            if result.get("confidence", 1.0) < 0.85:
                results[key]["need_human_review"] = True

        is_violation = any(r.get("is_violation", False) for r in results.values())
        return {"is_violation": is_violation, "results": results}

パフォーマンス最適化

最適化手法 効果 実装難易度
ACオートマトンで逐次単語マッチングを置き換え 10倍の速度向上 ★☆☆☆☆
センシティブワード結果キャッシュ 重複コンテンツの即時応答 ★★☆☆☆
大規模言語モデルバッチ推論 3倍のスループット向上 ★★★☆☆
キーフレームのスマートサンプリング フレーム数50%削減 ★★★☆☆
GPUアクセラレーションOpenCV 画像処理5倍高速化 ★★☆☆☆

まとめ

エンタープライズ級コンテンツモデレーションシステムのコア設計:

  1. マルチレベルフィルタリング:ルールエンジン(高速)→ AIモデレーション(高精度)→ 人間レビュー(安全網)
  2. マルチモーダルカバレッジ:テキスト + 画像 + 動画 + 音声、すべてのコンテンツタイプに対応
  3. Python エコシステムの優位性:OpenCV、easyocr、whisper などのライブラリが即座に利用可能
  4. 大規模言語モデルの活用:「キーワードマッチング」から「意味理解」への進化

コンテンツモデレーションは AI の最もハードコアな実用シーン——「会話できる」ではなく「判断できる」ことが本質です。

ブラウザローカルツールを無料で試す →

#AI审核#Python#大模型#OpenCV#内容安全