重要なポイント
- デフォルト設定は5,000~8,000チャンクで限界 – ベクトルインデックスがRAMを超過し、コサイン単独検索が字句的に類似だが意味的に誤ったチャンクを返します。
- 機能より規模で選択 : AnythingLLM調整版(100~1,000ドキュメント)、LlamaIndexローカル(1,000~5,000)、Ollama+ChromaDBカスタム(5,000~10,000)、Ollama+Qdrant(10,000+)。
- 影響度順の3つの改善 : ハイブリッド検索(BM25+ベクトル)、小規模cross-encoderでのリランキング(Top-50候補)、メタデータ事前フィルタリング。10k+ でも階層検索が有効。
- ストレージ予算 : チャンク設定とembedding次元で10~30 MB/100ページ。50,000ページコーパスにはベクトル用だけで5~15 GB必要。
- インデックス時間 : ドキュメント数に線形。nomic-embed-text-v1.5 で5,000 PDFごと30~90分。Apple Silicon上の方がx86 CPUのみより高速。
- 10k+ ドキュメント向けハードウェア最小構成 : 32 GB RAM、NVMe SSD、8GB+ VRAM 搭載GPU もしくは 32GB+ 統合メモリのApple Silicon。
- Embeddingモデル変更は全インデックス再作成強制 。10,000ドキュメント前にembedderを選択・確定してください。間違った選択は数時間の手戻りコスト。
1,000ドキュメント超でデフォルトRAGが失敗する理由
1,000~10,000ドキュメント間で2つの失敗が重なります:インデックスがRAMを超過し、コサイン単独検索が字句的に類似だが意味的に誤ったチャンクを返すからです。 20 PDFで動いたおもちゃのデモが個人研究ライブラリで使い物にならなくなる理由は、コードが悪いからではなく、デフォルト設定に組み込まれた前提が通用しなくなるからです。
- Index-out-of-RAM : LanceDB、ChromaDB、FAISSはすべてメモリ常駐で起動します。利用可能RAM(16 GB ノートPC では通常5~8 GB)を超過すると、ディスク読み込みに切り替わり、p95クエリレイテンシは~300ms から1~3秒に跳ね上がります。
- コサイン単独では稀な用語に対応不可 : 密集embeddings は珍しい固有名詞、医薬品名、法定番号、コード識別子の重みを低くします。「Section 230(c)(1)」への問い合わせは「Section 9」のチャンクを検索します。embedding は数値の特異性を区別できないからです。BM25 なら捕捉します。
- 大規模ではTop-K=4は狭すぎる : 1,000チャンクではTop-4で充分な再現率があります。50,000チャンクでは本当に最良のチャンクがランク12~30 にあり、Top-4ウインドウ外です。検索が機能しているように見えても(もっともらしい回答)、実は誤った箇所に基づいています。
- メタデータフィルタリング無し は索引を無駄に : 「Smith は X について何と言ったか」を10,000ドキュメント コーパス上で問う場合、システムは索引内すべてのチャンクを検索すべきではなく、まず「Smith のドキュメント」に事前フィルタリング。素朴なRAGにはこの概念がありません。
- デフォルトチャンクサイズ512/0は長コンテキストを断片化 : PDF 段落と法律条項は512トークンに収まりません。デフォルト0重複は境界を超えて意味を喪失します。1,000/200調整は中規模コーパスで機能 。5,000ドキュメント超では階層的チャンキングが必要。
- Embedding更新時のドリフト : 元のインデックス3ヶ月後に1,000 新PDF追加時、sentence-transformer モデルバージョンが変わっているかもしれません。2つのモデル版からembeddings を混在させると検索が静かに劣化。すべてのアーキテクチャでembedder 変更時に完全再インデックスが強制されます。
📌Note: 「スケーリングの壁」は1つの数値ではありません。コーパス、ハードウェア、検索設定が充分に相互作用悪化し、回答が視認可能に劣化する地点です。16 GB ノートPC 上では~5,000チャンク。32 GB ワークステーション NVMe 搭載では15,000~20,000。本記事の修正(ハイブリッド検索、リランキング、メタデータフィルタリング)は壁を完全に平坦化します。
アーキテクチャ選択フロー:規模で選ぶ
ドキュメント数を処理できる最も単純なアーキテクチャを選んでください。ハイブリッド検索やリランキング、階層インデックスの追加は後付け可能です。ベクトルストア全体の交換はできません。 インストーラを開く前にこのフローを使用してください。
📍 一文で説明
1,000 PDFまでのチャット向けで最も高速な設定はAnythingLLM Desktop、チャンクサイズ1,000/重複200、embedder はnomic-embed-text-v1.5。コード不要で、マシン内完全実行。
💬 簡潔に説明
ドキュメント数で選択: 1,000未満 → AnythingLLM(コード不要、ドラッグドロップ); 1,000~5,000 → LlamaIndex ローカル(150行Python); 5,000~10,000 → Ollama+ChromaDB カスタム(300~400行、ハイブリッド検索+リランキング追加); 10,000+ → Ollama+Qdrant(Docker、メタデータフィルタリング、プロダクショングレード)。正しい選択はコーパスを処理できる最も単純なもの。アーキテクチャの過度設計は保守コストを増やしますが、小規模コレクションの回答品質は向上しません。
- 1,000ドキュメント未満(~5,000チャンク未満) : AnythingLLM Desktop、チャンクサイズ1,000/重複200、embedder はnomic-embed-text-v1.5。カスタムコード不要。セットアップは30分ステップバイステップガイド参照。
- 1,000~5,000ドキュメント(5k~25kチャンク) : LlamaIndex ローカルモード、階層インデックス(DocumentSummaryIndex + VectorStoreIndex)、Ollama(LLMプロバイダ)、nomic-embed-text-v1.5(embedder)、LanceDB または ChromaDB(ベクトルストア)。150行Python、長時間実行プロセス。
- 5,000~10,000ドキュメント(25k~50kチャンク) : Ollama、ChromaDB、BM25 ハイブリッド検索(Whoosh または Tantivy経由)、BGE-reranker-v2-m3(Top-50候補リランキング)のカスタムスタック。300~400行Python。この規模ではリランカーは必須。
- 10,000+ ドキュメント(50k+ チャンク) : シングルノードモードの Ollama+Qdrant、ペイロードベースメタデータフィルタリング、Qdrant 1.10+ ネイティブハイブリッド検索、BGE-reranker-v2-m3、ドキュメントIDキーの階層サマリインデックス。シングルユーザーのプロダクショングレード。
- マルチユーザー(すべての規模) : 上記いずれかの前に Open WebUI、もしくは同じ Qdrant+Ollama バックエンドの小規模 FastAPI ラッパー。マルチユーザーは操作面(認証、分離、レート制限)を変えますが、検索アーキテクチャは変わりません。
💡Tip: 迷ったら現在のコーパス規模より1段階上を選択。今800 PDFで月200個追加予定なら LlamaIndex 段階で開始。後で AnythingLLM から再アーキテクチャ化はいまから1段階過度に設計するより苦痛。
アーキテクチャ比較表
4つのアーキテクチャを100、1,000、10,000ドキュメント時で同じコーパス上でテスト。 テスト : 平均12ページの研究PDF(10kドキュメント時で~120kページ)。ハードウェア: Windows 11 上の NVIDIA RTX 4070(12 GB VRAM、32 GB RAM)、M5 MacBook Pro(32 GB 統合)でクロスチェック。LLM: Ollama 経由 Llama 3.3 8B Q4_K_M。Embedder: nomic-embed-text-v1.5。すべて値はウォームアップ後3回実行の中央値。
| アーキテクチャ | セットアップ複雑度 | 最大テスト済みドキュメント数 | 1kドキュメント時クエリp50 | 10kドキュメント時クエリp50 | 最適用途 |
|---|---|---|---|---|---|
| AnythingLLM(デフォルト) | ドラッグ&ドロップ、コード不要 | 検索品質低下前~2,000ドキュメント | ~450 ms | 実用的でない(再現率50%未満) | デモおよび小規模コーパス; 500 PDF超で非推奨 |
| AnythingLLM(調整版) | コード不要; 設定のみ(1000/200 + nomic-embed-text) | ~3,000ドキュメント快適 | ~310 ms | ~1.4s、再現率~70% | 100~1,000ドキュメント、カスタムコード予算ゼロ |
| LlamaIndex ローカル | 150行Python、長時間プロセス | ~8,000ドキュメント | ~280 ms | 階層インデックス使用時~700 ms | 1,000~5,000ドキュメント、構造化検索パイプライン |
| Ollama+ChromaDB カスタム | 300~400行Python、BM25+リランカー統合 | ~12,000ドキュメント | ~340 ms | ハイブリッド+リランク使用時~520 ms | 5,000~10,000ドキュメント、ハイブリッド検索必須 |
| Ollama+Qdrant | 500行Python、Docker、ペイロードスキーマ | 50,000+ ドキュメント | ~310 ms | ネイティブハイブリッド+フィルタリング使用時~410 ms | 10,000+ ドキュメント、メタデータ重視フィルタリング |
オプション1:AnythingLLM調整版(100~1,000ドキュメント)
正しく調整すれば1,000ドキュメントの個人コーパスを扱える最も低摩擦のオプション。 AnythingLLM Desktop は LanceDB 内蔵、PDF/DOCX/MD をネイティブ解析、LLMプロバイダとして Ollama と通信。デフォルト設定は500ドキュメント超で破綻。下記調整で2,000~3,000まで可能。
- LLM : Ollama 経由 Llama 3.3 8B Q4_K_M(推論時5 GB RAM)。24 GB+ システムでは Qwen 2.5 14B Q4 が大幅に合成を改善。
- Embedder : AnythingLLM Native デフォルトから nomic-embed-text-v1.5(Ollama 経由)に切り替え。デフォルト embedder は「AnythingLLM はスケールしない」報告の最大理由。
- チャンキング : ワークスペースごとに Vector Database 設定で1,000トークン、200トークン重複。デフォルト512/0は数十ドキュメント超すべてで誤り。
- Top-K : デフォルト4から6~8に引き上げ。1,000ドキュメント時、本当に最良のチャンクはランク5~7にあり、LLM は弱いチャンク無視が欠落創作より得意。
- ワークスペース分割 : ドキュメント種別ごと(論文、契約、ノート)にワークスペース作成。各ワークスペースは個別インデックス LanceDB。クロスワークスペースクエリ未サポート、が個別再現率は1つの大きなプールより高い。
⚠️Warning: AnythingLLM はハイブリッド検索ネイティブなし、ネイティブリランカーなし。~2,000ドキュメント超では「正しいドキュメント、誤ったチャンク」エラー : モデルは論文を引用するが誤った箇所を引用。このサインが LlamaIndex 段階へアップグレードの時期。
オプション2:LlamaIndexローカル(1,000~5,000ドキュメント)
完全ローカルモードの LlamaIndex は 30分 Python セットアップと引き換えに階層検索、クエリルーティング、はるかに優れたスケーリング曲線を獲得。 同じ Ollama バックエンド、同じ nomic-embed-text-v1.5 embedder、ですが検索層はワンショット Top-K ではなく構造化パイプライン用。
- スタック : Ollama + LlamaIndex + LanceDB(または ChromaDB)+ OllamaEmbedding アダプタ経由 nomic-embed-text-v1.5。ディスク永続化; CLI もしくは小規模 FastAPI ラッパー経由通信の長時間 Python プロセス実行。
- VectorStoreIndex 上 DocumentSummaryIndex : LlamaIndex はインデックス時にドキュメント単位サマリ作成、検索は最初 関連ドキュメント(サマリ検索)を選び、次にそれら内チャンク検索。最も廉価な階層検索パターン。
- クエリルーティング : RouterQueryEngine は fact-recall クエリをチャンクインデックスへ、合成クエリをサマリインデックスへ送信。~30行コード; 長ドキュメント コーパス上で回答品質倍化。
- Sentence-Window 検索 : 対象文 + N周辺文を検索するオプション第2インデックス。法律・学術コーパスで有用(回答1文だが意味は段落全体の文脈に依存)。
- 永続化 :
index.storage_context.persist(persist_dir=...)がすべて保存。5,000ドキュメントインデックスの再読み込みは NVMe SSD 上で10~30秒。
# 階層インデックス付きミニマル LlamaIndex ローカルRAG(~30行)
from llama_index.core import VectorStoreIndex, DocumentSummaryIndex, SimpleDirectoryReader
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.llms.ollama import Ollama
from llama_index.core import Settings
Settings.llm = Ollama(model="llama3.3:8b-instruct-q4_K_M", request_timeout=120)
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text:latest")
Settings.chunk_size = 1000
Settings.chunk_overlap = 200
docs = SimpleDirectoryReader("./pdfs").load_data()
# ルーティング用サマリインデックス + 検索用チャンクインデックス
summary_index = DocumentSummaryIndex.from_documents(docs)
chunk_index = VectorStoreIndex.from_documents(docs)
summary_index.storage_context.persist("./storage/summary")
chunk_index.storage_context.persist("./storage/chunks")
# クエリ時、問い合わせタイプでルート
response = chunk_index.as_query_engine(similarity_top_k=8).query(
"Smith et al. はどのサンプルサイズを使いましたか?"
)
print(response)オプション3:Ollama+ChromaDB カスタム(5,000~10,000ドキュメント)
5,000ドキュメントで LlamaIndex デフォルト値が疲労を示す : 純ベクトル検索は語彙的特定クエリを逃し、50,000チャンク cosinus 検索は「十分高速」予算を超。 ChromaDB、BM25 ハイブリッド検索、BGE リランカー付きカスタムスタックは32 GB ワークステーション上で10,000ドキュメント処理。
- スタック : Ollama + ChromaDB(サーバーモード)+ BM25 用 Whoosh/Tantivy + BGE-reranker-v2-m3(~570 MB、CPU 上 50~100候補/秒)。単一 Python プロセスまたは Ingest + Query worker に分割ホスト。
- 検索時ハイブリッド検索 : BM25 とベクトル検索並行実行、各 Top-25 取得、重複排除、merged Top-50 を cross-encoder リランク。最終 Top-6~8 を LLM へ。
- ChromaDB メタデータフィールド : インデックス時各チャンク上
source_filename、page_number、document_type、author、year設定。クエリ時フィルタ(where={"document_type": "contract"})で検索空間を5~10倍削減、品質損失ゼロ。 - バッチインデックス化 : ChromaDB は32~128チャンク batch embedding。RTX 4070 上では BGE-リランカーがボトルネック(CPU 50~100候補/秒; GPU 400+/秒)。
- 永続化 : ChromaDB は SQLite + Parquet ディレクトリに書き込み。ディスク上の50,000チャンクインデックスは~3~5 GB。バックアップはディレクトリコピー。
💡Tip: BGE-reranker-v2-m3 この規模で最高影響度の追加。なしは正しいドキュメント誤ったチャンクが~15~25%。ありは5%未満、LLM は清潔な基礎で作業。クエリレイテンシに加わる200~500ms を予算化 – すべて価値あり。
オプション4:Ollama+Qdrant(10,000+ ドキュメント)
10,000ドキュメント超で、シングルプロセス ChromaDB は応答性利点を失い始めます。シングルノード Docker モード Qdrant は50,000+ ドキュメント、ネイティブハイブリッド検索、ペイロードベースフィルタリング、Sub-秒クエリ HNSW インデックス処理。 同じ Ollama バックエンド; 差異はベクトルストア。
- スタック : Ollama + Qdrant(Docker、single-node)+ ネイティブ sparse ベクトル(Qdrant 1.10+ 組込 BM25 相当)+ BGE-reranker-v2-m3 + 小規模 Python オーケストレーション層。
- ネイティブハイブリッド : Qdrant は1コレクション内 dense + sparse ベクトルをサポート、クエリ時加重融合。個別 BM25 プロセス保守不要。
- HNSW チューニング : 50,000+ ベクトル時、インデックスビルドで
ef_construct200、m32 に引き上げ、クエリ時ef=128。デフォルトは機能するが~10%再現率とトレードオフ。 - メタデータフィルタリング用ペイロードスキーマ : Qdrant はペイロードをファーストクラス扱い。
author、document_type、year、tagsを keyword payload にインデックス化して Sub-ms 事前フィルタリング有効化。 - 階層検索 :
summaries(ドキュメント単位ベクトル)とchunks(通常)の2コレクション保持。クエリをサマリコレクション経由ルート、マッチドキュメント ID 内でチャンク検索。 - 永続化 : Qdrant は単一マウントボリュームに書き込み。100,000チャンクコレクションはペイロード size と HNSW 設定依存で~6~12 GB。
# dense + sparse ベクトルとメタデータフィルタリング付き Qdrant コレクション
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, SparseVectorParams, SparseIndexParams
)
client = QdrantClient(host="localhost", port=6333)
client.create_collection(
collection_name="docs",
vectors_config={
"dense": VectorParams(size=768, distance=Distance.COSINE), # nomic-embed-text-v1.5
},
sparse_vectors_config={
"bm25": SparseVectorParams(index=SparseIndexParams(on_disk=False)),
},
)
# クエリ : ハイブリッド検索 + ペイロードフィルタ、個別 BM25 プロセス不要
from qdrant_client.models import Filter, FieldCondition, MatchValue, Prefetch
results = client.query_points(
collection_name="docs",
query=dense_vec,
using="dense",
prefetch=[
Prefetch(query=sparse_vec, using="bm25", limit=25),
Prefetch(query=dense_vec, using="dense", limit=25),
],
query_filter=Filter(
must=[FieldCondition(key="document_type", match=MatchValue(value="contract"))]
),
limit=50, # リランク前
)ハイブリッド検索:BM25 + ベクトル両方が単独より優秀
純コサイン検索は稀な固有名詞、法定番号、特定識別子に基づくクエリを逃します。純BM25 は異なる表現のクエリを逃します。組み合わせは単独より優秀、1,000ドキュメント超で特に。 実装コスト : 追加の検索呼び出し + 融合ステップ。
- Dense 単独が失敗する理由 : embeddings は稀な tokens を軽視。「RFC 9110 section 7.4」や「MNDA-2024-0143」への問い合わせは汎用 IETF/contract チャンク近辺に埋め込まれます。BM25 は正確な識別子をキャッチ; 純コサイン検索は逃します。
- BM25 単独が失敗する理由 : 語彙マッチは言い換えを逃します。「どのように解約しますか?」は「解約手続き」タイトル chunk は dense 空間で match、BM25 では 0 score。
- Reciprocal Rank Fusion (RRF) 標準結合器 : いずれかの結果リストに出現する各チャンク、スコア
1/(60+rank_dense) + 1/(60+rank_bm25)。降順ソート。60 は平滑化定数; 実際は30~100範囲。 - 実践的レシピ : 各メソッド Top-25 検索、RRF 経由結合、Top-50 取得、リランカーへ送信、Top-6~8 をLLMへ。これが1,000ドキュメント超すべての規模での標準プロダクション パイプライン。
- ストレージコスト : BM25 インデックスは小さい(~50~150 MB per 10,000 ドキュメント)と同規模の dense インデックス(~500 MB~2 GB)比較。既存 dense ストアへの BM25 追加は廉価。
📌Note: Qdrant 1.10+ と Weaviate 両方ハイブリッドネイティブサポート。ChromaDB は Whoosh/Tantivy 装着必要。LanceDB は実験的ハイブリッド対応だが API は 2026年5月時点で変更中 – commitment前に現在ドキュメント確認。ネイティブハイブリッド、ベクトルストア選択の価値ある。
リランキング:Top-N 精緻化パス
リランカーは小規模 cross-encoder で (query, candidate) ペア合同ではなく独立スコア。ハイブリッド検索の Top-25~50 候補上実行して「正しいドキュメント、誤ったチャンク」エラー修正。 5,000~50,000 ドキュメント間で単一最大品質レバー。
- BGE-reranker-v2-m3 (~570 MB、多言語、Apache 2.0) 2026年5月デフォルト選択。CPU 最新 50~100候補/秒; GPU 400+ /秒 実行。Top-50 リランキング遅延コストは CPU~200~500ms、GPU ~80~150ms。
- Cross-encoder が検索で勝つ理由 : dense embeddings は query とドキュメント独立エンコード、モデルは決して共に見ません。Cross-encoder は `[CLS] query [SEP] candidate [SEP]` 合同読み、ペア直接スコア。Recall@5 典型的に 15~25 ポイント上昇。
- リランカー注入場所 : ハイブリッド検索後、LLM 前。ハイブリッド top-50 取得、Top-6~8 リランク、それら を LLM コンテキストとして送信。
- 別案 – Cohere Rerank API : より高品質、cloud 呼び出し要。完全ローカルスタック、BGE-reranker-v2-m3 実践的デフォルト。mxbai-rerank-base-v2 強い代替。
- 1,000ドキュメント未満リランカー省略は OK : 品質利得遅延コストを正当化しない。5,000ドキュメント超、省略は~15~25% 回答が誤ったチャンク上に基礎。
大規模コレクション向けメタデータフィルタリング
ストラクチャ メタデータ各チャンク上保存すると、ベクトル検索実行前にインデックスを絞れます。10,000ドキュメント コーパスでは、payload フィルタは典型的に検索空間 5~10倍削減、品質損失ゼロ。 インデックス時追加は廉価; 後付けは高い。
- インデックス時設定すべき universal payload フィールド :
source_filename、page_number、document_type(論文/契約/ノート/wiki)、author、year、language、プラス domain 固有タグ(例:case_number、project_id、client_id)。 - クエリ時事前フィルタ : 「2024年Q3ボード議事録は価格について何と言った?」→
document_type=board_minutes AND year=2024 AND quarter=3まず filter、次にベクトル検索 all 10,000 ではなく~12ドキュメント内。 - Vector store サポート : Qdrant ペイロード、Weaviate properties、ChromaDB メタデータ、LanceDB スキーマカラム すべてフィルタリングサポート。パフォーマンス変動 – Qdrant ペイロードインデックスフィールド sub-ms; ChromaDB メタデータ>100k チャンク時 50~150ms 追加可能。
- メタデータ自動抽出 : 法律コーパス、小規模 LLM パス index-time が各ドキュメント case 番号、日付、関係者名抽出可能。Llama 3.3 8B 上~30秒/ドキュメント; ingest ごと1回。
- ハイブリッド検索と結合 : payload フィルタ narrow universe → BM25 + dense 検索 filtered set 内 → rerank。Payload フィルタは任意大型 RAG システムで最廉価 5~10倍 speedup。
階層検索パターン
階層検索は2インデックス保持 – ドキュメント単位サマリ 1つ、チャンク 1つ – クエリを両方へルート。サマリ検索が正しいドキュメント見つけ; チャンク検索が正しいパッセージ見つけ。 合成時のノイズ削減; ほぼ fact recall 不要。
- ドキュメント単位サマリ : インデックス時、LLM に各ドキュメント 100~200 トークン サマリ書かせ。サマリを別
summariesコレクションに embed。Llama 3.3 8B で~30~90 秒/ドキュメント。 - 二段階検索 : (1) query embed、
summaries検索、top-5 ドキュメント取得; (2) 5ドキュメント内、ハイブリッド検索 top-8 チャンク; (3) 必要時リランク; (4) LLM 送信。 - 最も利益が大きい場合 : 合成と複数ドキュメント問い(「これら論文はどのように X を扱ってるか比較」)。Fact recall(「Smith はどの値報告?」)は chunk インデックス単独で OK – サマリ迂回は遅延追加、品質利得ゼロ。
- コスト トレードオフ : インデックスストレージ倍化(サマリ小さいが index 自体が複製インフラ)。非ルートクエリ遅延倍化。利得は10,000+ ドキュメントでノイズ削減。
- LlamaIndex が組み込み :
DocumentSummaryIndexプラスRouterQueryEngineは 30行実装。ChromaDB/Qdrant 個別 Python は~80~120行。
100、1k、10k ドキュメント時の実測ベンチマーク
4アーキテクチャ同じコーパス上テスト。Test rig : NVIDIA RTX 4070(12 GB VRAM、32 GB RAM)、Windows 11+WSL2、NVMe SSD。M5 MacBook Pro(32 GB unified)で cross-check。中央値 3 run ウォームアップ後。 インデックス時間、on-disk ストレージ、query p50/p95 レイテンシ scales 上。
| スタック | メトリック | @ 100ドキュメント | @ 1,000ドキュメント | @ 10,000ドキュメント |
|---|---|---|---|---|
| AnythingLLM 調整版 | インデックス時間 | ~1分 | ~12分 | 3,000超テストされず |
| AnythingLLM 調整版 | On-disk ベクトル | ~30 MB | ~280 MB | N/A |
| AnythingLLM 調整版 | クエリ p50/p95 | ~180/420 ms | ~310/880 ms | N/A(再現率低すぎ) |
| LlamaIndex ローカル | インデックス時間 | ~3分(サマリ含む) | ~25分 | ~3.5時間 |
| LlamaIndex ローカル | On-disk ストレージ | ~45 MB | ~340 MB | ~3.6 GB |
| LlamaIndex ローカル | クエリ p50/p95 | ~210/480 ms | ~280/720 ms | ~700/1,400 ms |
| Ollama+ChromaDB カスタム | インデックス時間 | ~2分 | ~18分 | ~2.8時間 |
| Ollama+ChromaDB カスタム | On-disk ストレージ | ~40 MB | ~310 MB | ~3.2 GB |
| Ollama+ChromaDB カスタム | クエリ p50/p95 | ~240/540 ms(リランク含む) | ~340/760 ms | ~520/1,100 ms |
| Ollama+Qdrant | インデックス時間 | ~2分 | ~17分 | ~2.6時間 |
| Ollama+Qdrant | On-disk ストレージ | ~55 MB | ~410 MB | ~4.4 GB |
| Ollama+Qdrant | クエリ p50/p95 | ~220/480 ms | ~310/690 ms | ~410/920 ms |
ストレージサイジングとハードウェア要件
ストレージはドキュメント線形スケール、RAM は sub-linear。ほぼ検索エンジンが memory-map ではなく full load インデックス。下記値は nomic-embed-text-v1.5(768-dim)と1,000トークン/200重複 chunk 想定。 ディスク 3~5倍コーパスサイズ計画。
- 1,000 PDF(~12ページ)の raw テキスト : ~50~150 MB 抽出テキスト。密度に応じてかなり変動。
- 1,000ドキュメント時ベクトル : HNSW インデックスオーバーヘッド含め~300~400 MB disk。HNSW インデックス skip、brute-force 利用は~120~180 MB(5,000ドキュメント未満OK)。
- 10,000ドキュメント時ベクトル : ~3~5 GB disk。HNSW 構築 10~30分 modern CPU 上。
- 50,000ドキュメント時ベクトル : ~15~25 GB disk。Index build time がボトルネック – one-time 2~4時間 CPU 計画。
- クエリ中 RAM : dense 検索は index 30~50% working メモリで低レイテンシクエリ。5 GB index は HNSW 付き 8~16 GB RAM で快適query; brute-force は full index resident 要。
- インデックス中 RAM : embedding モデルサイズ 2~3倍(~600 MB nomic-embed-text)プラス per-batch テキスト spikes。8 GB 空き RAM で indexing パス十分。
- GPU vs CPU : embedding throughput は discrete GPU または Apple Silicon 上で 4~8倍高速。10,000+ one-shot indexing で GPU は 1~3時間節約。クエリ時 embedding(query 1つ)では CPU OK。
- ディスクタイプが重要 : NVMe SSD は 5,000+ ドキュメント実務的 floor。SATA SSD は冷クエリレイテンシに 30~100% 追加; spinning disk は~2,000ドキュメント超で使用不可。
インクリメンタルインデックス化と重複除去
10,000ドキュメント索引に100新 PDF 追加は、10,000すべての再インデックス強制すべきではありません。 このガイドのすべてのアーキテクチャが incremental adds サポート; より難しい問題は近傍重複ドキュメント検出・除去で、silent double-count chunks、検索混乱。
- Ingest 時 Hash ベース exact dedup : raw ファイルバイト SHA-256。Hash 既に索引済みファイル skip。廉価、identical ファイル catch、near-dupe miss(OCR 異パス same scan、format conversion)。
- Content-hash dedup : whitespace 正規化後 extracted plain テキスト SHA-256。異 file format 同コンテンツ catch。ingest ごと~5ms 追加。
- MinHash near-dupe 向け : legal/academic コーパス multiple draft same doc accumulate で MinHash signature(~128 bytes/doc)計算、既存 Jaccard 閾値 ~0.85 内 skip。
- Document ID は永遠 : 削除後 doc ID 再利用禁止。Vector store はしばしば orphaned ベクトル短期保持; ID 再利用は silent confusion 原因。UUID または hash ベース ID 利用。
- Embedder 変更時 re-embedding : すべてのアーキテクチャで embedder 変更時完全再インデックス force。2 model 版 embeddings mix は silent 検索劣化。10,000ドキュメント索引前に embedder 選択・commit 少なくも1年。
- 削除 : ChromaDB と Qdrant は ID point 削除サポート。LanceDB は compaction pass 要 disk reclaim – 月あたり corpus >~5% 削除で週単位計画。
⚠️Warning: 長期実行 personal RAG システムの最も一般的 silent 失敗は duplicate ingest : 同一論文 2 format で追加、または同一 wiki ページ 2回 export。症状「モデル同じチャンク 3回ずっと引用」と「syntheses がおかしく repetitive」。1,000ドキュメント超前に content-hash dedup 追加。
大規模RAG品質監視
10,000ドキュメント RAG システムはドキュメント追加、モデル swap、edge case 発見で長期にわたり silent 劣化。Fix は小さい評価harness – 30~50 hand-curated query/answer pair – 重要変更ごとに再実行。 5分評価は週の confused chasing 防止。
- 小規模 golden set 構築 : 30~50 問い、正解を知ってる、実使用から抽出。Fact recall(5~10)、syntheses(5~10)、cross-document(5~10)、edge case(5~10)、known-miss query(5~10、答え corpus 外)含む。
- 問い当たり3メトリック追跡 : retrieval recall(正しいチャンク top-K に現れた?)、generation faithfulness(回答は chunk マッチ?)、refusal rate(system 「corpus 外」正しく言った?)。
- 重要変更ごと再実行 : 新 ingest batch、embedder swap、chunk-size change、prompt tweak。結果を前回と diff; retrieval recall または answer 変わった問い flag。
- Trulens または RAGAS for automated eval frameworks。両方 local 実行、LlamaIndex integrate。30~50 問い manual scoring も fine、しばしば正確。
- Latency budget : p50 と p95 query latency を時系列 track。p95 で 50% jump は典型的に index RAM 超過 – 次アーキテクチャ層 upgrade 早期シグナル。
よくある質問
デフォルトRAG設定はドキュメント何個で限界?
16 GB ノートPC デフォルト設定(512トークン chunk、0 overlap、デフォルト embedder、top-K 4)では検索品質 1,000~2,000ドキュメント で視認可能 劣化、5,000超は使用不可。2つの失敗モード「正しい doc 誤った chunk」(top-K 大規模では狭い)と silent recall 低下(index RAM 超過)。AnythingLLM 調整版(1,000/200 chunk + nomic-embed-text-v1.5)で ~3,000ドキュメント へ cliff push。超えるとハイブリッド検索 + reranker 要。
ハイブリッド検索(BM25+ベクトル)使うべき?
1,000ドキュメント超では yes。純 dense 検索は稀 固有名詞、law 番号、特定識別子ベース問い逃す。純 BM25 は言い換え問い逃す。Top-25 list RRF fusion が標準 combiner。Qdrant/Weaviate はネイティブハイブリッド; ChromaDB は Whoosh/Tantivy 要。追加検索コスト ~50~100ms; 品質利得有意。
1,000 PDF embedding 後いくらストレージ要?
nomic-embed-text-v1.5(768 dimension)で 1,000トークン chunk/200 overlap で dense vector index 約 250~400 MB disk。ハイブリッド検索用 BM25 index +50~150 MB、hierarchy summaries +50~100 MB。Original PDF 本体はほぼ vector DB に保存されない – 抽出テキスト + embedding のみ。10,000 PDF corpus は ~3~5 GB vector + whatever PDF 占有。
リランキングは大規模で役立つ?
はい – 5,000~50,000ドキュメント で最大 impact 単一追加。なしは「正しい doc 誤った chunk」エラー ~15~25% 時間。BGE-reranker-v2-m3 + ハイブリッド top-50 で 5%未満に低下。200~500ms CPU / 80~150ms GPU 遅延。1,000ドキュメント未満は品質利得が遅延正当化しない; 5,000超では skip は 15~25% recall テーブル上に残す。
重複・近傍重複 doc どう処理?
三層 dedup : raw file bytes SHA-256(identical ファイル catch)、extract plain text SHA-256 whitespace 後(異 file format same 内容)、MinHash +Jaccard ~0.85(近傍 dupe like multiple draft / OCR variant)。embedding 前 ingest ですべて実行。skip 症状「synthese が bizarrely repetitive」– same chunk 3回 stored で LLM 見る 3回。
すべて再索引なしドキュメント追加可能?
はい、このガイド全アーキテクチャ incremental add サポート。ChromaDB/Qdrant は simple insert call; LanceDB は append-only file; LlamaIndex は wrap。例外は embedder 変更 – 完全再索引 force(2 model 版 mix silent 検索劣化)。5,000ドキュメント超前に embedder 選択・最低1年 commit。
大規模コレクション向けメタデータフィルタリング使う?
はい – metadata フィルタリングは大規模での最廉価 5~10倍 speedup。source_filename、page_number、document_type、author、year、domain タグ populate インデックス時。クエリ時事前フィルタ(payload)で検索空間数百 chunk に切る、品質損失ゼロ。Qdrant/Weaviate は first-class payload; ChromaDB/LanceDB もサポートだが >100k chunk で若干遅い。
大規模 RAG 品質監視する?
golden set 構築 – 30~50 hand-curate query/answer pair 正解知ってる、real usage 由来 – 重要変更(新 ingest、embedder swap、chunk change、prompt tweak)ごと再実行。Retrieval recall(正しいチャンク top-K?)、generation faithfulness(answer match chunk?)、refusal rate(system 「not corpus」言った?)追跡。Trulens/RAGAS は automate; manual 30 question 評価も fine、しばしば正確。
10,000ドキュメント向けハードウェア何必要?
floor : 32 GB system RAM、50+ GB 空き NVMe SSD、8GB+ VRAM discrete GPU もしくは 32GB+ unified Apple Silicon。GPU/Apple Silicon は one-shot indexing 速度(10,000 doc pass で 1~3時間節約); query inferencing は indexing後 CPU でOK。SATA SSD acceptable だが 30~100% cold query latency 追加; spinning disk は ~2,000ドキュメント超で使用不可。RAM は constraint 最初に bite – 5 GB index は HNSW で 16 GB RAM で快適.
複数ユーザー RAG ローカルホスト可能?
はい – Open WebUI を上記アーキテクチャの前に置くか、同一 Qdrant+Ollama backend の小さい FastAPI wrapper。Multi-user は operationally(auth、isolation、rate limiting、optional per-user workspace)変わるが、retrieval アーキテクチャは同じ。Open WebUI は auth、OAuth、role-base document access out-of-box handle。5+ concurrent user 10,000-doc corpus で embedder GPU indexing、query embedding CPU または GPU(QPS)計画 – single CPU embedder は ~3~5 QPS comfortable handle。