レッスン 1 / 6
RAGとは?いつ使う?
学ぶコト
- LLMが社内の情報について答えられない理由
- RAG・ファインチューニング・長いコンテキストの使い分け
- RAGの処理の流れ(読み込み→分割→埋め込み→検索→回答)
- 用意されたサービスを使うか、自分で作るかの判断
このコースでは、社内の規程やFAQをもとに質問に答えるAIを、Python で一から作ります。この仕組みを RAG(Retrieval-Augmented Generation、検索拡張生成)と呼びます。
題材にするのは、架空の会社「みなと文具」です。社員300人ほどの文房具メーカーで、在宅勤務規程・経費精算規程・休暇規程・情報システム部のFAQといった、どの会社にもありそうな資料を持っています。人事部や情報システム部には「在宅勤務は週に何日まで?」「VPNがつながらない」といった同じ質問が毎日届くので、資料をもとに答えるAIを作って、担当者の手間を減らしたい、という設定です。
最初のレッスンでは、コードの細かい話に入る前に「なぜ RAG が必要なのか」「ほかのやり方とどう使い分けるのか」をおさえます。
LLMは「あなたの会社のこと」を知らない
ChatGPT のようなチャットのAIに「うちの会社の在宅勤務は週に何日まで?」と聞いても、正しい答えは返ってきません。運がよければ「会社の規程を確認してください」と言われますが、「一般的には週2〜3日の会社が多いです」のように、それらしい一般論が返ってくることもあります。
理由は3つあります。
- 学習していない:大規模言語モデル(LLM)が学習したのは、主にWebなどで公開されている文章です。社内の規程や議事録は、そもそも学習のデータに入っていません
- 情報が古い:LLMが知っているのは学習した時点までのことです。先月改定した規程は知りません
- 出典を示せない:仮に知っていたとしても、「どの資料の何条に書いてあるか」を示せないので、答えが正しいかを確かめられません
LLMの仕組みそのものは「LLMのしくみとAPI入門」のコースで学びました。LLMは、渡された文章の続きとして自然な文章を作るのが得意です。ということは、答えの根拠になる資料を、質問と一緒に渡してあげればよいわけです。これが RAG の出発点です。
社内の情報を使わせる3つの方法
LLMに社内の情報を使わせる方法は、大きく分けて3つあります。
1. 資料をまるごとプロンプトに入れる(長いコンテキスト)
いちばん単純なのは、関係しそうな資料を全部プロンプトに入れてしまう方法です。最近のLLMは一度に読める量(コンテキストウィンドウ)がとても大きく、このコースで使う OpenAI の gpt-6-luna は、一度に約92万トークンまで入力できます(2026年10月時点。GPT-6 Luna のページ)。日本語はおよそ1文字が1トークン弱なので、規程の数十ページなら余裕で入ります。
資料が少なく、めったに変わらないなら、まずこの方法を試す価値があります。一方で、次のような弱点があります。
- 毎回のお金と時間:質問のたびに資料を全部送るので、送る量に比例して料金がかかり、答えが返るまでの時間も長くなります。同じ前置きをくり返し送ると割安になる仕組み(プロンプトキャッシュ)もありますが、資料が増えるほど負担は大きくなります
- 長い入力の中での取りこぼし:入力の真ん中あたりにある情報ほど見落とされやすい、という研究があります(Lost in the Middle、2023年)。モデルは改善を続けていますが、関係のない文章が大量にあると、答えの質が下がることは今でも起こりえます
- 量の上限:会社の資料が全部で数千ファイルあるなら、どれだけ大きなモデルでも一度には入りません
- 見せてよい範囲:全員に同じ資料を渡すので、「人事部の人だけが見てよい資料」のような区別がつけにくくなります
2. ファインチューニング
手元のデータでモデルを追加で学習させ、モデルそのものを変える方法です。言葉づかい・答えの形式・決まった分類のしかたのような「振る舞い」を覚えさせるのには向いています。
ただし、規程の中身のような「事実」を覚えさせる方法としては、あまり向いていません。
- 規程が変わるたびに学習し直す必要がある
- 覚えたことの出典を示せない
- 古い内容だけを忘れさせる、ということができない
Microsoft の研究者による論文(Fine-Tuning or Retrieval?、2023年)でも、新しい知識をモデルに使わせる目的では、ファインチューニングより RAG のほうがよい結果になったと報告されています。
3. RAG(検索してから答える)
RAG は、質問が来るたびに資料の中から関係のある部分だけを検索し、その部分を質問と一緒にLLMに渡して答えさせる方法です。図書館で、司書さんが関係のある本のページを開いて見せてから答えてくれるイメージです。
- 資料が変わったら、その資料を検索の索引に入れ直すだけでよい(モデルの学習は要らない)
- 答えと一緒に「在宅勤務規程 第4条」のような出典を示せる
- 検索の段階で、その人が見てよい資料だけに絞り込める
- 送るのは関係のある数か所だけなので、資料が大量にあっても1回の料金は小さい
その代わり、検索で正しい資料を見つけられないと、正しい答えは出ません。RAG の質の大部分は、検索の質で決まります。このコースの後半で、検索をよくする方法と、それを数字で確かめる方法を学ぶのはそのためです。
使い分けの目安
| 長いコンテキスト | ファインチューニング | RAG | |
|---|---|---|---|
| 向いていること | 少ない資料をまるごと読ませる | 口調・形式・分類のしかたを覚えさせる | 大量の資料から、根拠を探して答える |
| 資料が変わったとき | 入れる資料を差し替える | 学習し直す | 変わった資料だけ索引に入れ直す |
| 出典を示す | やや難しい | できない | しやすい |
| 1回の質問の料金 | 資料の量に比例して大きい | 小さい | 小さい(検索の分が少しかかる) |
| 作る手間 | ほぼない | 学習データの準備が大きい | 検索の仕組みを作る |
RAGの処理の流れ
RAG の仕組みは、前もってやっておく「準備」と、質問が来るたびに動く「回答」の2つに分かれます。
読み込む(準備)
PDF・Word・Webページ・社内Wikiなどから、文章を取り出します。表や見出しがくずれないように取り出せるかが、意外と大事なところです。
分ける(準備)
長い資料を、検索しやすい大きさのかたまり(チャンク)に分けます。チャンクには「どの資料の、どの見出しの部分か」という情報(メタデータ)も付けておきます。
ベクトルにする(準備)
チャンクを、意味を表す数の並び(ベクトル)に変えます。これを埋め込み(embedding)と呼び、専用のAPIで作ります。
保存する(準備)
チャンクの文章・メタデータ・ベクトルをまとめて保存します。これが検索の索引(インデックス)です。
検索する(回答)
質問もベクトルにして、意味が近いチャンクを上から数個取り出します。キーワードでの検索と組み合わせることもあります。
答えを作る(回答)
取り出したチャンクを質問と一緒にLLMに渡し、「資料に書いてあることだけで答え、出典の番号を付けて」と頼みます。資料に答えがなければ「分かりません」と答えさせます。
最小のRAGを動かしてみる
このページの Python のコードは「▶ 実行」を押すと、ブラウザの中で動かせます。上から順に実行してください。
まずは「検索」の部分を、とても単純なやり方で作ってみます。質問と資料に共通する「2文字の並び」がいくつあるかを数え、多い順に並べます。
rules = [
"在宅勤務は1週間に3日までです。",
"出張の交通費は、出張から1か月以内に経費精算システムで申請します。",
"年次有給休暇は、入社6か月後に10日付与されます。",
"パスワードを忘れたときは、情報システム部のポータルからリセットを申請します。",
]
def overlap_score(question, text):
# 質問と資料に共通する「2文字の並び」の数を数える(とても単純な検索)
q = {question[i:i + 2] for i in range(len(question) - 1)}
t = {text[i:i + 2] for i in range(len(text) - 1)}
return len(q & t)
question = "在宅勤務は週に何日までできますか?"
ranked = sorted(rules, key=lambda r: overlap_score(question, r), reverse=True)
for r in ranked:
print(overlap_score(question, r), r)
在宅勤務の資料が7点でいちばん上に来ました。ほかの資料にも1点ずつ入っているのは、「ます」のような、どの文にもある並びが一致したからです。
次に、見つかった資料を質問と一緒にプロンプトに入れます。
prompt = "\n".join([
"次の資料だけを使って、質問に答えてください。",
"答えの最後に、使った資料の番号を [1] のように付けてください。",
"資料に答えがないときは「資料には見つかりませんでした」と答えてください。",
"",
"# 資料",
f"[1] {ranked[0]}",
"",
"# 質問",
question,
])
print(prompt)
この文章をLLMに送れば、「在宅勤務は1週間に3日までです [1]」のような答えが返ってきます。RAG の正体は「検索」と「プロンプトの組み立て」で、LLMそのものには何も手を加えていません。
もちろん、実際の検索はこんなに単純ではありません。「リモートワーク」と聞かれたら「在宅勤務」の資料を見つけたいですし、資料が何百もあれば、たまたま同じ文字を含むだけの資料も混ざってきます。次のレッスンから、この「検索」を本格的なものにしていきます。
用意されたサービスを使うか、自分で作るか
RAG は、自分で一から作らなくても使えるようになってきました。
- OpenAI の API のファイル検索(file search):ファイルを「ベクトルストア(vector store)」に上げると、分割・埋め込み・検索までをAPIの側でやってくれ、回答に出典も付きます(ファイル検索のガイド)
- Gemini API の File Search:Google の Gemini API にも、同じような仕組みがあります(File Search)
- Claude(Anthropic)の API:渡した資料のどの部分を根拠にしたかを返す Citations の機能があります(Citations)。埋め込みのモデルは自社では出しておらず、Voyage AI などのほかの会社のものを使うよう案内しています(Embeddings)
- チャットのサービスの機能:ChatGPT・Claude・Gemini などには、ファイルを入れておくと、それをもとに答えてくれる機能があります。プログラムを書かずに使う方法は「生成AIの仕事での使い方」のコースで扱っています
用意されたサービスは、少ない手間ですぐに動くのが強みです。一方で、分け方・検索のしかた・絞り込みの条件を細かく決めたいとき、うまく答えられない原因を調べたいとき、資料を置く場所を自分で決めたいときは、自分で作るほうが向いています。
このコースでは、まず自分で作って中身を理解し、そのうえでファイル検索の使い方も見ます。中身が分かっていれば、用意されたサービスを使うときにも「なぜこの質問には答えられないのか」を考えられるようになります。
このコースの進め方
| レッスン | 内容 |
|---|---|
| 1. RAGとは?いつ使う? | RAGが必要な理由と使い分け、処理の流れ(このレッスン) |
| 2. 検索のしくみ:キーワードとベクトル | TF-IDF・BM25 と、埋め込み・cos類似度 |
| 3. 文書の分け方 | チャンクの大きさと重なり、見出しで分ける、メタデータ |
| 4. RAGを作る | 埋め込みのAPI、検索、プロンプト、出典付きの回答 |
| 5. 検索を良くする | ハイブリッド検索、質問の書き換え、絞り込み、並べ替え |
| 6. RAGを評価する | 質問のセット、検索と回答の評価、改善のくり返し |
このレッスンとレッスン2・3・5・6のコードは、すべてブラウザの中で動きます。APIを使うのはレッスン4だけで、Google Colab で動かします。
前提として、「LLMのしくみとAPI入門」で OpenAI の API の呼び出し方を学んでいることを想定しています。「PythonでAIチャットボットを作る」も終えていると、会話の履歴の扱いなどがスムーズに分かります。
演習
まとめ
- LLMは、学習していない社内の情報や、学習した後に変わった情報には答えられない。答えの根拠になる資料を、質問と一緒に渡せばよい
- 社内の情報を使わせる方法には、長いコンテキスト・ファインチューニング・RAG がある。資料が多い・よく変わる・出典が要る・見せる範囲を分けたいなら RAG
- RAG は「読み込む→分ける→ベクトルにする→保存する」の準備と、「検索する→答えを作る」の回答に分かれる。質の大部分は検索で決まる
- OpenAI のファイル検索など、用意されたサービスもある。このコースでは自分で作って中身を理解する
次のレッスンでは、RAG の心臓部である「検索」の仕組みを、キーワードの検索とベクトルの検索の両方から見ていきます。
分からないところがあればこのレッスンについて質問するこのコースの Q&A を見る
