【実務・中級編】 LLMのハルシネーションに対する信頼性スコアリング – ガバナンス・リスク管理 & 生成AIセキュリティ防御ガイド

LLMのハルシネーションを「信頼性スコア」で飼い慣らす:RAGパイプラインの防衛戦

現場でLLMを導入する際、最も恐ろしいのは「自信満々に嘘をつく」ハルシネーション(幻覚)だ。これが単なる誤情報ならまだいい。だが、社内の機密ドキュメントをRAGで読み込ませている場合、そのハルシネーションは「存在しない権限」や「改ざんされた承認フロー」を正当化する脆弱性へ直結する。

今日は、RAGの回答を単なる「生成物」として扱うのではなく、「検証可能なデータ」としてスコアリングする設計について話そう。

1. なぜ「ハルシネーション」がセキュリティリスクなのか?

攻撃者はLLMに対し、プロンプトインジェクションを仕掛けて「RAGの検索結果を無視しろ」と命じることがある。もしシステム側が、AIが生成した回答を無条件で信頼していれば、本来アクセス権のないデータベースの情報を引き出されたり、架空の承認URLをユーザーに踏ませたりするインシデントが起きる。

これを防ぐための鉄則は、「AIの言葉を信じるな。引用元との一致を確認せよ」だ。

2. 信頼性スコアリングの仕組み:RAGの検証パイプライン

単に「生成する」のではなく、以下の3ステップを自動化する。

1. 検索結果の抽出: ベクトル検索で取得したドキュメントを特定する。
2. 根拠の照合(NLI: 自然言語推論): 回答文が、提示したソースに基づいているかをAI自身にチェックさせる。
3. 信頼性スコアの付与: 一致度を数値化し、閾値以下の場合は「回答不能」として遮断する。

3. 実装サンプル:Pythonによる検証ロジック

以下は、回答の信頼性を担保するための検証クラスだ。openai や langchain を使っている環境で、回答生成直後に実行する「ガードレール」として機能させる。

import openai

class RAGValidator:
    """
    RAGの生成結果が、検索ソースに基づいているかを検証するクラス
    """
    def __init__(self, api_key):
        self.client = openai.OpenAI(api_key=api_key)

    def verify_response(self, query, response, source_docs):
        # 厳格な検証用プロンプトを構築
        prompt = f"""
        以下の質問に対し、提供されたソースドキュメントに基づいて回答が生成されました。
        回答がソースの内容と矛盾していないか、あるいはソースにない情報を捏造していないか判定してください。
        
        [質問]: {query}
        [回答]: {response}
        [ソース]: {source_docs}
        
        判定基準(0.0〜1.0のスコアで出力):
        - 1.0: ソースに完全に準拠している
        - 0.5: 一部根拠が曖昧だが、全体としては妥当
        - 0.0: ソースにない情報の捏造、または矛盾がある
        
        JSON形式で回答してください: {{"score": float, "reason": str}}
        """
        
        # 検証実行
        evaluation = self.client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": prompt}],
            response_format={"type": "json_object"}
        )
        return evaluation.choices[0].message.content

# 使い方:閾値0.8を下回ったら出力をブロックする運用を徹底する
validator = RAGValidator(api_key="your-api-key")
result = validator.verify_response(user_query, ai_response, retrieved_docs)

4. インフラ側で守りを固める:WAFとIAMの防衛線

コードレベルでの対策だけでなく、インフラ側の設定も忘れてはいけない。特にAPIキーの漏洩や、プロンプトインジェクションによる「大量のリクエスト」への対策は必須だ。

Nginxでのレート制限(Rate Limiting)

LLMのAPIコストを浪費させる攻撃(DoS攻撃の一種)を防ぐために、NginxでIPごとのリクエスト数を制限する。

# nginx.conf 内の設定
limit_req_zone $binary_remote_addr zone=llm_api:10m rate=5r/s;

server {
    location /api/generate {
        # 1秒間に5リクエストまで。バーストは10まで許容
        limit_req zone=llm_api burst=10 nodelay;
        proxy_pass http://backend_app;
    }
}

AWS IAMによる最小権限の原則

LLMがアクセスするベクトルデータベース(Amazon OpenSearch Serverlessなど)には、読み取り専用の権限を与えること。万が一LLMが乗っ取られても、データベースの書き込みや削除ができないようにしておく。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "aoss:APIAccessAll"
            ],
            "Resource": "arn:aws:aoss:region:account:collection/my-vector-db",
            "Condition": {
                "StringEquals": {
                    "aoss:collection": "my-vector-db"
                }
            }
        }
    ]
}

最後に:セキュリティは「性悪説」で設計せよ

生成AIは魔法の杖ではない。信頼性スコアリングを導入したとしても、それは確率的な防御に過ぎない。

エンジニアとして肝に銘じてほしいのは、「AIの出力結果をシステムの決定権限に直結させない」ことだ。重要なアクション(DB書き込み、外部メール送信、権限変更)を行う前には、必ず人間による確認(Human-in-the-loop)を入れるか、あるいはAIの出力をバリデーションするための別の堅牢なプログラムを介在させること。

この設計思想こそが、インシデントに強い堅牢なシステムを作る唯一の道だ。今日から、君たちのRAGパイプラインに「検証」という名の監査役を常駐させてくれ。期待している。

コメント

タイトルとURLをコピーしました