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パイプラインに「検証」という名の監査役を常駐させてくれ。期待している。
コメント