[LLM] RAG(検索拡張生成)

RAG(Retrieval-Augmented Generation/検索拡張生成)は、LLMの「記憶の弱点」を補うための仕組み

### RAGの基本アイディア
– 学習データが古い
– 企業固有の情報を知らない
– 事実を正確に記憶していない

### RAGの仕組み(流れ)
1. ユーザーの質問(Query)

2. 検索(Retrieval)
・質問を ベクトル化(embedding) して数値化
・ベクトルデータベース(例:FAISS, Chroma, Milvusなど)から
・「意味的に近い文書」を検索

3. 統合(Augmentation)
検索で得たテキストをまとめて「プロンプトに埋め込む」

以下の資料を参考に質問に答えてください:
[資料1: ...]
[資料2: ...]
質問:2025年の日本の経済成長率は?

4. 生成(Generation)
LLMがその検索結果(コンテキスト)をもとに回答を生成

ユーザー質問

【Embedding】→ ベクトル化

【Vector DB】→ 意味的に近い文書を検索

【Augmentation】→ 文書をプロンプトに追加

【LLM生成】→ 文脈に基づいて回答生成

### デメリット
– 検索精度が悪いと、間違った情報を引用してしまう
– ベクトルDBの管理・更新が必要
– 長いコンテキストを扱うとコストが増える

from openai import OpenAI
import faiss
import numpy as np

client = OpenAI(api_key="sk-***")

docs = ["富士山は日本で一番高い山です", "日本の首都は東京です"]
embs = [client.embeddings.create(model="text-embedding-3-small", input=d).data[0].embedding for d in docs]


index = faiss.IndexFlatL2(len(embs[0]))
index.add(np.array(embs))

query = "日本の一番高い山は?"
q_emb = client.embeddings.create(model="text-embedding-3-small", input=query).data[0].embedding

D, I = index.search(np.array([q_emb]), k=1)
context = docs[I[0][0]]

prompt = f"次の情報を参考に質問に答えてください。\n資料: {context}\n質問: {query}"
resp = client.responses.create(model="gpt-4o-mini", input=prompt)

print(resp.output_text)

$ python3 rag.py
日本の一番高い山は富士山です。

FAISSとPostgreSQLの違い
観点 FAISS PostgreSQL(psql)
開発元 Meta(旧Facebook) PostgreSQL Global Development Group
主な用途 ベクトル検索(類似度検索) 構造化データの検索・管理
データの種類 数値ベクトル(例:768次元の埋め込み) テーブル形式(行・列)
検索内容 「意味的に似ている文章や画像を探す」 「条件に一致する行を探す(例:WHERE句)」
検索方法 コサイン類似度 / 内積 / L2距離 SQL文(SELECT, JOIN, ORDER BYなど)
速度 超高速(数百万ベクトルでもミリ秒単位) 適度(構造化クエリに最適)
保存形式 メモリ上のインデックス(永続化も可) 永続的なデータベースファイル
例 「この文に似た文を探せ」 「age > 30 のユーザーを取得」

なるほど、FAISSはmetaが開発しているのね。