生成AIの「嘘」を許すな:LLMハルシネーション検知と事実確認パイプラインの実装
現場のエンジニア諸君、お疲れ様。最近は生成AIを組み込んだアプリケーションを構築するのが当たり前になったが、お前たちはLLMが平然と嘘をつく「ハルシネーション」のリスクを、どれだけ真剣に考えている?
「AIが答えを生成したから大丈夫」などという性善説は、我々の世界では即座に致命的な脆弱性に直結する。特に、RAG(Retrieval-Augmented Generation)を用いた社内データ検索システムにおいて、AIが誤った情報を根拠として提示した場合、それは単なる誤解では済まない。悪意ある攻撃者が意図的に検索クエリを操作し、AIに偽の情報を生成させて重要システムの設定を変更させたり、機密情報を開示させたりする「プロンプトインジェクション」と「ハルシネーション」の複合攻撃は、現在の最大の脅威の一つだ。
今日は、そんな泥沼を避けるための「事実確認(Fact-Checking)パイプライン」の設計思想と、即戦力となる実装コードを伝授する。
1. なぜ「信頼度スコア」が必要なのか
LLMは確率論で言葉を紡ぐ機械だ。我々が実装すべきは、「回答の正当性を外部ソースとの照合で定量化する層」である。
攻撃者が狙うのは、RAGの検索フェーズで「関連性の低い、あるいは改ざんされたドキュメント」をLLMに注入し、AIに「もっともらしい嘘」を吐かせる手法だ。これを防ぐには、生成された回答の各文が、検索したソースドキュメントのどの部分に基づいているかを追跡(アサーション)する必要がある。
2. 事実確認パイプラインのアーキテクチャ
実装の要諦は以下の3ステップだ。
1. Context Extraction: 回答を生成した際に参照したドキュメント断片を特定する。
2. NLI(自然言語推論)による検証: 回答の各文が、ソースドキュメントの内容と矛盾しないかを別の軽量モデルで判定する。
3. 信頼度スコア算出: 矛盾率が高い場合は回答を拒否(またはユーザーに警告)する。
3. 実装サンプル:PythonによるNLI検証ロジック
ここでは、HuggingFaceの軽量なモデルを用いて、回答がソースドキュメントに基づいているかを検証するPythonコード例を示す。
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
# 事実確認用のNLIモデルをロード(例: cross-encoder/nli-deberta-v3-baseなど)
model_name = "cross-encoder/nli-deberta-v3-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
def verify_fact(source_text, generated_answer):
"""
ソースドキュメントと回答を比較し、論理的な包含関係を確認する
"""
inputs = tokenizer(source_text, generated_answer, return_tensors='pt', truncation=True)
with torch.no_grad():
logits = model(**inputs).logits
# 0: 矛盾(Contradiction), 1: 中立(Neutral), 2: 含意(Entailment)
probs = torch.softmax(logits, dim=-1)
entailment_score = probs[0][2].item()
return entailment_score
# 実行例
source = "当社のセキュリティポリシーでは、本番環境への直接アクセスは原則禁止されている。"
answer = "本番環境には誰でも自由にアクセス可能です。"
score = verify_fact(source, answer)
print(f"信頼度スコア: {score:.2f}")
if score < 0.5:
print("警告:ハルシネーションの可能性あり。回答を遮断します。")
4. 攻撃者への対策と運用の極意
コードを書くだけで満足してはいけない。実務上の防御ポイントは以下の通りだ。
- 入出力のサニタイズ:
$や<script>等の特殊文字が含まれる入力をLLMに渡す前に、正規表現で厳格にフィルタリングすること。RAGの検索結果に攻撃者が仕込んだクロスサイトスクリプティング(XSS)コードが含まれている場合、そのままフロントエンドにレンダリングすると、クライアントサイドで攻撃が発火する。 - 権限分離(IAM): LLMを実行するIAMロールには「読み取り専用」の権限を付与し、たとえプロンプトインジェクションで命令が乗っ取られても、データベースの書き換えができないようにしておくこと。
- ハルシネーション検知の非同期化: ユーザー体験を損なわないよう、検証プロセスはメインの生成処理とは非同期で実行し、スコアが一定以下の場合は「回答の修正」または「UI上での警告表示」を行うのが正解だ。
最後に
セキュリティとは、技術的な実装だけでなく「疑う力」そのものだ。「AIがそう言っているから」という思考停止こそが、最大のセキュリティホールになる。
今回紹介したパイプラインは、あくまで最低限の防御壁だ。しかし、この「検証プロセス」を導入するだけでも、悪意ある攻撃者や、システムの誤用を防ぐ抑止力は格段に向上する。
現場で何か行き詰まったら、また相談に来い。コードのバグよりも、人間の油断の方がよほど始末が悪い。しっかりと設計を突き詰めてくれ。期待している。
コメント