RAG ナレッジベース構築実践:国産オープンモデルとローカル配備の完全ガイド
RAG ナレッジベース構築実践
RAG(検索拡張生成)は、国産オープンモデルの最も価値ある応用の一つです。自分の文書・コードベース・社内ナレッジをモデルに渡し、汎用学習データの「推測」ではなく自分のデータに基づいて回答させる — この記事では、国産オープンモデルで RAG ナレッジベースを構築する完全な流れを解説します。
30 秒でわかる要点
RAG = 文書分割 → Embedding でベクトル化 → ベクトル DB に保存 → 質問時に類似断片を検索 → プロンプトに組み込んで LLM が回答。ローカル構成は Ollama Embedding + llama.cpp モデル + Chroma、クラウド構成は EXAIV の OpenAI 互換端点 + 任意のベクトル DB。中核コードは LangChain で 30 行ほどです。
RAG の 4 工程
RAG は「文書をモデルに詰め込む」ことではありません。パイプラインです。
| 工程 | 何をするか | 重要な判断 |
|---|---|---|
| 1. 文書分割 | 文書を検索可能な断片に | チャンクサイズ、オーバーラップ |
| 2. Embedding | 断片をベクトルに | Embedding モデル選定 |
| 3. ベクトル検索 | 質問から関連断片を | ベクトル DB、類似度しきい値 |
| 4. 回答生成 | 検索断片をプロンプトに | LLM 選定、プロンプト設計 |
Embedding と LLM は別々に選ぶ
Embedding モデルは「テキストの意味を理解してベクトルに変換」し、LLM は「検索された断片から回答を生成」します。二つの独立したモデルなので、軽量 Embedding と高性能 LLM を組み合わせられます。「一つのモデルで全部」より柔軟でリソース効率も良い構成です。
Embedding とベクトル DB の選定
Embedding の選定基準は多言語対応(日本語・中国語のシナリオでは必須)、ベクトル次元(保存と検索速度に影響)、モデルサイズ(エンコード速度)です。日本語・中国語を含む場合は必ず該当言語の学習データを持つモデルを確認してください。
| ベクトル DB | 特徴 | 向いている場面 |
|---|---|---|
| Chroma | 軽量、純 Python、配備不要 | 個人プロジェクト、試作 |
| Qdrant | 高性能、フィルタ対応 | 本番環境 |
| Milvus | 分散、大規模 | エンタープライズ |
| FAISS | Meta 製、純計算ライブラリ | アプリ組み込み |
個人・小規模チームは Chroma から始めるのが最も手軽です。
完全実装:LangChain 30 行
ローカルモデルによる最小の RAG パイプライン:
# pip install langchain langchain-community chromadb
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.llms import Ollama
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 1. 文書分割
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
docs = splitter.split_documents(your_documents)
# 2. Embedding + ベクトル DB へ保存
embeddings = OllamaEmbeddings(base_url="http://127.0.0.1:11434", model="nomic-embed-text")
vectorstore = Chroma.from_documents(docs, embeddings)
# 3. 検索 + 生成
llm = Ollama(base_url="http://127.0.0.1:11434", model="your-model")
query = "あなたの質問"
results = vectorstore.similarity_search(query, k=3)
context = "\n\n".join([r.page_content for r in results])
prompt = f"以下の内容に基づいて回答してください。\n\n{context}\n\n質問:{query}"
print(llm.invoke(prompt))
クラウド API への切り替えは 3 行だけ
Ollama の LLM を EXAIV の OpenAI 互換端点に差し替え、Embedding はローカルのまま(または変更)、ベクトル DB は据え置き — LangChain の抽象層により「ローカルモデル」と「クラウド API」は差し替え可能です。これが OpenAI 互換インターフェースの価値です。
クラウド構成:EXAIV 端点
ローカルモデルを管理したくない場合、生成段を EXAIV の互換端点に任せます:
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://exaiv.com/api/ai/v1")
resp = client.chat.completions.create(
model="kimi-k3", # /models のリアルタイム ID に従う
messages=[
{"role": "system", "content": f"以下の内容に基づいて回答してください。内容が不十分なら明示してください。\n\n{context}"},
{"role": "user", "content": query},
],
)
print(resp.choices[0].message.content)
チャンク分割の戦略
| 戦略 | chunk_size | 向いている |
|---|---|---|
| 細かめ | 200-300 文字 | FAQ、短文書、精密一致 |
| 標準 | 400-600 文字 | 汎用文書 |
| 粗め | 800-1200 文字 | 長文書、文脈密度が高い |
小さければ良いわけではありません
断片が小さすぎると文脈が切れ(一つの論点が半分に割れる)、検索された断片だけでは回答できません。大きすぎると意味が薄まり検索精度が落ちます。500 文字から始め、検索結果を見て調整してください — RAG 調整で最も時間をかける価値のあるパラメータです。
発展テクニック
基本パイプラインが動いた後、検索品質を上げる手法:
1. 再ランキング。 ベクトル DB が返した候補断片を cross-encoder 等で再採点し並べ替えます。ベクトル類似度は高いが実際の関連性が低いケースを拾えます。
2. クエリ展開。 検索前に LLM がユーザーの質問を複数のバリエーションに書き換え、すべてで検索します。質問と文書の語彙が食い違う場合の再現率が上がります。
3. メタデータフィルタ。 出典・日付・文書種別を各断片に持たせ、ベクトル検索前に絞り込みます。
4. ハイブリッド検索。 ベクトル類似検索とキーワード(BM25)検索を併用し、重み付きで統合します。
いずれも LLM の変更を必要とせず、プロンプトに渡す前の検索層を改善します。
本番配備の注意点
永続化:Chroma のデフォルトはオンメモリで、再起動で消えます。試作を出たら永続バックエンドへ。
差分更新:文書が変わったら、変更のあった断片だけ再エンコードします。出典文書との対応を追跡できる設計にしてください。
評価:質問 + 期待する出典断片 + 期待回答から成る小さな評価セットを作り、パイプライン変更のたびに実行します。評価がないと検索品質の劣化が静かに進行します。
コスト管理:クラウドモードでは検索コンテキストと生成の両方がトークンを消費します。コンテキストサイズを監視し、取得断片を絞ってコストを制御してください。
FAQ
RAG と文書をそのままプロンプトに入れる違いは?
Embedding モデルは何を使うべき?
検索断片が的外れなときは?
LangChain と LlamaIndex どちら?
価格はどこで見られますか?
関連記事
- LangChain と EXAIV — LangChain 完全連携
- ローカルデプロイ完全プレイブック — 配備フロー
- Qwen モデル選びガイド — モデル選定
- 国産オープンウェイト vs 米国フラッグシップ — ローカルとクラウドの全体像
- 料金 — クラウドのリアルタイム価格