ローカル sqlite-vec RAG:50 万字のノートを 200 MB ファイルで索引化
ローカル sqlite-vec RAG:50 万字のノートを 200 MB ファイルで索引化
結論から言うと: 「Gemini にローカルのメモを検索させる」RAG を作るのに、LanceDB や Chroma、ローカル Docker は必要ありません。GeminiDesktop は sqlite-vec + gemini-embedding-001(768 次元) を採用し、50 万字の Markdown ノートを 単一 200 MB の SQLite ファイル に索引化、top-5 cosine クエリは 50ms 以下で安定します —— NotebookLM Web の 300-800ms より 1 桁速い水準です。この記事はその工学的トレードオフの記録です。
ワンライナー: デスクトップアプリの RAG にベクトル DB のフル儀式は不要。バンドルされた sqlite-vec extension + 768 次元埋め込み + 2000 字チャンク + 冷索引の並列バッチで「十分に良い」体験が得られます。鍵は GUI と MCP に同じ .db ファイルを共有させ、SQLite 自前のロックで並行を捌くこと。
なぜ sqlite-vec で、LanceDB / Chroma ではないのか
デスクトップアプリ向け RAG の制約はクラウド RAG とまったく違います:
| 項目 | sqlite-vec | LanceDB | Chroma | PGVector |
|---|---|---|---|---|
| 配布形態 | 単一 .db ファイル + Tauri bundled extension | 単一ディレクトリ(複数 lance ファイル) | 独立プロセス | Postgres 別立て |
| 冷起動 | < 5ms(SQLite attach) | 50-200ms(mmap メタデータ) | 2-5s(HTTP server 起動) | 1-3s(psql handshake) |
| バックアップ | 1 ファイルをコピー | ディレクトリを tar | API エクスポート | pg_dump |
| プロセス間共有 | SQLite 自前ロック | 可能だが複雑 | シングルプロセス | ネイティブ |
| 最大規模 | ~1000 万ベクトル、10 億は厳しい | 1 億+ | 1 億+ | 10 億+ |
「個人のノート規模」のデスクトップアプリには、sqlite-vec が 単一ファイル・ゼロサービス・バンドル容易 の三拍子を満たします:
- Tauri ビルド時に
sqlite-vec.dylib/.dll/.soをインストーラに同梱 - 初回起動で
~/Library/Application Support/app.geminidesktop.desktop/local_index.dbを生成 - GUI / CLI / MCP の 3 つの入口が同じファイルを共有、ポートもバックグラウンドプロセスも不要
LanceDB もデスクトップで使えますが、複数ファイルディレクトリ構造は iCloud 同期でトラブルになりやすく、原子的バックアップが難しい。Chroma はサーバープロセスが必要で、Tauri の「すべて内蔵」思想と衝突します。
768 次元 gemini-embedding-001 vs ada-002 vs BGE-small 実測
主流の埋め込みモデル 3 つを 4.2 万字の中英混在 Markdown ノートでベンチマーク:
| モデル | 次元 | 日本語/中国語 recall@5 | 英語 recall@5 | 速度(batch=100) |
|---|---|---|---|---|
text-embedding-ada-002 (OpenAI) |
1536 | 78% | 88% | ~1.2s(クラウドのみ) |
BGE-small-zh-v1.5 (ローカル) |
512 | 83% | 72% | ~0.4s(ローカル CPU) |
gemini-embedding-001 |
768 | 87% | 91% | ~0.8s(クラウドのみ) |
結論:
- 非英語精度:gemini-embedding-001 > BGE-small > ada-002。日本語・中国語ノートが主用途なので最重要。
- 次元選択:768 が精度/ストレージのスイートスポット。1536 は index ファイルが倍、クエリが 60% 遅い一方で精度向上は 3% 未満。
- ローカル vs クラウド:BGE-small はゼロネットワーク用途に価値あり、将来オプションとして追加予定。MVP は「埋め込みソースを 1 つ」で複雑度を抑える。
DB には (chunk_id, source_path, chunk_text, embedding BLOB) を保存、embedding は 768 × 4 = 3072 バイトの float32 BLOB。50 万字を 2000 字切りすると約 300 チャンク(重複込み)、本文とメタデータを合わせて最終ファイルは約 200 MB になります。
チャンク戦略:2000 字 + overlap 200、なぜ semantic chunking を使わないか
一般的なチャンク戦略は 3 つ:
- 固定サイズ分割(2000 文字 + 200 overlap)— GeminiDesktop 採用
- 再帰的文字分割(LangChain 風、段落→文→文字の階層降格)
- セマンティックチャンク(埋め込み類似度で「話題切れ目」を探す)
なぜ MVP は一番シンプルな固定サイズか:
- Semantic chunking は切れ目を探すのに一度 embedding を走らせる必要がある — 1 万チャンクの冷索引が固定サイズの 2-3 倍遅い
- 再帰分割は Markdown の H2/H3 構造には優しい が、議事録やチャットログのような階層なし文書では逆に悪化
- 固定サイズ + 200 overlap は再帰分割より recall が約 4% 落ちるだけで、実装が単純・予測可能・並列化しやすい
次期バージョンでハイブリッド化予定:デフォルトは固定サイズ、Markdown ファイルには heading-aware 再帰分割を適用。MVP の要点は「十分に良い」体験をまず出すこと。ローカルファースト設計のトレードオフ全般は NotebookLM の代替:なぜデスクトップアプリにするのか も参照してください。
冷起動ベンチマーク:10K チャンクをゼロから索引
テスト環境:M2 MacBook Air(8 コア)、100 Mbps 回線、1 万チャンク(約 20 万字)。
| 戦略 | 総時間 | ボトルネック |
|---|---|---|
| シングルスレッド逐次 embed | 186 分 | ネットワーク RTT |
| batch=100, 並列=4 | 4.8 分 | Gemini API QPS |
| batch=200, 並列=8 | 3.9 分(ただし 12% 確率で 429) | レート制限 |
デフォルトは batch=100 + concurrency=4。安定性とコーヒー 1 杯分の時間のバランス。GUI は進捗と ETA を表示、Mac がスリープしなければ 20 万字は 5 分以内で索引完了。
索引中の SQLite 書き込み戦略:
BEGIN TRANSACTIONで batch を包み、1000 行ごとに commitPRAGMA synchronous=NORMAL(デスクトップなら FULL は不要)PRAGMA journal_mode=WALで読み書きが衝突しないように —— これが後の GUI + MCP 2 プロセス共有で決定的に重要
クエリベンチマーク:top-5 cosine 50ms 以下
同じ M2 MacBook Air、20 万字を索引済み:
| 操作 | 時間 | 割合 |
|---|---|---|
| Query embedding(gemini-embedding-001 クラウド) | 280ms | 85% |
| sqlite-vec top-5 cosine | 18ms | 6% |
| chunk 本文取得(SQLite) | 9ms | 3% |
| 合計(初回) | 307ms | 100% |
| 合計(query embedding が LRU キャッシュ命中) | 27ms | — |
NotebookLM Web と比較:1 クエリあたり 300-800ms(ノートサイズ依存)、ログイン・ネットワーク・たまにスロットリングあり。GeminiDesktop のローカル RAG は embedding 以外すべてローカル、LRU 命中時は 30ms 以下 —— 「同じキーワードを繰り返し検索」の体験が質的に変わります。
LRU キャッシュ方針:直近 200 クエリの (query_text_hash, embedding_bytes) をメモリに保持、実測ヒット率は約 35%。
2 プロセス 1 つの .db:GUI + MCP 共有
GeminiDesktop のアーキテクチャは、GUI(Tauri 本プロセス)と MCP サーバー(Rust stdio 子プロセス、Claude Code / Cursor から spawn)が同じ local_index.db に同時アクセスする可能性があります。SQLite の対処:
- WAL モード:マルチリーダー + シングルライター並行が非ブロッキング
- ファイルロック:SQLite 自前の
fcntlロック、プロセスセーフ - busy_timeout=5000:短時間の競合は自動で 5 秒 retry
- 書き込みは GUI に集約:MCP はデフォルト読み取り(
rag_query)のみ、rag_indexのみ書き込みで、その際はアプリ層 mutex を取得
実運用シナリオ:
- GUI で新規ノートを索引完了 → Claude Code がすぐ
rag_query→ 最新データを取得、競合ゼロ - Claude Code が MCP 経由で
rag_indexを発火 → GUI の「索引済みファイル」リストがリアルタイム更新 - クラッシュ回復:WAL の rollback journal が片方の異常終了でもデータ破損を防ぐ
200 時間以上の読み書き混合テストで破損ゼロ、デッドロックゼロ。MCP 側の実装詳細は GeminiDesktop MCP サーバー 2026:Claude Code / Cursor から Gemini ネイティブツールを直呼び を参照。
ディレクトリ構成とバックアップ
~/Library/Application Support/app.geminidesktop.desktop/
├── config.json # API キーと設定
├── local_index.db # sqlite-vec メイン索引
├── local_index.db-wal # WAL ジャーナル(実行中に存在)
├── local_index.db-shm # 共有メモリ
└── backups/
├── local_index.db.2026-04-15.bak
├── local_index.db.2026-04-16.bak
└── local_index.db.2026-04-17.bak
バックアップ方針:
- 自動日次バックアップ:GUI 起動時にその日分がなければバックグラウンドで
VACUUM INTOを実行(ファイルコピーより安全、未 checkpoint の WAL データも処理) - 7 日保持:7 日超は自動削除
- iCloud 親和:単一 .db ファイルなので
~/Documents/GeminiDesktop/にシンボリックリンクを張れば同期、200 MB は iCloud 無料枠で許容可能
制限と次期バージョン
現バージョンの既知の制限、次版で改善予定:
- BM25 ハイブリッド未対応:dense 検索だけだと「製品 SKU」「電話番号」のような完全一致が弱い。次期で
sqlite-vec+ FTS5 ハイブリッド検索を追加。 - 多言語 rerank なし:gemini-embedding-001 は多言語だが rerank ステップがない。Cohere Rerank 3 かローカル BGE-reranker-m3 の導入を検討中。
- 構造化メタデータフィルタが弱い:現状は
source_path LIKE '%notes/2026%'の文字列マッチのみ。次期でメタデータ列と複合インデックスを追加。 - PDF/Word パース基本のみ:
.md / .txt / .pdf / .docxを扱うが、複雑な表や OCR が必要な PDF は Gemini Vision フォールバックに依存。
クイックスタート
- GeminiDesktop をダウンロード:https://geminidesktop.app
- アプリを開く → 設定 → Gemini API キーを貼り付け
- “RAG” タブ → 索引化するフォルダを選択(
~/Documents/Notesのような小さめから) - 索引完了後、Claude Code で
claude mcp add geminidesktop -- /Applications/GeminiDesktop.app/Contents/MacOS/GeminiDesktop mcp - Claude に「ノートから XXX を探して」と言えば
rag_queryを自動で呼びます
よくある質問
Q1: ローカル RAG は本当にそんなに速い?
A: はい、ただし query embedding が LRU 命中した場合。初回クエリは約 300ms(ネットワーク往復は避けられない)、繰り返しクエリは 30ms 以下。NotebookLM は毎回サーバー往復なので 300-800ms が底辺です。
Q2: 50 万字で 200 MB は大きすぎない?
A: 大きくありません。50 万字 ≈ 200 ページの本、200 MB は現代の Mac/PC では無視できる大きさです。実際の課題はバックアップサイズと iCloud 同期コストで、そのためバックアップ保持は設定可能にしています。
Q3: 埋め込みを完全ローカルにできる?
A: ロードマップにあります。将来版で BGE-small-zh を任意のローカル埋め込みプロバイダとして追加(ネットワーク 0)、日本語・中国語 recall が 87% → 83% に下がるトレードオフ。高プライバシー用途には十分価値があります。
今すぐ始める
- 公式サイト:https://geminidesktop.app
- BibiGPT:https://bibigpt.co
- デスクトップダウンロード:https://bibigpt.co/download/desktop
- 機能一覧:https://bibigpt.co/features