ローカルRAG: introduction
ローカル RAG(検索拡張生成)を使うと、自分のコンピュータで動作するモデルで、自分の文書について質問できます。ファイルを分割し、埋め込みモデルでベクトルに変換したうえで、質問のたびに、質問に最も近い文章部分だけをモデルのプロンプトに追加します。インデックス作成にも回答生成にも、コンピュータの外へデータを送る必要はありません。
この入門ガイドでは、ローカルRAGの仕組み、Ollama上で構築するための最小構成、ノーコードの選択肢、LlamaIndexを使ったPythonの例を説明します。特に、多くの初期の試行がつまずく点である、分割、言語、検索、PDFを取り上げます。また、RAGが適切な解決策ではない場合も示します。
#ローカルRAG:定義と期待できること
RAGはretrieval-augmented generation(検索拡張生成)の略です。まず文書データベースから関連する箇所を取得し、それらに基づいて回答を書くようモデルに依頼します。「ローカル」とは、文書の読み取り、埋め込みの計算、保存、生成という各工程が、使用する機器上で実行されることを意味します。これはプライベートモデルの最も有用な使い方です。契約書、メモ、社内ナレッジベースについて質問し、出典を引用した回答を得られます。
| コンポーネント | 役割 | 例 |
|---|---|---|
| ドキュメント読み取り機能 | PDF、Word、Markdown、HTMLからクリーンなテキストを抽出 | LlamaIndexのリーダー、Docling |
| チャンク分割器(chunker) | テキストを適切なサイズのセグメントに分割 | トークンまたは構造に基づく分割 |
| 埋め込みモデル | 各テキスト断片をベクトルに変換する | embeddinggemma, qwen3-embedding, all-minilm(Ollama が推奨) |
| ベクトルデータベース | ベクトルを保存し、最も近いものを検索する | ChromaDB、Qdrant、FAISS、pgvector |
| 生成モデル | 抜粋箇所に基づいて回答を作成する | OllamaまたはLM Studio経由で配信されるモデル |
#すべてをモデルに送るのではなく、RAGを使う理由
あなたのドキュメント、あなたのAI:あなたのPDF、メモ、メールを扱う信頼性の高いローカルRAG。何もクラウドに送信しません。
- 永久に利用できるオンラインスペース
- PDF + ファイル
- 生涯アップデート
まず考えられるのは、すべての文書をプロンプトにコピーすることです。しかし、これには2つの限界があります。コンテキストウィンドウには上限があり、300個のPDFは数百万トークンに相当するため、ローカルモデルが受け入れられる範囲を大きく超えます。また、文書が収まる場合でも、品質は低下します。代表的な研究(Liuほか、スタンフォード大学)は、有用な情報が長いコンテキストの中央にあると、長いコンテキスト向けに設計されたモデルでも性能が大幅に低下する可能性があることを示しています。この現象はlost in the middleと呼ばれます。
RAGは、質問に合わせて選んだ少数の文章だけをモデルに渡すことで、この2つの問題を回避します。モデルが読むのは、あまり役に立たない数万トークンではなく、質問に的を絞った数百トークンなので、計算コストとレイテンシが下がります。肝心なのは、適切な文章を検索して取り出すことです。
例として、20ページのPDFを300件、1ページ約600トークンとすると、合計360万トークンになります。これは、ローカルモデルでよく設定する8,000トークンのコンテキストの数百倍です。400トークンの文章に分割すると約9,000件になり、1つの質問で5件、つまり2,000トークンを取り出します。検索が成功すれば、モデルが読むのはコーパスの0.06%ですが、適切な0.06%です。
#2分でわかる概念:埋め込みと距離
エンベディングとは、テキストの意味を表す数値のリストです。同じ内容について述べている2つのテキストは、同じ単語を使っていなくても、ベクトルが近くなります。Ollamaのドキュメントでは、エンベディングはベクトルデータベースに保存し、コサイン類似度で検索したり、RAGで使用したりできる数値ベクトルとして説明されており、その長さはモデルによって異なり、一般的には384次元から1024次元の間です。
質問は同じモデルでベクトルに変換され、インデックスに登録されたすべての文章断片と比較されます。その中で最も近いものが返されます。初心者がつまずきやすいのは、インデックス作成に使う埋め込みモデルと質問に使う埋め込みモデルが同一でなければならないという点です。LlamaIndexのドキュメントも、インデックスの再読み込みの例で、作成時に使ったものと同じembed_modelを使うことが重要だと説明しています。
#RAGの仕組み:2つのフェーズ
#フェーズ1:インデックス作成(ドキュメントごとに一度だけ実行)
- 01取り込みファイル(PDF、Word、Markdown、HTML)を読み取り、整形されたテキストを抽出する。これは最も軽視されがちな工程です。
- 02分割精度を確保できる程度に小さく、意味を保てる程度に大きな文章のまとまりに分割する。まずは200〜500トークン程度のまとまりから始めるのが一般的です。
- 03Embedding各テキスト断片を埋め込みモデルで処理する。たとえば、ollama run embeddinggemma コマンドまたは /api/embed API を使用する。
- 04ストレージ元のテキストとメタデータ(ファイル名、ページ、日付)とともにベクトルを保存
#フェーズ2:各質問に対するリクエスト
- 01質問の埋め込みインデックス作成用と同じモデルを使用
- 02検索コサイン類似度でベクトルの近さを測り、最も近い N 個の文章を見つける。
- 03プロンプトの構成抜粋と、出典を引用して回答し、抜粋に答えがない場合はその旨を伝えるという指示を含むメッセージを作成する。
- 04生成このプロンプトをローカルモデルに送信する。モデルが回答を生成する。
#最小限のスタックとノーコードの選択肢
機能するローカルRAGには、4つの要素で十分です: Ollama によって提供される生成モデル、埋め込みモデル、ベクトルデータベース、そしてそれらを連携させるレイヤーです。フランス語の場合、多言語対応の埋め込みモデルを選択してください。Ollama のページでは3つ(embeddinggemma、qwen3-embedding、all-minilm)が推奨されており、ベクトルサイズは控えめなため、ノートパソコン上で実行できます。
| 経路 | 労力 | 制御 | 適した対象 |
|---|---|---|---|
| LM Studio, Chat with Documents | 会話に.pdf、.docx、.txtファイルをドラッグアンドドロップ | 低い:ドキュメント全体とRAGの間で自動切り替え | いくつかのファイルで手軽に試す |
| AnythingLLM | 埋め込みモデルとベクトルデータベースを選べるアプリケーション | 中程度 | 開発者がいない小規模なチーム |
| Open WebUI | Ollama に接続されたウェブインターフェース、知識ベース | 中程度 | 蓄積したノートを日常的に利用する |
| PythonでのLlamaIndexまたはHaystack | コードの作成が必要 | 高:分割、検索、評価 | 独自仕様のプロジェクト、またはデプロイを予定しているプロジェクト |
コードを書かずに利用するための方法は、LM StudioでのRAGに関するガイドとAnythingLLMに関するガイドで、それぞれ詳しく説明しています。NotebookLMとローカルの代替ツールに関するガイドでは、「notebook lm rag」という検索クエリに対応する内容を扱っています。
#Pythonによるパイプラインをステップごとに解説
以下の例は、LlamaIndexのローカルモデル用公式チュートリアルの構成に従っています。ディレクトリーリーダー、埋め込みモデル、Ollamaによって提供されるモデル、そしてクエリエンジンです。まず、llama-index-llms-ollamaとllama-index-embeddings-huggingfaceのパッケージをインストールしてください。モデル名は、ダウンロードしたものに合わせて調整してください。
初回の実行ではすべての埋め込みを計算するため、データ量やマシンによって所要時間が変わります。すべてを再計算せずに済むように、index.storage_context.persistでインデックスを保存し、同じ埋め込みモデルを再利用してload_index_from_storageで読み込んでください。チュートリアルにも明記されているとおり、context_windowパラメータはメモリ消費量を制限します。
#最初の試みが失敗する原因となる落とし穴
- 単純な分割は構造を破壊します
- 表の途中で分割すると、内容が読み取れない断片が生じます。見出しや表の構造を保つ分割ツールを使うか、まずDoclingで文書を変換してください。
- エンベディングの言語は重要です
- 主に英語で学習された埋め込みモデルは、フランス語の文章を検索する性能が劣ります。多言語モデルを選び、コーパス全体をインデックス化する前に、実際の質問10問でテストしてください。
- 単一のtop-k値ですべてに対応できることはまれです
- 渡す文章の抜粋が少なすぎると回答の内容が乏しくなり、多すぎるとモデルが情報に埋もれてしまいます。文書の性質に応じて調整し、答えがわかっている質問で確認してください。
- 検索の質が低いと、自信ありげで誤った回答が生成されます
- 関連性のない抜粋を与えられたモデルは、確信に満ちているように見える回答を捏造することがあります。まず、抜粋の関連性を評価してください。
- PDFには落とし穴がある
- 二段組、フッター、表、スキャン文書などがあるため、取り込むデータを整える作業が全体のかなりの部分を占めます。スキャンされたPDFには、他の処理に先立ってOCRが必要です。
- 埋め込みモデルを混在させる
- あるモデルでインデックスを作成し、別のモデルで検索すると、エラーメッセージが出ないまま、意味をなさない結果が返されます。
#RAGを使わないほうがよい場合
| 状況 | 最適なアプローチ | なぜ |
|---|---|---|
| 二十ページ未満 | すべてをコンテキストに含める | よりシンプルで、文書のどの部分も取りこぼしません。文書が収まる場合は、LM Studioもこの方法を使います |
| 構造化データに関する事実を尋ねる質問(2024年の売上高) | SQLクエリまたは抽出スクリプト | RAGはテキストを検索するだけで、正確な計算は行いません |
| コーパス全体を総合して答える質問 | 階層的な要約の後に、要約に関する質問 | RAGで取得できるのは少数の文章の抜粋だけで、全体像ではありません |
| 常に変更されるドキュメント | インクリメンタルインデックス化またはキーワード検索 | 変更ごとに再インデックスするよりも、問い合わせを行う方がコストが低い |
| スタイルやフォーマットを学習する | Fine-tuning | RAGは事実を提供するもので、文章の書き方を示すものではありません |
ファインチューニングとRAGの比較ガイドでは、最後に挙げたケースを詳しく説明しています。
#ハードウェアとプライバシー:手元に残るもの
完全にローカルで動く RAG では、文書、ベクトル、質問がマシン内にとどまります。ただし、すべての構成要素がローカルで動くことが条件です。埋め込みモデルは Ollama で提供するかディスクから読み込み、ベクトルデータベースはファイルまたはローカルサービスとして動かし、生成モデルもローカルで実行する必要があります。オンラインサービスを呼び出す構成要素がないことを確認してください。クラウドの埋め込みモデルや生成モデルを誤って選ぶと、文書の該当箇所が外部に送信されます。
ハードウェア面では、最もリソースを必要とするのは生成モデルです。Q4では、80億〜90億パラメータのモデルが約5 GBのメモリに収まり、これにコンテキスト用のメモリが加わります。ここでは抜粋を含むためコンテキストが大きくなります。文書断片の数を増やす場合は、メモリに余裕を持たせてください。埋め込み自体は軽量です。大規模コーパスの初回インデックス作成が最も時間のかかる処理ですが、行うのは一度だけです。GPUなしでLLMを動かすためのガイドでは、各RAM容量で何ができるかを説明しています。
#次は何をする?改善を進める順序
基本的なRAGは、単純な質問によく対応します。さらに進める場合、最も費用対効果の高い順序は次のとおりです。まず構造を尊重したチャンク分割、次にハイブリッド検索(ベクトル検索とBM25によるキーワード検索。契約番号などの正確な用語を見逃さないため)、その後で上位の結果を再順位付けするリランカー、最後に回答が既知の約50問のセットでの評価です。測定なしでは、各変更は印象に留まります。
ローカルRAGとは何ですか?+
RAGとファインチューニングの違いは?+
フランス語にはどのエンベディングモデルを選べばよいですか?+
ローカルRAGにはGPUが必要ですか?+
インデックス作成時の文章チャンクの長さはどのくらいにすればよいですか?+
自分のRAGが正しく回答しているか、どう確認すればよいですか?+
- ソース:Ollama でのエンベディング
- 出典:LlamaIndexチュートリアル(ローカルモデルを用いた)
- 出典:Lost in the Middle (Liu et al.)
- ソース:LM Studio、Chat with Documents
ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。