確認日:2026年9月24日。各社の公式ドキュメントと原論文で確認し、サンプルコードの検索部分は筆者の Mac(Python 3.12)で実行しました。この記事は2025年1月に公開した「RAG完全実装ガイド」を、今の状況に合わせて全面的に書き直したものです。
はじめに:AI に「社内の資料」を見ながら答えさせたい
ChatGPT や Claude に社内のルールを聞いても、正しく答えられません。AI は学習したときのデータしか知らず、あなたの会社の資料は読んだことがないからです。
そこで使われるのが RAG(ラグ、Retrieval-Augmented Generation:検索拡張生成)です。質問に関係する資料を先に探して、その資料を AI に渡してから答えてもらう仕組みです。
この記事では、次のことを順番に説明します。
- RAG とは何か、なぜ必要か
- AI が長い文章を読めるようになった今でも RAG が必要な理由
- 仕組みと、約60行で動く最小のサンプル
- 検索の精度を上げる方法
- 自分で作らずに使えるサービス
- 評価の方法とセキュリティの注意点
RAG とは:「持ち込み可の試験」のようなもの
RAG は、AI にとっての持ち込み可の試験にたとえられます。何も持たずに答える(ふつうのチャット)のではなく、手元の資料から関係するページを探して、それを見ながら答えます。
- 検索する:質問に関係しそうな資料の一部を探す
- 渡す:見つかった資料と質問を、まとめて AI に渡す
- 答える:AI が資料の内容をもとに回答する
RAG でできるようになること
| 困りごと | RAG を使うと |
|---|---|
| AI が社内の情報を知らない | 社内の資料をもとに答えられる |
| AI の知識が古い | 最新の資料を渡せば、最新の内容で答えられる |
| もっともらしい嘘(ハルシネーション)が心配 | 根拠にした資料を一緒に示せるので、確認しやすい |
| AI に覚えさせ直すのは大変 | 資料を差し替えるだけで内容を更新できる |
RAG という名前は、2020年に Meta(当時の Facebook)の研究者らが発表した論文(Lewis ほか, 2020)に由来します。
長い文章を読める AI の時代に、RAG はまだ必要?
2026年9月時点で、Claude Opus 5.5 や Sonnet 5 は一度に100万トークン(日本語で数十万字程度)を読めます。GPT や Gemini の上位モデルも同じくらいです。それなら、資料を全部そのまま渡せばいいのでは、と思うかもしれません。
実際、Anthropic は2024年9月の記事「Contextual Retrieval」で、資料が20万トークン(約500ページ)に収まるなら、RAG を作らずに全部をプロンプトに入れる方法を勧めています。同じ資料を何度も使うなら、プロンプトキャッシュ(送った文章を一時保存して割り引く仕組み)で費用も抑えられます。
一方で、次のような場合は今でも RAG が向いています。
- 資料が多すぎて、一度に読める量に収まらない
- 資料が頻繁に増えたり変わったりする
- 人によって見てよい資料が違う(権限の管理が必要)
- 質問のたびに大量の文章を送ると、費用や待ち時間が大きくなる
資料が少なければまず全部渡してみる、多ければ RAG、と考えるのが今の現実的な使い分けです。AI に渡す情報量の考え方は コーディングエージェントのコンテキスト管理入門 でも解説しています。
RAG の仕組み
RAG は「前もって準備しておく作業」と「質問が来たときの作業」の2つに分かれます。
前もって準備しておく作業
- 分割(チャンク化):資料を数百〜千文字くらいのかたまり(チャンク)に分ける
- ベクトル化(埋め込み):各チャンクを、意味を表す数値の並び(ベクトル)に変換する。意味が近い文章ほど、近い数値になる
- 保存:ベクトルを検索できる場所(ベクトルデータベース)に保存する
質問が来たときの作業
- 質問も同じ方法でベクトルに変換する
- 質問と意味が近いチャンクを数件探す
- 見つかったチャンクと質問を AI に渡して、答えてもらう
ポイントは、キーワードが一致しなくても意味が近ければ見つけられることです。たとえば「家で働けるのは週何日?」という質問で、「リモートワーク」と書かれた資料を探し出せます。
約60行で動く、いちばん小さな RAG
実際に動くサンプルを見てみましょう。社内ルールの文書4件から関係するものを探し、Claude に出典付きで答えてもらいます。ベクトル化には、無料で使える多言語対応の公開モデル multilingual-e5-small を使います。
準備
python3 -m venv .venv
source .venv/bin/activate
pip install anthropic sentence-transformers
export ANTHROPIC_API_KEY="取得したAPIキー"
Python 3.10 以上が必要です。API キーは Claude Console で作成できます。
コード(rag_min.py)
"""いちばん小さな RAG:社内ルールを検索して、出典付きで Claude に答えてもらう。"""
import anthropic
from sentence_transformers import SentenceTransformer
# 1. 検索対象の文書(実際はファイルやデータベースから読み込む)
DOCS = [
{"title": "経費精算ルール", "text": "経費の精算は、支払った月の翌月10日までに経費システムから申請します。領収書の写真の添付が必要です。"},
{"title": "リモートワーク規程", "text": "リモートワークは週3日まで認められます。前日の18時までにチャットで上長に連絡してください。"},
{"title": "PC貸与ルール", "text": "貸与PCの修理や交換は情報システム部に依頼します。私物のUSBメモリは接続禁止です。"},
{"title": "有給休暇", "text": "有給休暇は取得日の3営業日前までに勤怠システムで申請します。半日単位でも取得できます。"},
]
# 2. 文書を「意味を表す数値の並び(ベクトル)」に変換しておく
model = SentenceTransformer("intfloat/multilingual-e5-small")
doc_vecs = model.encode(["passage: " + d["text"] for d in DOCS], normalize_embeddings=True)
def search(question: str, k: int = 2) -> list[dict]:
"""質問と意味が近い文書を上位 k 件返す"""
q_vec = model.encode(["query: " + question], normalize_embeddings=True)[0]
scores = doc_vecs @ q_vec # 正規化済みなので内積 = コサイン類似度
top = scores.argsort()[::-1][:k]
return [DOCS[i] | {"score": float(scores[i])} for i in top]
def answer(question: str) -> str:
"""検索した文書だけを根拠に、Claude に出典付きで答えてもらう"""
hits = search(question)
documents = [
{
"type": "document",
"source": {"type": "text", "media_type": "text/plain", "data": h["text"]},
"title": h["title"],
"citations": {"enabled": True}, # どの文書のどこを根拠にしたかを返してもらう
}
for h in hits
]
client = anthropic.Anthropic() # 環境変数 ANTHROPIC_API_KEY を使う
response = client.beta.messages.create(
model="claude-opus-5",
max_tokens=2000,
# 安全判定で断られたときに、自動で別モデルに切り替えてもらう設定
betas=["server-side-fallback-2026-07-01"],
fallbacks="default",
system="社内ルールの質問に答えるアシスタントです。渡された文書に書かれていないことは「文書には記載がありません」と答えてください。",
messages=[{"role": "user", "content": [*documents, {"type": "text", "text": question}]}],
)
if response.stop_reason == "refusal":
return "回答できませんでした。"
parts = []
for block in response.content:
if block.type == "text":
parts.append(block.text)
for c in block.citations or []:
parts.append(f" (出典: {c.document_title})")
return "\n".join(parts)
if __name__ == "__main__":
print(answer("経費の申請期限はいつですか?"))
search() が「検索する」、answer() が「渡す・答える」の部分です。文書を document という形式で渡し、citations(引用)をオンにすると、Claude が回答のどの部分をどの文書から引いたかを返してくれます。
検索部分を動かした結果
筆者の Mac で、search() だけを実行した結果です(数字は意味の近さで、1に近いほど近い)。
| 質問 | 1位 | 2位 |
|---|---|---|
| 経費の申請期限はいつですか? | 経費精算ルール(0.882) | 有給休暇(0.821) |
| 家で働けるのは週に何日まで? | リモートワーク規程(0.830) | 有給休暇(0.825) |
| USBメモリを使ってもいい? | PC貸与ルール(0.849) | リモートワーク規程(0.804) |
3問とも正しい文書が1位になりました。ただ、2問目は2位との差がわずかです。文書が増えると、このような「僅差の取り違え」が起こりやすくなります。次の章の工夫は、この精度を上げるためのものです。
筆者の環境には API キーを設定していないため、
answer()で実際に Claude を呼び出すところまでは試していません。送信する内容が正しい形式になっていることは、SDK(anthropic 1.8.0)で確認しました。
検索の精度を上げる方法
| 方法 | 内容 |
|---|---|
| ハイブリッド検索 | 意味の近さ(ベクトル検索)と、キーワードの一致(BM25 などの全文検索)を組み合わせる。製品名や型番のような「正確な言葉」に強くなる |
| リランキング | 最初に多めに候補を集め、専用のモデルで並べ直してから上位を使う |
| チャンクに文脈を付ける | 各チャンクの先頭に「この部分は何の資料のどの話か」という短い説明を付けてからベクトル化する |
| 分割の調整 | チャンクの大きさや、隣のチャンクとの重なりを調整する。OpenAI の File Search の標準は最大800トークン・重なり400トークン |
| 質問の言い換え | 質問を検索しやすい形に書き換えたり、複数の小さな質問に分けたりする |
| AI に検索させる(エージェント型 RAG) | AI 自身が「何を、何回検索するか」を決め、足りなければ検索し直す |
Anthropic の Contextual Retrieval の検証では、チャンクに文脈を付けるだけで検索の失敗率が35%減り、キーワード検索との併用で49%減、さらにリランキングを加えると67%減ったと報告されています(出典)。
最近は、事前にすべてを検索しておくのではなく、AI エージェントが必要なときに道具として検索する形も増えています。社内のサービスや資料を AI の道具としてつなぐ仕組みは MCP 実践ガイド で紹介しています。
自分で作らずに使えるサービス
RAG は、分割・ベクトル化・保存・検索をすべて任せられるサービスも増えています。まずはこうしたサービスで試し、足りなければ自分で作る、という順番がおすすめです。
| サービス | 特徴 |
|---|---|
| OpenAI File Search | ファイルを置くだけで、意味検索とキーワード検索を組み合わせて引用付きで答える |
| Gemini API File Search | 保存や分割を含めてすべておまかせ。課金は取り込み時のベクトル化のみ |
| Claude(API) | ベクトルの保存場所はないが、自分の検索結果を出典付きで答えさせる機能(Search results・Citations)がある |
| Claude の Projects | 資料が多くなると自動で RAG に切り替わり、より多くの資料を扱える(有料プラン) |
| Amazon Bedrock Knowledge Bases | SharePoint などとの接続、文書ごとの権限、リランキングに対応 |
| Azure AI Search | ハイブリッド検索や、AI が質問を分けて検索する機能(agentic retrieval)に対応 |
自分で組み立てる場合は、LangChain や LlamaIndex といった部品集(フレームワーク)がよく使われます。
ベクトル化のモデルを選ぶ
| モデル | 特徴 |
|---|---|
| OpenAI text-embedding-3-small | 安くて手軽(100万トークンあたり0.02ドル) |
| Voyage(voyage-4 など) | Anthropic のドキュメントで例として案内されている |
| Cohere embed-v4.0 | 多言語・画像・PDF に対応 |
| Gemini embedding | 画像も扱える gemini-embedding-2 がある |
| BAAI/bge-m3・multilingual-e5 | 無料の公開モデル。日本語にも対応し、手元で動かせる |
一度ベクトル化した後にモデルを変えると、すべての資料をベクトル化し直す必要があります。最初に候補をいくつか試してから決めましょう。
うまく動いているかを測る
RAG は「検索がうまくいったか」と「回答が資料に沿っているか」を分けて確かめるのが基本です。評価用の道具としては RAGAS がよく使われ、次のような指標があります。
| 指標 | 確かめること |
|---|---|
| Faithfulness(忠実さ) | 回答が、渡した資料の内容に沿っているか |
| Response Relevancy(回答の関連性) | 回答が質問に合っているか |
| Context Precision(検索の正確さ) | 検索した資料に、関係ないものが混ざっていないか |
| Context Recall(検索の網羅性) | 答えに必要な資料を取りこぼしていないか |
RAGAS を実際に動かしながら学べるアプリの作り方は RAGAS × FastAPI × Next.js × Docker で学ぶ Web アプリ開発入門 で紹介しています。
セキュリティの注意点
AI アプリの代表的なリスクをまとめた OWASP Top 10 for LLM Applications(2025年版) では、RAG に関係する次のリスクが挙げられています。
- 資料に仕込まれた指示(間接プロンプトインジェクション):検索した資料の中に「これまでの指示を無視して…」のような文章が紛れ込んでいると、AI がそれに従ってしまうおそれがある。RAG を使っても完全には防げないとされています
- 権限の漏れ:本来見られない人の質問に、閲覧権限のない資料が検索されて答えに使われてしまう(LLM08:2025)
対策としては、検索のときに質問した人の権限で絞り込む、AI に渡す資料と指示をはっきり分ける、メール送信など影響の大きい操作の前には人が確認する、といった方法があります。
まとめ
- RAG は、質問に関係する資料を探して AI に渡し、それをもとに答えてもらう仕組みです。
- AI が100万トークンを読める今は、資料が少なければ全部渡す方法も有力です。資料が多い・頻繁に変わる・権限が必要なら RAG が向いています。
- 精度を上げるには、ハイブリッド検索・リランキング・チャンクへの文脈付けが効果的です。
- まずは OpenAI や Gemini の File Search など、おまかせのサービスで試すのが近道です。
- 評価は「検索」と「回答」を分けて行い、権限と間接プロンプトインジェクションに注意しましょう。

