RAG(Retrieval-Augmented Generation、検索拡張生成)とは、外部の知識ソースを検索し、その結果をLLMのコンテキストに組み込んで回答を生成する手法です。LLMの知識カットオフの壁を越え、社内文書や最新情報に基づいた正確な応答を実現する技術として、2024年以降の生成AI活用における事実上の標準構成となっています。本記事ではRAGの基本的な仕組みから、最小構成での構築手順、精度を引き上げる5つのコツ、よくある失敗パターンまでを体系的に解説します。

RAG(検索拡張生成)とは何か

RAGは、ユーザーの質問に対して外部の知識ソースから関連情報を検索し、その検索結果をLLMのプロンプトに埋め込んだうえで回答を生成する仕組みです。LLM単体で回答を生成する場合、モデルが学習時点で持っている知識しか使えず、「知識カットオフ」と呼ばれる情報の古さや、存在しない事実を捏造する「ハルシネーション」が大きな課題となります。RAGはこの課題に対する実践的な解決策として位置づけられています。

RAGが必要とされる理由は主に3つあります。第一に、LLMの学習データには反映されていない最新情報や社内独自のデータを回答に活用できること。第二に、検索結果という根拠を明示することでハルシネーションを抑制できること。第三に、モデル自体を再学習することなく知識を更新できるため、運用コストと開発スピードの両面で優位性があることです。ファインチューニングに比べて実装・維持のハードルが低く、多くの企業がまずRAGからAI活用を始めています。

【RAGの処理フロー】

[ユーザークエリ] --> [クエリのベクトル化]
                         |
                         v
                  [ベクトルDB検索]
                         |
                         v
                  [関連文書の取得(Top-K)]
                         |
                         v
      [クエリ + 検索結果をプロンプトに組立]
                         |
                         v
                     [LLMが回答生成]
                         |
                         v
                  [ユーザーへの応答]

※ 検索結果を根拠としてLLMに渡すことで、ハルシネーションを抑制

RAGの仕組みを5ステップで理解する

RAGの処理は大きく5つのステップに分解できます。インデックス作成フェーズ(Step 1〜3)と検索・生成フェーズ(Step 4〜5)という2段構成で整理すると理解しやすいでしょう。

Step 1: 文書のチャンキング(分割)。社内ドキュメントやマニュアルを、検索単位となる小さなテキスト片(チャンク)に分割します。粒度の設計次第で検索精度が大きく変わるため、RAG構築における最重要工程の一つです。

Step 2: エンベディング(ベクトル化)。各チャンクをエンベディングモデルに通し、意味を表す高次元ベクトル(典型的には768〜1536次元)に変換します。Step 3: ベクトルDBへの保存。生成したベクトルをChromaやPineconeなどのベクトルDBにインデックスとして保存します。

Step 4: クエリのベクトル化と類似文書の検索。ユーザーからの質問文も同じエンベディングモデルでベクトル化し、ベクトルDBでコサイン類似度の高い上位K件のチャンクを取得します。Step 5: LLMによる回答生成。取得したチャンクをコンテキストとしてプロンプトに埋め込み、LLMに回答を生成させます。これら5つのステップが連携することで、RAGは「検索」と「生成」を統合した応答を実現します。

# LangChainによる最小RAGパイプライン
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA

# Step 1: 文書ロードとチャンキング
loader = TextLoader("company_manual.txt", encoding="utf-8")
documents = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(documents)

# Step 2-3: ベクトル化してChromaに保存
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(chunks, embeddings)

# Step 4-5: 検索 + LLM生成
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)

# クエリ実行
answer = qa_chain.invoke("就業規則の年次有給休暇のルールを教えて")
print(answer["result"])

RAGの構成要素と技術スタック

RAGを構成する要素は大きく4つに整理できます。エンベディングモデル、ベクトルDB、LLM、そしてそれらを接続するオーケストレーションフレームワークです。それぞれの役割と代表的な選択肢を理解しておくことで、自社のユースケースに応じた最適な構成を見極めやすくなります。

