はじめに
Retrieval Augmented Generation(RAG)は便利そうだけど、
いざ作ろうとすると一気に敷居が上がる。
- ベクトル?
- embedding?
- 類似検索?
- guardrail?
- moderation?
概念が多く、「結局なにを守っているのか」が分かりづらい。
そしてもう一つ、RAGが難しく感じられる理由がある。
それは 論文ベースで発展してきた研究分野だから だ。
実際、RAGは今も活発に研究が続いており、
検索戦略・生成精度・安全性などをテーマに大量の論文が発表されている。
そのため、実装しようとすると
「論文を読まないと分からないのでは?」
「学術レベルが高すぎるのでは?」
と感じてしまいがちになる。
この記事では、そうした背景を踏まえつつ、
- RAGの検索の正体
- ベクトル検索がやっていること
- ガードレール設計の実務的な意味
- 実際の実装コードの設計思想
を、業務アーキテクチャの視点からまとめる。
なぜ RAG は難しいと思われがちなのか?
RAG は単なる「検索 + 生成」ではなく、
LLM と検索エンジンを組み合わせた研究領域として発展してきた技術である。
代表的なRAG関連論文としては、次のようなものがある。
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (Lewis et al., 2020)
- A Survey on Retrieval-Augmented Generation for Large Language Models
- Modular Retrieval-Augmented Generation for Knowledge-Intensive Tasks
これらの論文を見ると分かる通り、RAGは
- 情報検索
- 自然言語処理
- 分散システム
- 機械学習
といった複数分野の知識が前提になっている。
つまり、RAGはもともと
「業務システムとして簡単に組み込むための技術」ではなく、
「研究テーマとして発展してきた技術」なのだ。
この背景が、そのまま「敷居の高さ」につながっている。
ガードレールもまた研究分野である
RAGと並んで重要なのが ガードレール(安全制御) である。
これもまた近年急速に研究が進んでいる分野だ。
- Safeguarding Large Language Models: A Survey
- RigorLLM: Resilient Guardrails for Large Language Models against Undesired Content
これらの論文では、単なるNGワードフィルタではなく、
- プロンプトインジェクション対策
- 個人情報検知
- 有害表現検出
- ハルシネーション抑制
- 意図しない推論の防止
といった多層防御の設計が議論されている。
つまりガードレールもまた、
RAGと同じく「研究ベースで発展してきた分野」なのだ。
RAGの検索は「意味の世界」で起きている
RAGの検索は、普通のキーワード検索とはまったく違う。
キーワード検索は:
「"牛丼 レシピ" という文字列を含むページを探す」
RAGは:
「牛丼っぽい話をしている文章」を探す
つまり 意味で検索している。
このとき使われているのがベクトル(embedding)。
文章は embedding されると数値の集合になり、
意味が近い文章同士は近い位置に配置される。
RAGはこの「意味空間」で距離を測って検索している。
意味空間のイメージ
ここで重要なのは、
RAGは「検索エンジン」ではなく「意味空間ナビゲーション」である
という点だ。
実装コードの設計思想(guardrail.py)
今回の実装は、以下のコードをベースにしている。
このファイルは単なるユーティリティではなく、
LLMの入力と出力の品質と安全性を担保するためのガードレール層 を実装したサービス群である。
guardrail.py では、役割の異なる2種類のガードサービスを分離して実装している。
- OpenAIModerationGuardService
- SemanticGuardService
どちらも「ガードレール」ではあるが、
守っている対象も設計思想もまったく異なる。
OpenAIModerationGuardService の設計思想
― LLM入出力に対する二段階安全性ガードレール ―
OpenAIModerationGuardService は、
LLM 呼び出しの 入口と出口の両方にガードレールを敷く安全制御サービス である。
このサービスは単なる「出力のモデレーション」ではない。
設計上の責務は次の二つに分かれている。
- check_input_moderation
- check_output_moderation
つまり OpenAIModerationGuardService は、
LLMの呼び出し境界に設置される
入力と出力の両方を監視する安全検査ゲート
として設計されている。
check_input_moderation の設計思想
― LLMに送信してはいけない入力を止める入口ゲート ―
業務システムにおけるユーザー入力には、普通に次のような情報が混ざる。
- 社員の個人名(PII)
- メールアドレス
- 顧客名
- 契約番号
- 社内資料の断片
これらをそのまま外部LLMに送信した瞬間、
その時点で「情報は外に出た」ことになる。
つまり出力をどれだけ厳重にチェックしても、
入力段階で送ってしまった時点で情報漏洩は成立する
という構造になっている。
OpenAIModerationGuardService の check_input_moderation は、
この問題を防ぐために存在する。
- LLMに投げてよい入力なのか
- 外部サービスに送信してよい情報なのか
を事前に検査し、NGであれば そもそもLLMを呼ばない という制御を行う。
これは
「守るために送らない」
という、ガードレール設計における最も重要な思想である。
check_output_moderation の設計思想
― ユーザーに返してはいけない回答を止める出口ゲート ―
一方、LLM は確率モデルである以上、
どれだけ検索精度を高めても、どれだけプロンプトを工夫しても、
- 暴力的表現
- 差別表現
- 不適切な言い回し
- 誤解を招く表現
- 業務的に出してはいけない文言
を生成する可能性を常に持っている。
RAGで正しいドキュメントを検索しても、
生成フェーズで事故る可能性はゼロにならない
だからこそ、
ユーザーに返す直前に止める層
が必要になる。
OpenAIModerationGuardService の check_output_moderation は、
LLMの生成結果を検査し、
- ユーザーに返してよいか
- 業務的に公開してよいか
- 法務・コンプライアンス的に問題がないか
を判定する最終関門として機能する。
なぜ入口と出口の両方にガードが必要なのか
多くのガードレール設計は「出力だけを検査する」構成になりがちだが、
それでは本質的な安全性は担保できない。
- 入力で漏れる
- 出力で事故る
この両方のリスクが存在する以上、
入口と出口の両方にガードレールを敷く
という構造そのものが安全設計になる。
OpenAIModerationGuardService は
そのための「境界層」として設計されたサービスである。
SemanticGuardService の設計思想
― 意味ブラックリストによるLLM事故防止フィルタ ―
SemanticGuardService は、
LLMに入力を投げる前段で実行される 意味ベースのフィルタリングサービス である。
このサービスの目的は明確である。
LLMの取り違いや事故を防ぐために、
危険な入力パターンを意味的に排除する
従来のNGワードフィルタでは、
- 言い回しの違い
- 類義語
- 皮肉
- 曖昧表現
に対応できない。
そこで SemanticGuardService では、
あらかじめ用意した「禁止すべき意味パターン」を
ブラックリストとしてベクトル化し、
入力文との意味距離で判定する
という方式を採用している。
意味ブラックリストという考え方
SemanticGuardService が扱うブラックリストは、
単なる文字列リストではない。
- 「やってはいけない質問の意味」
- 「LLMに投げると危険な問い合わせパターン」
- 「誤回答を誘発しやすい入力構造」
といったものを 意味ベクトルとして事前登録 している。
入力文も embedding され、
ブラックリストとの距離を計算することで、
- 意味的に近い入力をNGと判定
- 十分に離れていればOKと判定
という形でフィルタリングされる。
これにより、
- 単純なルールでは防げない取り違い
- 想定外の言い回し
- 微妙な意味のズレ
をまとめて排除できる。
SemanticGuardService の本質的な役割
SemanticGuardService は
- セキュリティガードではない
- 業務フロー制御装置でもない
- モデレーションでもない
LLMに投げる入力の品質を最大化するための前処理エンジン である。
この層があることで、
- 無駄なLLM呼び出しが減る
- 事故る入力が入らなくなる
- 回答の品質が安定する
- レイテンシが爆速になる
という効果が得られる。
つまり SemanticGuardService は、
爆速で、質のいい、安全なLLM回答を出すための土台
を作るコンポーネントである。
設計思想の本質
guardrail.py の設計思想は一貫している。
ガードレールは「機能」ではなく「前処理と後処理の境界層」である
- 入力をどう検査するか
- 何をLLMに渡すか
- 何をユーザーに返すか
この境界を明確にし、
その境界に責務を分離したサービスを置く。
その結果、
- LLMが変わっても
- embeddingモデルが変わっても
- moderation API が変わっても
ガードレール層はそのまま使える。
これは「研究実装」ではなく、
完全に「業務システム向けLLMアーキテクチャ設計」である。
最後に
ここまで業務イメージに落とし込めれば、
RAGはもはや「数学の世界」ではなく 業務設計の世界 になる。
もちろん、ベクトルの距離計算や embedding の仕組みを理解していれば、
より高度なチューニングにも踏み込める。
ただし実務で本当に重要なのは、
- どこで検索するか
- どこで止めるか
- どこで守るか
- どこで差し替えられるようにするか
というアーキテクチャ設計である。
RAGは難解な研究テーマに見えるが、
一度業務フローに落とし込めば、あとは業務をどう組み立てるかの世界だ。
数学力はあればもちろん武器になる。
だが、それがなければ何も作れないわけではない。
RAGは、ちゃんと設計すれば業務システムとして十分に扱える技術になってきている。