この記事は、実際に使って確かめた記録ではありません。この記事は公式の文書や論文を読んでまとめたものです。
3行でいうと
- RAGは「文書を小さく切る、数値のベクトルにする、似たものを探す、見つけた断片を質問と一緒にAIに渡す」の流れです。
- 日本語の文書なら、埋め込みモデルは日本語を扱えるものにします。Chromaの既定のモデルは英語向けです。
- 保存先は、Chroma、SQLiteの拡張(sqlite-vec)、Postgresの拡張(pgvector)が候補です。
- 登録時と検索時は、同じ埋め込みモデルを使います。Ollamaの文書もそう書いています。
先に結論
見立てです。個人や小さなチームで、文書が数千〜数万の断片までなら、「Ollama(埋め込み)+ Chroma(保存)」が、部品の少なさで手を付けやすいと思います。すでにPostgresを使っているなら pgvector、アプリがSQLiteで完結しているなら sqlite-vec が自然です。どれも公式の文書で使い方が確認できました。
数字に頼る比較は避けました。検索の精度や速さは、文書と質問で変わるためで、この記事では測っていません。
前提:言葉の整理
- RAG(検索拡張生成):AIに答えさせる前に、関連する文書の断片を探し出して、質問と一緒に渡す方法です。AIの記憶に頼らず、手元の資料を根拠にできます。
- 埋め込み(エンベディング):文章を、数百〜千数百個の数字の並び(ベクトル)に変えることです。意味が近い文章は、近い数字になるように作られます。Ollamaの文書は、ベクトルの長さはモデルで決まり、たいてい384〜1024次元だと書いています。
- ベクトルデータベース:ベクトルを保存して、「これに近いもの」を素早く探す入れ物です。
- チャンク:長い文書を切り分けた、小さな断片です。
- コサイン類似度:2つのベクトルが、同じ向きを向いている度合いです。Ollamaの文書は、たいていの意味検索で、これを使うよう勧めています。
全体の流れ
2つの段階があります。
登録(最初に1回、文書が増えたら追加) 1. 文書を、チャンクに切る。 2. 各チャンクを、埋め込みモデルでベクトルにする。 3. ベクトルと、元の文章・出どころ(ファイル名など)を、保存先に入れる。
質問のとき 1. 質問を、同じ埋め込みモデルでベクトルにする。 2. 保存先から、近いチャンクを上位数件取り出す。 3. 取り出した文章を質問に添えて、会話用のAI(LLM)に渡し、答えさせる。
埋め込みモデルと会話用のモデルは、別物です。小さな専用モデルを埋め込みに使い、大きなモデルを答えに使います。
部品1:埋め込みを手元で動かす
Ollama
Ollamaの公式文書(Embeddings)にあるおすすめモデルは、embeddinggemma、qwen3-embedding、all-minilmです。呼び出し口は /api/embed です。公式文書の例です。この記事では、実行していません。
curl -X POST http://localhost:11434/api/embed \
-H "Content-Type: application/json" \
-d '{"model": "embeddinggemma", "input": "The quick brown fox jumps over the lazy dog."}'
文書とAPI仕様から分かる点です。
inputに文字列の配列を渡すと、まとめて変換できます。- 返るベクトルは、L2正規化(長さ1)です。
truncateは既定でtrue。モデルの文脈の長さを超えた分は、末尾が切り捨てられます。falseにすると、超えたときにエラーです。dimensionsで、ベクトルの次元数を指定できます。keep_aliveの既定は5分。使い終わった埋め込みモデルは、5分メモリに残ります。- 公式の「Tips」は、「登録と検索で同じ埋め込みモデルを使う」と書いています。
Ollamaのソースコード(mainブランチ、server/sched.go)では、埋め込みモデルは常に並列数1で読み込まれます。大量の文書を登録しながら、同時に質問に答えさせる使い方では、待ちが出る可能性があります。
LM Studio
LM Studioには、2つの道があります。
- アプリの「Chat with Documents」:
.docx、.pdf、.txtを会話に添付します。公式の説明では、文書が短くモデルの文脈に収まるなら全文を入れ、長ければRAGで関係する部分だけを選んで渡します。調整が要ることもある、と書かれています。質問に、文書にありそうな言葉をたくさん入れると、見つかりやすくなる、という助言もあります。 - API:OpenAI互換の
/v1/embeddingsがあります。公式の例は、base_url="http://localhost:1234/v1"です。Pythonのlmstudioライブラリにもembedding_model(...).embed(...)があり、例ではlms get nomic-ai/nomic-embed-text-v1.5でモデルを取得しています。
llama.cpp
llama.appの文書によると、llama serve -hf unsloth/embeddinggemma-300m-GGUF --embedding で埋め込み専用のサーバーを立てられます。/v1/embeddings を呼びます。並べ替え(--rerank)のモデルも同じサーバーで動かせると書かれています。
部品2:埋め込みモデルを選ぶ
読んだモデルカードとOllamaのモデル頁を、表にします。
| モデル | 規模・次元・入力長 | 言語 | ライセンス | Ollamaでの大きさ |
|---|---|---|---|---|
| EmbeddingGemma(Google) | 300M、768次元(512・256・128にも縮められる)、入力2K | 100以上の言語で学習 | 別の利用規約あり | 622MB |
| Qwen3-Embedding 0.6B | 0.6B、最大1024次元(32〜1024で指定可)、文脈32k | 100以上の言語 | Apache 2.0 | 639MB |
| BGE-M3 | 1024次元、入力8192 | 100以上の言語 | MIT | 1.2GB |
| Ruri v3 310m | 315M、768次元、入力8192 | 日本語 | Apache 2.0 | (確認していません) |
| nomic-embed-text v1.5 | (次元は縮められる)、入力2K | カードの言語表示は英語のみ | Apache 2.0 | 274MB |
| all-MiniLM-L6-v2 | 小型、Ollama版は512 | カードの言語表示は英語 | Apache 2.0 | 46MB |
各モデルのカードにある使い方の注意
- EmbeddingGemma:Matryoshka(入れ子)表現学習で、768次元のベクトルを前から切って短くし、再び正規化すれば、小さい次元でも使えるとカードにあります。Hugging Faceのページは、利用の承諾が必要でした(Googleのモデル頁で内容を確認しました)。
- Qwen3-Embedding:質問側に1文の指示(
Instruct: ...\nQuery:...)を付けるのが前提です。カードによると、指示を付けないと検索の性能が約1〜5%下がります。文書側には付けません。 - BGE-M3:1つのモデルで、密なベクトル、疎なベクトル(BM25に似た単語の重み)、複数ベクトル(ColBERT方式)の3つの検索ができるとカードにあります。
- Ruri v3:日本語専用です。質問に「検索クエリ: 」、文書に「検索文書: 」を付ける決まりです。同じカードの表では、310mのJMTEB(日本語の埋め込み評価)平均が77.24です。
- nomic-embed-text v1.5:文書に
search_document:、質問にsearch_query:を必ず付けると、カードにあります。付け忘れは、精度が落ちる原因になります(見立てです)。
日本語で使うときの判断
見立てです。日本語の文書なら、次の順で考えます。
- 日本語と英語が混ざる、または多言語:EmbeddingGemma、Qwen3-Embedding、BGE-M3のように、100以上の言語を対象にするモデルが候補です。カードや公式の説明で、日本語で測った数字があるのは、僕らが読んだ範囲ではRuri v3だけです。
- 日本語だけ:Ruri v3が候補です。ただしOllamaの公式頁での配布は確認していません。Hugging Face経由でsentence-transformersから使う形になります。
- 英語向けのモデル(nomic、all-MiniLM)は、日本語の文書にはおすすめしません。カードが対象言語を英語としているためです。
Chromaは、埋め込み関数を指定しないと、all-MiniLM-L6-v2 を既定に使う、と文書に書いています。このモデルのカードは、言語を英語としています。Chromaで日本語を扱うときは、必ず、別の埋め込み関数(OllamaやSentence Transformers)を指定してください。
部品3:ベクトルの保存先
| 保存先 | 形 | 公式文書で確認できた点 |
|---|---|---|
| Chroma | Pythonなどのライブラリ。ファイルに保存、またはサーバー | PersistentClient(path=...)で保存。既定のパスは .chroma。距離の既定は l2。cosine と ip も選べる |
| sqlite-vec | SQLiteの拡張。1つのファイルで完結 | vec0 という仮想テーブルに float[768] のように宣言。READMEは「v1より前なので、互換が崩れる変更に注意」と明記 |
| pgvector | Postgresの拡張 | 近似検索の索引にHNSWとIVFFlat。vector 型の索引は2,000次元まで。ACID、JOINなどPostgresの機能が使える |
Chromaを例に
- Ollamaの埋め込みは公式のラッパー(
OllamaEmbeddingFunction)で使えます。コレクションに埋め込み関数を渡すと、addとqueryでテキストを渡すだけで、登録と検索ができます。 - 僕らの計算です。Ollamaのベクトルは長さ1に正規化されるので、長さ1のベクトルどうしでは、二乗距離(l2)が小さい順と、コサイン類似度が大きい順は同じ並びになります(二乗距離は 2−2×コサイン類似度)。つまり、Ollama+Chromaの既定のままでも、順位は変わりません。ただし、距離の値そのものは、コサイン距離とは別物です。しきい値で足切りするときは、注意してください。
- チャンクの注意として、Chromaの文書は、1レコードの文書サイズを16KBに制限しています。また、埋め込みモデルには入力の上限があり、超えた部分はベクトルに反映されません。
- Chromaは1.5.4から、製品の利用状況の収集(テレメトリー)をやめた、と文書にあります。
pgvectorの注意
READMEによると、近似索引は、絞り込み条件を、索引の検索の後に適用します。たとえば条件に合うのが全体の10%なら、既定の hnsw.ef_search(40)で、平均4件しか残りません。0.8.0以降は反復スキャン(hnsw.iterative_scan)で、足りない分を探し足せます。部署や公開範囲などで絞り込む使い方では、重要な点です。
チャンクの切り方
Chromaのチャンクの手引きは、文を1つずつに切ると、答えと見出しの言葉が別の断片に離れて、検索に失敗する例を挙げています。「接続のタイムアウトは何秒?」という質問に対し、「既定値は30秒」の文だけの断片は「接続のタイムアウト」という語を含まず、見つかりにくいのです。手引きは、段落のまとまりを保つ切り方を勧めています。
その上で、切る大きさには上限が2つあります。
- 埋め込みモデルの入力長(EmbeddingGemmaなら2K)。
- 会話用のモデルの文脈の長さ。取り出した断片を全部入れる必要があるためです。
僕らの計算です。1断片を約500トークン、上位5件を取り出すと、断片だけで約2,500トークンです。質問と答えの分を合わせると、Ollamaの既定の文脈が4k(VRAM 24GiB未満の場合の公式の説明)では、ぎりぎりです。件数を絞るか、num_ctx(OLLAMA_CONTEXT_LENGTH)を上げる必要があります。
よくあるつまずき
- 登録と検索でモデルが違う:ベクトルの次元数も意味の空間も合いません。モデルを替えたら、全文書を埋め込み直します。
- 接頭辞の付け忘れ:nomic、Ruri、Qwen3-Embeddingは、質問と文書で付ける文言が決まっています。
- 英語向けの既定のまま日本語を入れる:Chromaの既定が該当します。
- 入力長の超過:Ollamaの
truncateは既定で末尾を切り捨てます。気づかないまま、後半が検索されなくなります。 - 更新の反映:文書を直したら、そのチャンクのベクトルも作り直して、古い断片を消す必要があります。
- ベクトルの距離の設定:Chromaの既定はl2です。pgvectorは、索引の種類(
vector_l2_ops、vector_cosine_opsなど)を、検索の演算子と合わせます。
気をつけること
- この記事は、この構成を組んで動かした記録ではありません。コードは、公式文書の短い例だけを載せました。
- 検索の精度や速度は、測っていません。モデルの優劣の断定は避けています。
- Ruri v3以外のモデルで、日本語の性能を示した数字は、読んだ範囲では確認できていません。「100以上の言語」は、学習データの記述で、日本語の品質の保証ではありません。
- Chromaの文書はChroma Cloud(有料のクラウド)の案内を多く含みます。ここではローカルの
PersistentClientに絞りました。 - sqlite-vecは、READMEで開発途中(v1より前)と明記されています。
- 「すべて手元」でも、Hugging Faceからモデルを取得する時点では、通信が起きます。取得後はオフラインで使えます。
- 機密性の高い文書は、保存先のファイルのバックアップや権限も、自分で管理する必要があります。
- 各モデルのライセンス、バージョン、サイズは、変わることがあります。
出典
- Embeddings(Ollama Docs、Ollama、GitHub、2026年10月8日確認)
- API: Generate Embedding(Ollama Docs、Ollama、GitHub、2026年10月8日確認)
- embeddinggemma(Ollama Library、Ollama、2026年10月8日確認)
- qwen3-embedding / bge-m3 / nomic-embed-text / all-minilm(Ollama Library、Ollama、2026年10月8日確認)
- server/sched.go(Ollama、GitHub、2026年10月8日確認)
- Chat with Documents(LM Studio Docs、LM Studio、2026年10月8日確認)
- Embeddings(OpenAI互換API、LM Studio Docs、2026年10月8日確認)
- Embedding(Python SDK、LM Studio Docs、2026年10月8日確認)
- Running a server(llama.app Docs、llama.cppチームとHugging Face、2026年10月8日確認)
- EmbeddingGemma model card(Google AI for Developers、Google、2026年10月8日確認)
- Qwen3-Embedding-0.6B モデルカード(Hugging Face、Qwen、2026年10月8日確認)
- bge-m3 モデルカード(Hugging Face、BAAI、2026年10月8日確認)
- ruri-v3-310m モデルカード(Hugging Face、cl-nagoya、2026年10月8日確認)
- nomic-embed-text-v1.5 モデルカード(Hugging Face、Nomic AI、2026年10月8日確認)
- all-MiniLM-L6-v2 モデルカード(Hugging Face、sentence-transformers、2026年10月8日確認)
- Chroma Clients / Embedding Functions / Configure Collections / Query and Get / Open Source(Chroma Docs、Chroma、2026年10月8日確認)
- Chunking(Chroma Docs、Chroma、2026年10月8日確認)
- Ollama(Chroma Docs 埋め込み連携、Chroma、2026年10月8日確認)
- sqlite-vec README(asg017、GitHub、2026年10月8日確認)
- KNN queries(sqlite-vec Docs、2026年10月8日確認)
- pgvector README(pgvector、GitHub、2026年10月8日確認)
更新履歴
- 2026年10月25日 書き方を直しました。
- 前:運営者が使っていないと読める書き方 → いま:「この記事は、実際に使って確かめた記録ではありません」。公式の資料を読んでまとめた記事で、使い心地は書いていない、という意味に直した