構成要素役割代表的なツール選定ポイントコスト目安
エンベディングモデルテキストをベクトル化し意味的類似度計算を可能にするOpenAI text-embedding-3、Cohere Embed、multilingual-e5日本語性能、次元数、APIコスト100万トークンあたり約20〜130円
ベクトルDBベクトルを保存し類似度検索を高速化Chroma、Pinecone、Qdrant、Weaviate、PGVectorスケーラビリティ、メタデータ検索、運用コストOSS無料〜月額数万円〜
LLM検索結果を文脈として回答を生成GPT-4o、Claude 3.5 Sonnet、Gemini 1.5、Llama 3応答品質、コスト、コンテキスト長100万トークンあたり数百〜数千円
オーケストレーション各要素を連結しパイプラインを構築LangChain、LlamaIndex、Haystack拡張性、エコシステム、学習コストOSS無料

なお、PoC段階ではOSSのChromaとOpenAI APIを組み合わせるのが最速の選択肢です。本番運用フェーズに入った段階で、スケーラビリティと運用性の観点から商用ベクトルDBやセルフホスト構成への移行を検討すると良いでしょう。

RAGの精度を上げる5つのコツ

RAGシステムは最小構成で動かすだけなら半日程度で組み上がりますが、「社内で使えるレベル」の精度に持ち上げるにはいくつかの工夫が必要です。ここでは代表的な5つの改善テクニックを取り上げます。

1. チャンキング戦略の最適化。固定長ではなく意味単位で分割するセマンティックチャンキングや、親子構造で粗粒度と細粒度を使い分けるペアレントチャイルド方式により、検索ヒット率が向上します。詳細はB-03(チャンキング戦略)を参照してください。

2. リランキング。ベクトル検索で取得した候補を、より精度の高いクロスエンコーダで並べ替えることで、上位に本当に関連性の高いチャンクを押し上げます。3. HyDE(Hypothetical Document Embeddings)。ユーザーの質問を一度LLMに渡して仮想的な回答を生成させ、その回答のベクトルで検索を行うことで、検索クエリと文書の表現ギャップを埋めます。

4. メタデータフィルタリング。文書に付与したメタデータ(部署、更新日、文書種別)を用いて検索範囲を絞り込むことで、誤ヒットを大幅に削減できます。5. プロンプト設計の最適化。「検索結果に基づいて回答し、該当情報がない場合は不明と答える」といった明示的な指示を加えることで、ハルシネーションを抑制できます。

テクニック効果実装難易度コスト適した場面
セマンティックチャンキング検索ヒット率の向上構造化されていない長文
リランキング上位精度の向上中(API従量)候補が多く絞り込みたい時
HyDEクエリ表現ギャップの解消中(LLM追加呼出)ユーザー質問が曖昧
メタデータフィルタリング誤ヒットの削減文書種別が多岐にわたる
プロンプト設計ハルシネーション抑制無料全ケース共通

これら5つの施策はどれか1つで劇的に変わるものではなく、組み合わせることで相乗効果を発揮します。詳細な実装ノウハウについてはB-04「RAGの精度改善10の手法」で解説していますので、あわせてご覧ください。

RAGの構築ステップ――最小限からスタートする

RAGは初手から完璧を目指さず、段階的に育てていくのが成功の定石です。当社で支援するプロジェクトでも、以下の3フェーズに分けて構築を進めることが多い傾向にあります。

Phase 1: 最小構成での検証(1〜2週間)。Chroma、OpenAIエンベディング、GPT-4oという最もシンプルな組み合わせで動くものを作り、想定ユーザーで実際に触ってもらいます。この段階ではUIは最小限で構いません。重要なのは「RAGが業務上の価値を生むか」を確かめることです。

Phase 2: 精度改善(2〜4週間)。Phase 1のログから失敗パターンを分析し、チャンキングの見直し、リランキングの追加、プロンプト調整を行います。同時に評価用のゴールデンデータセットを用意し、改善効果を定量的に測れる状態を整えます。Phase 3: 本番化(1〜3ヶ月)。スケーラブルなベクトルDBへの移行、監視・ログ収集基盤の整備、セキュリティレビュー、再インデックスのパイプライン構築を行います。このフェーズでは、単体の精度よりも「継続的に改善できる運用体制」を作ることが鍵となります。

# Phase 1の最小RAG構成(Chroma + OpenAI + GPT-4o)
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA

# 社内文書ディレクトリを一括ロード
loader = DirectoryLoader("./docs", glob="**/*.md")
docs = loader.load()

# チャンク分割(日本語を想定して小さめ)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=400, chunk_overlap=80,
    separators=["\n\n", "\n", "。", "、", " "]
)
chunks = splitter.split_documents(docs)

# Chromaにインデックス
vectordb = Chroma.from_documents(
    chunks,
    OpenAIEmbeddings(model="text-embedding-3-small"),
    persist_directory="./chroma_db"
)

# RAGチェーン構築
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o", temperature=0),
    retriever=vectordb.as_retriever(search_kwargs={"k": 5})
)
print(qa.invoke("申請フォームの提出先は?")["result"])

RAGのよくある失敗パターン

RAGは簡単に動き始める一方で、「思ったほど精度が出ない」という相談をよく受けます。失敗パターンは概ねパターン化されており、以下の3つが圧倒的多数を占めます。

失敗パターン1: チャンキングが粗すぎる。1チャンクに複数のトピックが混在していると、検索時にノイズが増え、関連性の低い情報がヒットしやすくなります。対策として、セマンティックチャンキングや階層型チャンキングを導入し、1チャンクに1トピックの原則を守りましょう。

失敗パターン2: エンベディングモデルの日本語性能が低い。英語中心のモデルを日本語文書に使うと、類似度の分離が甘くなり検索精度が伸び悩みます。対策として、multilingual-e5やOpenAI text-embedding-3のような多言語対応モデルを選定し、社内データで精度を評価してください。失敗パターン3: プロンプトで検索結果を活用できていない。LLMが検索結果を無視して独自知識で答えてしまうケースです。対策として、「検索結果のみに基づいて回答し、該当情報がなければ不明と答える」といった明示的な制約をプロンプトに書き込むことが有効です。

まとめ――RAGは「LLMに記憶を与える」技術

  • RAGは外部知識ソースを検索してLLMに渡す、知識カットオフとハルシネーション対策の実践解
  • 5ステップ(チャンキング→エンベディング→保存→検索→生成)で全体像を把握できる
  • 精度改善はチャンキング・リランキング・HyDE・メタデータ・プロンプトの組み合わせが効果的
  • 構築は最小構成で検証→精度改善→本番化の3フェーズで段階的に進めるのが王道
  • 失敗パターンは概ね類型化されており、先回りの対策が可能

DE-STKでは、RAGの要件定義から本番運用までの伴走支援を提供しています。まずは自社データでのPoC設計からご相談ください。

よくある質問(FAQ)

Q. RAGとは何ですか?

RAG(Retrieval-Augmented Generation)は、外部の知識ソースを検索し、その結果をLLMのプロンプトに組み込んで回答を生成する手法です。LLMが持たない最新情報や社内データに基づいた正確な回答を生成できる点が特徴で、ハルシネーションを抑制する実践的な手段としても広く用いられています。

Q. RAGの構築にはどのくらいの期間がかかりますか?

最小構成のプロトタイプなら1〜2週間で構築可能です。精度改善と本番運用に耐えるシステムの構築には1〜3ヶ月が目安となります。既存の文書データの整備状況、社内のセキュリティ要件、連携すべきシステムの数によって大きく変動するため、事前にPoCスコープを明確化することが重要です。

Q. RAGとファインチューニングのどちらを選ぶべきですか?

最新情報や社内データに基づく回答が必要な場合はRAG、特定のタスクでの出力スタイルや専門知識の習得にはファインチューニングが適しています。多くのケースではRAGから始め、出力の癖や専門語彙の定着が必要になった段階でファインチューニングを追加する、段階的アプローチが推奨されます。