最初に結論を述べます。RAG(検索拡張生成)がデモでは動くのに本番で「誤答する・遅い・情報が漏れる」のは、LLMが賢くないからではありません。「検索(Retrieval)の質」が低いからです。 RAGの精度は、AIモデルの賢さではなく、AIに渡す「根拠(コンテキスト)」の質でほぼ決まります。間違った根拠を渡せば、どんなに賢いモデルでも間違えます。素朴に「ベクトルDBに文書を入れて、類似検索した結果を渡す」だけのRAGは、本番では高い確率で精度不足に陥ります。
本記事は、私がRAGで「専門商材の誤答を構造的に排除」した音声接客AIを本番運用した経験をもとに、(1) 素朴なRAGが失敗する典型的な落とし穴、(2) それを実用品質に上げる設計(ハイブリッド検索の実装付き)、(3) 発注者が要求すべきこと、を整理します。RAGそのものを採用すべきかの判断はRAG vs ファインチューニングの記事を、より深い実装はpgvectorによる本番RAGを参照してください。
1. なぜ「素朴なRAG」は本番で失敗するのか
RAGのプロトタイプは、驚くほど簡単に作れます。文書をベクトルDBに入れ、質問をベクトル化して類似検索し、ヒットした文書をLLMに渡す——これで「それらしく」動きます。問題は、この素朴な構成が本番の多様な質問に晒されたとき、精度が大きく崩れることです。
失敗は、決まった場所で起きます。
| 落とし穴 | 何が起きるか |
|---|---|
| 検索精度の不足 | ベクトル類似だけでは、固有名詞・型番・略語が拾えず、根拠が外れる |
| チャンク化の失敗 | 文書の分割が粗い/細かいと、根拠が断片化・希釈される |
| リランクの不在 | 検索上位が必ずしも「最も答えに役立つ」順ではない |
| 評価の不在 | 精度を測れないので、改善のしようがない |
| アクセス制御の欠落 | マルチテナントで他社の文書が結果に混ざる(情報漏洩) |
| 鮮度の管理不足 | 古い文書が根拠になり、最新情報と矛盾する |
「LLMをもっと賢いモデルに変えれば直る」と考えがちですが、根拠が間違っていれば、モデルを変えても直りません。直すべきは検索層です。
2. 落とし穴①:ベクトル検索だけでは足りない → ハイブリッド検索
最も多い失敗が、「ベクトル類似検索だけ」に頼ることです。ベクトル検索は「意味的に近い」文書を見つけるのは得意ですが、固有名詞・型番・専門用語・略語の完全一致が苦手です。「型番 XR-200 の仕様」と聞かれたとき、ベクトル検索は「似た雰囲気の別の型番」を拾ってしまうことがあります。
本番の標準解は、ハイブリッド検索——ベクトル検索(意味)とキーワード/全文検索(完全一致)を組み合わせ、両者の結果を統合する設計です。
PostgreSQL(pgvector)での実装例を示します。ベクトル検索と全文検索を別々に走らせ、Reciprocal Rank Fusion(RRF)で順位を統合します。アクセス制御(テナント分離)を検索クエリそのものに組み込むのが、セキュリティ上の要点です。
interface RetrievedChunk {
readonly id: string;
readonly content: string;
readonly score: number;
}
interface HybridSearchParams {
readonly tenantId: string; // アクセス制御:必ず検索条件に含める
readonly queryEmbedding: number[]; // 質問のベクトル
readonly queryText: string; // 質問の原文(全文検索用)
readonly limit: number;
}
const RRF_K = 60; // RRFの平滑化定数(順位の影響を緩やかにする慣行値)
/**
* ベクトル検索と全文検索を統合するハイブリッド検索。
* - tenant_id を WHERE に必ず含め、他テナントの文書を構造的に除外(情報漏洩を防ぐ)
* - パラメータ化クエリのみ(SQLインジェクション対策)
* - 2系統の順位を Reciprocal Rank Fusion で統合し、意味一致と完全一致の両取り
*/
export async function hybridSearch(
db: Database,
params: HybridSearchParams,
): Promise<readonly RetrievedChunk[]> {
const { tenantId, queryEmbedding, queryText, limit } = params;
const rows = await db.query<RetrievedChunk & { rrf: number }>(
`
WITH vector_hits AS (
SELECT id, content,
ROW_NUMBER() OVER (ORDER BY embedding <=> $2) AS rank
FROM chunks
WHERE tenant_id = $1 -- アクセス制御は検索層で強制
ORDER BY embedding <=> $2 -- コサイン距離で近い順
LIMIT 50
),
keyword_hits AS (
SELECT id, content,
ROW_NUMBER() OVER (
ORDER BY ts_rank_cd(content_tsv, plainto_tsquery('simple', $3)) DESC
) AS rank
FROM chunks
WHERE tenant_id = $1
AND content_tsv @@ plainto_tsquery('simple', $3) -- 全文検索(完全一致に強い)
LIMIT 50
)
SELECT COALESCE(v.id, k.id) AS id,
COALESCE(v.content, k.content) AS content,
-- Reciprocal Rank Fusion: 1/(k+rank) を両系統で合算
COALESCE(1.0 / ($4 + v.rank), 0) + COALESCE(1.0 / ($4 + k.rank), 0) AS rrf
FROM vector_hits v
FULL OUTER JOIN keyword_hits k ON v.id = k.id
ORDER BY rrf DESC
LIMIT $5
`,
[tenantId, toVector(queryEmbedding), queryText, RRF_K, limit],
);
return rows.map(({ id, content, rrf }) => ({ id, content, score: rrf }));
}
私の音声接客AIでも、専門商材の型番や固有名詞を正しく拾うために、意味検索と完全一致検索を統合する設計にしました。「誤答を構造的に排除」できたのは、モデルを賢くしたからではなく、渡す根拠の質を検索層で担保したからです。
3. 落とし穴②:チャンク化とリランク
チャンク化(文書の分割)
RAGでは、長い文書を「チャンク」に分割して索引します。この分割設計が精度を大きく左右します。
- 粗すぎる(1チャンクが長い)→ 関連箇所が無関係な文章で薄まり、根拠がぼやける。
- 細かすぎる(1チャンクが短い)→ 文脈が失われ、断片だけでは意味をなさない。
実務では、**意味のまとまり(見出し・段落・条項)でチャンク化し、隣接チャンクと少し重ねる(オーバーラップ)**のが定石です。文書の種類(マニュアル・規程・FAQ・チャット履歴)ごとに最適な分割は変わるため、ここはチューニングが要ります。
リランク(再順位付け)
検索の上位が、必ずしも「答えに最も役立つ順」とは限りません。そこで、検索で取った候補(例: 上位50件)を、より精密なモデルで「質問への関連度」を測り直して並べ替える(リランク)。これにより、LLMに渡す最終的な根拠の質が上がります。コストと精度のトレードオフですが、精度がシビアな業務では効果が大きい工程です。
4. 落とし穴③:アクセス制御という「静かな情報漏洩」
マルチテナント(複数の顧客・部門が同じ基盤を使う)RAGで、最も危険なのがアクセス制御の欠落です。全社・全顧客の文書を1つのベクトルDBに入れ、検索時にテナントで絞り込んでいないと、A社の質問にB社の社外秘文書がヒットして根拠として渡される——という情報漏洩が、静かに起こりえます。
これは「あとから気をつける」では防げません。前章のコード例のように、テナントIDを検索クエリそのものの条件に組み込み、構造的に他テナントの文書を除外する必要があります。さらに、ユーザーの閲覧権限に応じて見られる文書を絞る(行レベルのアクセス制御)ことも、業務システムでは必須です。
発注者への含意: RAGを発注するとき、「他の顧客・部門の文書が、検索結果に混ざらない保証はどうなっていますか?」と必ず質問してください。これに「テナントIDを検索条件に組み込み、構造的に分離しています」と答えられない相手は、情報漏洩リスクを抱えています。決済における冪等性と同じく、正しさは「運用の注意」ではなく「構造」で担保すべきです。
5. 落とし穴④:評価がなければ改善できない
最後に、最も見落とされがちで、最も重要な落とし穴——評価(精度測定)の仕組みがないことです。
「なんとなく良くなった気がする」では、RAGは改善できません。本番品質のRAGには、
- 代表的な質問と「正解の根拠・回答」のセット(評価用データセット)を用意し、
- **検索が正しい根拠を引けているか(Retrieval精度)**と、**回答が根拠に忠実か(幻覚していないか)**を、
- 変更のたびに自動で測る
仕組みが要ります。これがあって初めて、「チャンク化を変えたら精度が上がった/下がった」を数字で判断でき、改善が回ります。放送局向けの生成AI考査支援では、グラウンディング由来の引用を回答に付与し、「どの文書を根拠にしたか」を追跡可能にしました。根拠が追えることは、評価と原因究明の両方に効きます。
よくある質問(FAQ)
Q. RAGがうまく答えてくれません。LLMを賢いモデルに変えれば直りますか?
多くの場合、直りません。RAGの精度は「AIに渡す根拠の質」でほぼ決まるため、根拠が外れていれば、どんなに賢いモデルでも間違えます。直すべきは検索層です。ベクトル検索だけに頼らずキーワード検索と組み合わせるハイブリッド検索、チャンク化の見直し、リランクの導入——これらで根拠の質を上げるのが先決です。
Q. ベクトルDBに文書を入れれば、RAGは完成ですか?
それはプロトタイプの段階です。本番品質には、ハイブリッド検索(意味+完全一致)、適切なチャンク化、リランク、アクセス制御、評価の仕組みが必要です。特に固有名詞・型番・専門用語はベクトル検索だけでは拾えないため、全文検索との組み合わせが実用上ほぼ必須です。
Q. マルチテナントのRAGで、他社の情報が漏れることはありますか?
設計が甘いと起こりえます。全テナントの文書を1つのDBに入れ、検索時にテナントで絞っていないと、他社の社外秘文書が検索結果に混ざります。これを防ぐには、テナントIDを検索クエリの条件に組み込み、構造的に他テナントを除外する設計が必須です。発注時は必ずこの点を確認してください。
Q. RAGの精度はどうやって測るのですか?
代表的な質問と「正解の根拠・回答」のセット(評価用データセット)を用意し、検索が正しい根拠を引けているか(Retrieval精度)と、回答が根拠に忠実か(幻覚の有無)を、変更のたびに自動で測ります。この評価基盤がないと「良くなった気がする」で終わり、改善が回りません。発注時は「精度をどう測るか」を必ず要求してください。
Q. RAGの導入を外注したいのですが、何を確認すべきですか?
「ハイブリッド検索を使うか」「チャンク化とリランクをどう設計するか」「マルチテナントの情報分離をどう保証するか」「精度をどう測定・改善するか」を質問してください。これらに構造で答えられる相手は信頼できます。「ベクトルDBに入れて検索するだけ」の提案は、本番で精度不足に陥るリスクが高いです。
まとめ:RAGの精度は「検索の質」で決まる
RAGを実用品質で本番運用するために、押さえるべきは次の通りです。
- 失敗の原因はLLMの賢さではなく「検索(Retrieval)の質」——渡す根拠の質が精度を決める。
- ベクトル検索だけでは不十分——キーワード検索と組み合わせるハイブリッド検索+リランクが標準。
- チャンク化の設計が精度を左右する——意味のまとまりで分割し、適度に重ねる。
- マルチテナントは検索層でアクセス制御——テナントIDを検索条件に組み込み、構造的に分離する。
- 評価の仕組みがなければ改善できない——精度を測る基盤を最初から用意する。
「RAGを入れたが精度が出ない」「これから社内文書AIを作りたい」——その成否は、検索層の設計とアクセス制御、評価基盤で決まります。専門商材の誤答を構造的に排除した実績と同じ水準で、要件定義から精度設計・セキュリティ・運用までお引き受けします。