「ChromaDBとOllamaを連携させる具体的な手順が見つからず、RAG構築の第一歩で立ち止まっている」
そんな悩みを抱えるLinuxサーバー管理者・インフラエンジニアは多いはずです。この記事では、OllamaのEmbedding APIとChromaDBを組み合わせて、完全ローカル動作のベクターデータベースを構築する手順を解説します。インストールから社内ドキュメントのインジェスト・意味検索の実行・永続化設定まで、Pythonスクリプトとともに一通りカバーします。クラウドAPIを一切使わず機密文書を扱いたい方に向けた内容です。
この記事のポイント
・nomic-embed-text をOllamaで動かすカスタムEmbedding関数でChromaDBと連携できる
・pip install chromadb 後、PersistentClientを使えばファイル永続化まで数十行で実装可能
・インジェスト→意味検索の一連の流れをPythonスクリプトのコピペで試せる
・コレクション管理・バックアップ・よくあるエラー対処法も網羅
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
ChromaDBとOllamaを組み合わせる理由 — ローカルだけで意味検索を実現するアーキテクチャ
従来のキーワード検索(grep・全文検索)は、検索クエリの言葉がドキュメントに文字どおり含まれていないと引っかかりません。「多要素認証の設定手順」というドキュメントを「SSHのセキュリティ設定」というキーワードで探す場合、単語が一致しないため見つけられない、という構造的な限界があります。意味検索ではテキストを高次元のベクター(数値の配列)に変換し、意味的に近いベクター同士を数学的な距離で比較します。「SSHのセキュリティ」と「多要素認証」のベクターが近い位置に存在すれば、たとえ単語が異なっていても関連文書として返せます。この仕組みの中でベクターの保存と高速な類似検索を担うのがベクターデータベースです。
ChromaDBはPython製のオープンソースベクターストアです。Pinecone・Weaviate・Qdrantといったクラウドサービスと異なり、ローカルサーバーのみで動作するため外部へのデータ送信がありません。APIがシンプルで、インメモリ・ファイル永続化・クライアントサーバー構成の3モードを用途に合わせて切り替えられます。
Ollamaとの組み合わせでは、ベクター変換(Embedding)にもローカルモデルを使います。Embedding専用の軽量モデル(nomic-embed-textなど)をOllamaで動かすことで、OpenAIのEmbedding APIに相当する機能をインターネットなしで実現できます。OllamaのUbuntu Serverへの構築手順はUbuntu ServerでローカルLLMを構築する方法の記事で詳しく解説しています。まだ環境を作っていない場合はそちらを先に確認してください。
事前準備 — Ollamaの動作確認とEmbeddingモデルの取得
作業を始める前に、OllamaのEmbedding APIが正常に応答することを確認します。Ollamaサービスが起動していないと以降のすべての手順が失敗するため、先に疎通確認を済ませておくことが重要です。1. OllamaのEmbedding APIに疎通確認する
# OllamaのEmbedding APIへcurlで確認する $ curl http://localhost:11434/api/embeddings \ -d '{"model": "nomic-embed-text", "prompt": "テスト"}' {"embedding":[-0.01234, 0.06789, -0.02345, 0.03456, ...]}
2. nomic-embed-textモデルを取得する
# Embeddingモデルをローカルに取得する $ ollama pull nomic-embed-text pulling manifest pulling 970aa74c0a90... 100% ████████ 274 MB/274 MB verifying sha256 digest writing manifest success
3. Python環境を確認する
$ python3 --version Python 3.11.9 $ pip3 --version pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.11)
ChromaDBをUbuntu Serverにインストールする手順
ChromaDBはpipで簡単にインストールできます。専用の仮想環境を用意してから進めると、システムのPython環境を汚染しません。1. 作業ディレクトリと仮想環境を準備する
# 作業ディレクトリを作成して仮想環境を構築する $ mkdir -p /opt/chromadb-project && cd /opt/chromadb-project $ python3 -m venv venv $ source venv/bin/activate (venv) $
2. ChromaDBをpipでインストールする
# ChromaDBとHTTPクライアントをインストールする (venv) $ pip install chromadb httpx Collecting chromadb Downloading chromadb-0.5.20-py3-none-any.whl (589 kB) ... Successfully installed chromadb-0.5.20 httpx-0.27.2
3. インストールを確認する
(venv) $ python3 -c "import chromadb; print(chromadb.__version__)" 0.5.20
OllamaのEmbedding APIをChromaDBで使うカスタム関数を実装する
ChromaDBのデフォルトEmbedding関数はscikit-learnベースで動作しますが、Ollamaのローカルモデルでベクター生成するにはカスタム実装が必要です。ChromaDBは `__call__(input: list) -> list` のインターフェースを持つクラスをEmbedding関数として受け付けます。1. カスタムEmbedding関数クラスを作成する
以下を `/opt/chromadb-project/ollama_embed.py` として保存します。# /opt/chromadb-project/ollama_embed.py import httpx class OllamaEmbeddingFunction: def __init__(self, model="nomic-embed-text", base_url="http://localhost:11434"): self.model = model self.base_url = base_url def __call__(self, input: list) -> list: embeddings = [] for text in input: res = httpx.post( f"{self.base_url}/api/embeddings", json={"model": self.model, "prompt": text}, timeout=30.0 ) res.raise_for_status() embeddings.append(res.json()["embedding"]) return embeddings
2. カスタム関数の動作を確認する
(venv) $ python3 -c " from ollama_embed import OllamaEmbeddingFunction fn = OllamaEmbeddingFunction() result = fn(['テスト文字列']) print(f'次元数: {len(result[0])}') print(f'先頭5値: {result[0][:5]}') " 次元数: 768 先頭5値: [-0.01234, 0.06789, -0.02345, 0.03456, -0.05678]
社内ドキュメントをChromaDBにインジェストする手順
実際にテキストファイルを読み込んでChromaDBへ格納するスクリプトを作成します。大量ドキュメントを扱う場合は、1ドキュメントあたり300~600字に分割(チャンキング)してから格納すると検索精度が上がります。ここではまず分割なしの基本形から始めます。1. インジェストスクリプトを作成する
以下を `/opt/chromadb-project/ingest.py` として保存します。# /opt/chromadb-project/ingest.py import chromadb from ollama_embed import OllamaEmbeddingFunction import os, sys def ingest_docs(doc_dir, collection_name="internal_docs"): embed_fn = OllamaEmbeddingFunction(model="nomic-embed-text") client = chromadb.PersistentClient(path="/opt/chromadb-data") col = client.get_or_create_collection( name=collection_name, embedding_function=embed_fn ) ids, texts = [], [] for fname in sorted(os.listdir(doc_dir)): if not fname.endswith(".txt"): continue with open(os.path.join(doc_dir, fname), "r", encoding="utf-8") as f: text = f.read().strip() if not text: continue ids.append(fname) texts.append(text) print(f" 読み込み: {fname} ({len(text)}字)") if ids: col.add(documents=texts, ids=ids) print(f"\n合計 {len(ids)} 件をChromaDBへ格納完了") else: print("対象ファイルが見つかりません") if __name__ == "__main__": ingest_docs(sys.argv[1] if len(sys.argv) > 1 else "./docs")
2. サンプルファイルでインジェストを実行する
# サンプルドキュメントを作成してインジェストを実行する (venv) $ mkdir -p /opt/chromadb-project/docs (venv) $ echo "rootパスワードは月次で変更すること。変更はpasswdコマンドを使う。" \ > /opt/chromadb-project/docs/security_policy.txt (venv) $ echo "本番サーバーへのSSHは多要素認証を必須とする。鍵認証とOTPを組み合わせる。" \ > /opt/chromadb-project/docs/ssh_policy.txt (venv) $ python3 ingest.py /opt/chromadb-project/docs 読み込み: security_policy.txt (35字) 読み込み: ssh_policy.txt (38字) 合計 2 件をChromaDBへ格納完了
既存コレクションへの追加時、IDが重複するとエラーになります。再インジェストする場合は `col.delete(ids=[fname])` で既存エントリを削除してから `col.add()` を実行してください。差分インジェスト(変更ファイルのみ更新)をするなら、ファイルのハッシュ値をmetadataとして保存し変更検出する実装が有効です。
PythonからChromaDBで意味検索を実行する
格納したドキュメントに対して意味検索を実行します。検索クエリもOllamaでベクター化され、格納済みベクターとのコサイン距離が計算されます。テキストが一言も一致しなくても、意味が近ければ上位に返ってきます。1. 検索スクリプトを作成する
以下を `/opt/chromadb-project/search.py` として保存します。# /opt/chromadb-project/search.py import chromadb from ollama_embed import OllamaEmbeddingFunction import sys def search_docs(query, n_results=3, collection_name="internal_docs"): embed_fn = OllamaEmbeddingFunction(model="nomic-embed-text") client = chromadb.PersistentClient(path="/opt/chromadb-data") col = client.get_collection( name=collection_name, embedding_function=embed_fn ) results = col.query(query_texts=[query], n_results=n_results) print(f"\n検索クエリ: {query}") print("─" * 44) for i, (doc_id, doc, dist) in enumerate(zip( results["ids"][0], results["documents"][0], results["distances"][0] ), 1): print(f"[{i}] {doc_id} (距離: {dist:.4f})") print(f" {doc[:80]}") print() if __name__ == "__main__": q = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "パスワード管理" search_docs(q)
2. 意味検索を実行する
# 「アクセス認証」でサーバー関連ドキュメントを意味検索する (venv) $ python3 search.py "サーバーへのアクセス認証について" 検索クエリ: サーバーへのアクセス認証について ──────────────────────────────────────────── [1] ssh_policy.txt (距離: 0.2341) 本番サーバーへのSSHは多要素認証を必須とする。鍵認証とOTPを組み合わせる。 [2] security_policy.txt (距離: 0.5123) rootパスワードは月次で変更すること。変更はpasswdコマンドを使う。
RAGパイプラインとして使う場合は、検索結果のドキュメントをOllamaのChat APIに「コンテキスト」として渡します。ローカルLLMをRAGの回答生成エンジンとして使う際の社内展開判断については社内でChatGPTが使えないときの代替手段の記事も参考にしてください。
ChromaDBのコレクション管理と永続化・データ確認
本番運用に向けて、コレクションの確認・カウント・削除・バックアップの操作を押さえておきます。Kubernetesへのスケールアウトや外部クライアントからの接続が必要になった場合は、`chromadb.HttpClient` を使ったクライアントサーバー構成への移行も検討してください。1. コレクション一覧とドキュメント数を確認する
(venv) $ python3 -c " import chromadb client = chromadb.PersistentClient(path='/opt/chromadb-data') for col in client.list_collections(): c = client.get_collection(col.name) print(f'{col.name}: {c.count()} 件') " internal_docs: 2 件
2. 格納済みドキュメントの内容を取得して確認する
(venv) $ python3 -c " import chromadb client = chromadb.PersistentClient(path='/opt/chromadb-data') col = client.get_collection('internal_docs') all_docs = col.get() for doc_id, doc in zip(all_docs['ids'], all_docs['documents']): print(f'[{doc_id}] {doc[:60]}') " [security_policy.txt] rootパスワードは月次で変更すること。変更はpasswdコマン [ssh_policy.txt] 本番サーバーへのSSHは多要素認証を必須とする。鍵認証とOTPを組
3. データをバックアップする
ChromaDBの永続化データは `/opt/chromadb-data` ディレクトリ以下のSQLiteファイルです。バックアップはディレクトリごとコピーするだけで済みます。# ChromaDBのデータをrsyncでバックアップする $ rsync -av /opt/chromadb-data/ /backup/chromadb-data-$(date +%Y%m%d)/ sending incremental file list ./ chroma.sqlite3 2026/09/11 07:00:01 (xfer#1, to-check=0/1) 合計サイズ: 1.2MB (speedup is 1.00)
よくあるエラーと対処法
構築時に遭遇しやすいエラーを整理します。本番投入前にこの節を確認しておくと、原因調査の時間を短縮できます。エラー1: "model 'nomic-embed-text' not found"
OllamaのEmbedding APIを叩いたときに発生します。モデルの取得が済んでいないか、モデル名のタイポが原因です。`ollama pull nomic-embed-text` を実行してから再試行してください。取得済みモデル一覧は `ollama list` で確認できます。エラー2: "Collection already exists"
`create_collection` を重複実行すると発生します。既存コレクションを再利用する場合は `get_or_create_collection` を使ってください。既存コレクションをリセットしたい場合は `delete_collection` で削除してから `create_collection` で作り直します。エラー3: "Expected embedding with dimension X, got Y"
Embeddingモデルを変更(nomic-embed-text→mxbai-embed-largeなど)すると次元数が変わり、既存コレクションのベクターと不一致が起きます。モデルを切り替えるときは既存コレクションを削除し、新しいモデルで再インジェストする必要があります。コレクション作成時にモデル名をメモしておくと後から混乱しません。エラー4: httpx.ConnectError(OllamaのAPIに繋がらない)
Dockerコンテナ内でChromaDBを動かしている場合、`http://localhost:11434` ではOllamaに繋がりません。`http://host.docker.internal:11434`(Docker Desktop)または OllamaサーバーのホストIPアドレスに変えてください。Ollamaが特定のネットワークインターフェースのみで待ち受けている場合は `OLLAMA_HOST=0.0.0.0:11434` を設定してから `systemctl restart ollama` で再起動します。まとめ
ChromaDBとOllamaを組み合わせることで、クラウドを一切使わないローカル意味検索基盤を構築できます。本記事で扱った内容を以下に整理します。| 手順 | コマンド・ポイント |
|---|---|
| Embeddingモデルの取得 | ollama pull nomic-embed-text |
| ChromaDBのインストール | pip install chromadb httpx |
| カスタムEmbedding関数 | OllamaEmbeddingFunction クラスを実装する |
| 永続化クライアントの初期化 | chromadb.PersistentClient(path="/opt/chromadb-data") |
| ドキュメントのインジェスト | collection.add(documents=texts, ids=ids) |
| 意味検索の実行 | collection.query(query_texts=[query], n_results=3) |
| データのバックアップ | rsync -av /opt/chromadb-data/ /backup/ |
20年以上のLinux教育の現場では、ローカルで完結するAI基盤への関心が急速に高まっています。ChromaDBとOllamaの組み合わせは、その入門として最も試しやすい構成の一つです。
ChromaDB+OllamaのベクターDB構築を2日間のハンズオンで体験する
ローカルLLMを使ったベクターDB・RAGパイプラインの実装を、実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:OllamaでGPUを有効化する方法|NVIDIA CUDA・AMD ROCmをLinuxで設定してローカルLLMの推論を高速化する手順
- この記事の属するカテゴリ:ローカルLLMへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます