3.

RAG 入門|検索 + LLM の仕組み・実装・ベクトル DB 完全ガイド

編集
この記事の要点
  • RAG (Retrieval-Augmented Generation): 検索 + LLM で「外部知識」を回答に組み込む技術
  • なぜ必要?: LLM 単体では最新情報や社内情報を知らない、長文を全部入れるとコスト高
  • 構成: 文書 → チャンク分割 → Embedding でベクトル化 → ベクトル DB 保存 → 検索 → LLM に渡して回答
  • 主要 Embedding: text-embedding-3-large (OpenAI), voyage-3 (Anthropic 推奨), Cohere Embed
  • ベクトル DB: Pinecone (SaaS), Weaviate, Chroma, pgvector (PostgreSQL 拡張)
  • フレームワーク: LangChain, LlamaIndex で実装が劇的に簡単に

RAG とは

RAG (Retrieval-Augmented Generation、検索拡張生成) は、「LLM」+「検索」を組み合わせた仕組みです。質問に対して、まず関連する文書をデータベースから検索し、その内容を LLM に渡して回答を生成させます。

例えば「うちの会社の経費精算ルールは?」と聞いた時、LLM 単体ではそんなルールを知らないので答えられません。しかし RAG なら社内マニュアルをベクトル DB に入れておき、検索で該当箇所を引いてきて LLM に渡すことで、「社内ルールに基づいた正確な回答」を返せます。

なぜ RAG が必要か

  • 知識のカットオフ: LLM は学習時点までの知識しか持たない(最新ニュースを知らない)
  • 社内・専門情報: 学習データに含まれない情報(製品マニュアル・社内 wiki)は回答できない
  • コスト: 全文書を毎回プロンプトに入れると高額、必要な部分だけ渡すと安い
  • コンテキスト窓制限: GPT-5 で 128K、Claude で 200K tokens まで、それを超える文書は入らない
  • ハルシネーション抑制: 根拠となる文書を引きながら回答するので嘘が減る
  • 出典明示: 「この回答は文書 X の Y ページから」と引用元を提示できる

RAG の基本構成

セットアップ段階(一度だけ実行)

  1. 文書の収集: PDF / Word / HTML / Notion 等から本文を抽出
  2. チャンク分割: 長い文書を 500〜1500 トークン程度の塊に分ける
  3. Embedding: 各チャンクをベクトル(数百〜数千次元の数値列)に変換
  4. ベクトル DB へ保存: チャンクとベクトルをペアで保存

クエリ段階(質問のたびに実行)

  1. ユーザの質問を Embedding でベクトル化
  2. ベクトル DB から類似度が高いチャンクを Top-K (5〜10件) 取得
  3. 取得したチャンク + 質問を LLM のプロンプトに組み立てて投げる
  4. LLM が文脈を踏まえた回答を生成

セットアップ・準備

# Python 環境
pip install openai chromadb langchain langchain-openai pypdf

# 環境変数
export OPENAI_API_KEY="sk-..."

最初のコード — Hello World

from openai import OpenAI
import chromadb

client = OpenAI()
chroma = chromadb.Client()
collection = chroma.create_collection("my_docs")

# 1. 文書をチャンク化して保存
docs = [
    "弊社の経費精算は毎月25日締めで翌月10日払いです。",
    "出張旅費は事前申請が必要です。10万円以上は部長承認。",
    "有給休暇は入社半年後に10日付与され、年次で繰越可能。"
]

# 2. Embedding を取得して保存
for i, doc in enumerate(docs):
    emb = client.embeddings.create(
        model="text-embedding-3-small",
        input=doc
    ).data[0].embedding
    collection.add(ids=[str(i)], embeddings=[emb], documents=[doc])

# 3. 検索 → LLM に渡して回答
query = "経費精算はいつ振り込まれる?"
q_emb = client.embeddings.create(
    model="text-embedding-3-small",
    input=query
).data[0].embedding

result = collection.query(query_embeddings=[q_emb], n_results=2)
context = "\n".join(result["documents"][0])

answer = client.chat.completions.create(
    model="gpt-5",
    messages=[
        {"role": "system", "content": "以下の社内情報を根拠に回答してください。\n" + context},
        {"role": "user", "content": query}
    ]
)
print(answer.choices[0].message.content)

主要コンポーネント

Embedding モデル

モデル次元数料金 ($/1M tokens)特徴
text-embedding-3-large3072$0.13★ OpenAI 最高精度
text-embedding-3-small1536$0.02OpenAI 軽量版・コスパ良
voyage-31024$0.06★ Anthropic 推奨
Cohere embed-v31024$0.10多言語対応強い
BGE (OSS)1024無料★ ローカル動作可能

ベクトル DB

DB形態特徴
PineconeSaaS★ 最も使われる商用ベクトル DB
WeaviateSaaS / OSSGraphQL クエリ・ハイブリッド検索
ChromaOSS / ローカル★ 開発・PoC に最適、Python だけで完結
pgvectorPostgreSQL 拡張既存 RDB に追加可、運用容易
MilvusOSS大規模向け、Kubernetes
QdrantOSS / SaaSRust 製・高速
FAISSライブラリMeta 製、ライブラリレベル

実践コード例

例 1: LangChain で PDF を RAG 化

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA

# 1. PDF 読み込み
loader = PyPDFLoader("manual.pdf")
docs = loader.load()

# 2. チャンク分割
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
chunks = splitter.split_documents(docs)

# 3. ベクトル化して保存
vectordb = Chroma.from_documents(chunks, OpenAIEmbeddings())

# 4. RAG チェーン構築
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-5"),
    retriever=vectordb.as_retriever(search_kwargs={"k": 4})
)

print(qa.run("経費精算の手順を教えて"))

例 2: LlamaIndex で Notion を RAG 化

from llama_index.core import VectorStoreIndex
from llama_index.readers.notion import NotionPageReader

# Notion から記事を読み込む
documents = NotionPageReader(integration_token="secret_xxx").load_data(
    page_ids=["abc123", "def456"]
)

# インデックス構築(裏で Embedding + ベクトル DB)
index = VectorStoreIndex.from_documents(documents)

# クエリ
query_engine = index.as_query_engine()
print(query_engine.query("プロジェクトAの進捗状況は?"))

Chunking 戦略

戦略説明適用シーン
固定長1000 tokens 等で機械的に分割シンプル・標準
区切り文字句点・改行で自然な境界日本語文書
Recursive章 → 節 → 段落 → 文と階層的に★ 構造化文書(推奨)
Semantic意味の切れ目を Embedding で判定精度重視・コスト高
Overlap隣接チャンク間で 100〜200 tokens 重複★ 文脈断絶を防ぐ(推奨)

精度向上テクニック

Hybrid Search(ベクトル検索 + キーワード検索)

ベクトル検索だけでは固有名詞や型番が見つけづらいことがある。BM25 / Elasticsearch 等のキーワード検索と組み合わせて、両方の結果をマージすると精度が上がる。

Re-ranking

ベクトル検索で粗く 20 件取得 → Cohere Rerank / BGE Reranker 等で再評価して上位 5 件を LLM に渡す。検索精度が大幅に上がる。

HyDE (Hypothetical Document Embeddings)

質問をそのまま Embedding するのではなく、LLM に「もし回答があるならこんな文章だろう」という仮想回答を生成させてから Embedding。質問と文書の表現ギャップを埋めるテクニック。

評価指標

  • Recall@K: 正解チャンクが上位 K 件に含まれる割合
  • MRR (Mean Reciprocal Rank): 正解の順位の逆数の平均
  • Faithfulness: 回答が引用文書に忠実か(ハルシネーションしてないか)
  • Answer Relevance: 回答が質問に対して適切か
  • RAGAS: これらを自動評価する OSS フレームワーク

注意点・落とし穴

  • チャンクサイズ: 大きすぎるとノイズ、小さすぎると文脈断絶。500〜1500 tokens が目安
  • Embedding モデルの変更: 後から変えると全データの再 Embedding が必要、慎重に選定
  • 多言語: 日本語の精度はモデルにより大差、voyage / multilingual-e5 等を検証
  • 更新頻度: 文書が更新されたら該当チャンクを再 Embedding しないと古い情報を返す
  • 権限管理: 社内 RAG では「ユーザが見れる文書のみ検索対象に」というフィルタリング必須
  • 引用元提示: ユーザが信頼するには「どの文書のどこから」を明示すべき

関連リンク

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. OpenAI API 入門 — Python / Node.js から GPT-5 を呼ぶ
  2. Anthropic Claude API 入門 — Claude 4 を使い倒す
  3. RAG (Retrieval-Augmented Generation) 入門
  4. LangChain 入門 — LLM アプリ開発フレームワーク

最近更新/作成されたページ