ローカルLLMで社内文書を検索するRAGシステムの作り方

ローカルLLM

この記事のポイント

  • ローカルLLM + RAGで社内文書をAI検索するシステムを機密データを外に出さず完全ローカルで構築できます
  • Ubuntu 24.04.4 LTS(Python 3.12.3)で chromadb 1.5.9 / langchain 0.3.30 / qdrant-client 1.16.1 / pypdf 6.13.2 の導入と動作を実機確認しました
  • 日本語の質問8件で実測したところ、英語特化の埋め込みモデルは正答率50%(4/8)止まり、多言語対応モデルに替えると100%(8/8)に改善しました
  • ChromaDB(プロトタイプ向け)と Qdrant 1.18.2(本番向け・GUIあり)の2通りの構成を実際に動かして解説します
  • PDF・テキストをベクトルDBに投入し、日本語で質問して該当文書を取り出せます

「社内の議事録やマニュアルをAIで検索したいけど、ChatGPTに機密情報を送るのは怖い」——そんな要望に応えるのが、ローカルLLMとRAG(Retrieval Augmented Generation)を組み合わせたオフラインAI検索システムです。本記事では Ubuntu 24.04 で実際に環境を構築し、ChromaDB と Qdrant を使って社内文書を検索できるシステムの作り方を解説します。

結論から言うと、ChromaDB なら pip install だけで今日から試せます。ただし埋め込みモデルの選択を間違えると日本語検索がまともに当たりません。本記事では Docker 公式イメージ(ubuntu:24.04)と手元の Python 仮想環境で実際にコマンドを動かし、パッケージのバージョンも日本語検索の正答率もすべて実測した値で説明します。

注意

本記事は Ubuntu 24.04 LTS(Noble Numbat、実測 PRETTY_NAME は Ubuntu 24.04.4 LTS)で検証しています。Python 仮想環境(venv)を使う前提です。バージョンが異なると動作が変わる場合があります。

RAGシステムとは何か

RAG(Retrieval Augmented Generation)は、LLMが回答を生成する際に外部の文書データベースから関連情報を取得してプロンプトに付加する手法です。LLMが学習していない社内独自のドキュメント、最新のマニュアル、議事録などを「知識ベース」として活用できます。

①RAGと通常のLLMの違い

通常のLLMは学習データに含まれる知識しか答えられません。一方RAGは、事前に文書をベクトルDBに蓄積しておき、ユーザーの質問に関連するチャンク(文書の断片)を動的に取得して回答の材料にします。

社内文書QAシステムの処理フロー(Ollama + ChromaDB / Qdrant 構成、概念図)
社内文書QAシステムの処理フロー(Ollama + ChromaDB / Qdrant 構成、概念図)

処理の流れは上図のとおりです。①文書をチャンク分割して②Embeddingモデルでベクトル化し③ベクトルDBに保存、質問が来たら④類似検索でTop-Kのチャンクを取得して⑤LLMがコンテキスト付きで回答します。本記事では②〜④の「検索」部分を実際に動かし、⑤の回答生成は Ollama との接続で締めくくります。

②ローカルRAGのメリット

  • 情報漏洩ゼロ:社内機密文書をインターネットに送らない
  • API費用ゼロ:VPS/自宅サーバーの電気代だけで動く
  • カスタマイズ自由:社内用語・専門用語に合わせた設計ができる
  • オフライン動作:ネットワーク障害時でも問い合わせに答えられる

ベクトルDB比較:ChromaDB vs Qdrant

ローカルRAGで使えるベクトルDBとして、ChromaDBQdrantが特に人気です。両者の特徴を整理しておきます。

ベクトルDB比較表(ChromaDB / Qdrant / Weaviate / pgvector)
ベクトルDB比較表(ChromaDB / Qdrant / Weaviate / pgvector)

最初に試すなら ChromaDB が手軽です。インストールは pip install chromadb の1行で完了し、Docker も不要です。データを永続化したい・GUIで状態を確認しながら運用したい場合は Qdrant が優れています。本記事では両方を実際に起動して紹介します。表中のバージョン(ChromaDB 1.5.9・Qdrant 1.18.2)は、このあと実際に導入・起動して確認した実測値です。

前提環境

  • OS:Ubuntu 24.04 LTS(または Docker ubuntu:24.04 イメージ。実測 PRETTY_NAME は Ubuntu 24.04.4 LTS
  • Python:3.12.3(Ubuntu 24.04 の apt-cache policy python3 候補は 3.12.3-0ubuntu2.1
  • Docker:インストール済み(Qdrant を使う場合)
  • メモリ:最低2GB(埋め込みモデル+Ollama を動かすなら8GB以上推奨)

ChromaDB でシンプルにRAGを試す

まずは ChromaDB を使ったシンプルな構成から始めましょう。Docker 不要で、インストールからすぐ試せます。

手順1:Python仮想環境とパッケージのセットアップ

Ubuntu 24.04 では、pip install をシステム環境に直接実行するとエラーで弾かれます。実際に Docker コンテナで再現してみました。




ubuntu@linuxlab: ~
# ❌ システム環境に直接入れようとすると弾かれる
$ pip3 install chromadb
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install …

# ✅ venv を作ってから入れる
$ sudo apt update && sudo apt install -y python3-venv
$ python3 -m venv rag-env
$ source rag-env/bin/activate
(rag-env) $ pip install chromadb sentence-transformers qdrant-client langchain pypdf
Successfully installed chromadb-1.5.9 langchain-0.3.30 \
sentence-transformers-5.1.2 qdrant-client-1.16.1 pypdf-6.13.2
RAG環境セットアップ実ログ(Ubuntu 24.04 実測:externally-managed エラー再現とvenv解決)
RAG環境セットアップ実ログ(Ubuntu 24.04 実測:externally-managed エラー再現とvenv解決)

実際に Ubuntu 24.04 のコンテナで pip3 install を直接叩くと error: externally-managed-environment が返ることを確認しました。venv を経由すれば問題なく導入でき、chromadb 1.5.9 / langchain 0.3.30 / sentence-transformers 5.1.2 / qdrant-client 1.16.1 / pypdf 6.13.2 が入りました。

著者アイコン
著者アイコン

古い記事だと「langchain 1.x」と書いてあるものを見かけますが、2026年6月時点で pip install langchain すると実際に入るのは 0.3.30 です。バージョンを鵜呑みにせず、自分の環境で pip show langchain を一度叩いて確認する癖をつけると安全ですよ。

手順2:サンプル文書を用意する

今回は社内Linuxマニュアルを想定して、Docker・SSH・ログ監視・cron・バックアップなど12件の日本語文書を用意しました。実際の運用ではPDFファイルを pypdf で読み込みます(後述)。




ubuntu@linuxlab: ~/rag-demo
(rag-env) $ cat doc_qa_demo.py
import chromadb

# 社内文書(PDFから読み込んだテキストと同等)
docs = [
“Dockerのインストール手順: curl -fsSL https://get.docker.com | sh …”,
“SSHの鍵認証設定: /etc/ssh/sshd_config で PasswordAuthentication no …”,
“ログのリアルタイム監視: journalctl -f でシステムログを追跡 …”,
# …(計12件)
]
client = chromadb.EphemeralClient()
col = client.create_collection(“company_docs”)
col.add(documents=docs, ids=[f”doc{i}” for i in range(len(docs))])

手順3:RAGパイプラインを実行して検索する

ChromaDB は埋め込みモデルを指定しないと、デフォルトで all-MiniLM-L6-v2(ONNX形式、初回のみ約79MBのダウンロードが発生)を使います。これで日本語の質問を投げて、社内文書を検索してみます。




ubuntu@linuxlab: ~/rag-demo
(rag-env) $ python3 doc_qa_demo.py
=== 社内文書QA デモ (chromadb 1.5.9 / cosine) ===
投入件数: 12件

Q: Dockerを導入する手順を教えて
-> [dist:0.4023] Dockerのインストール手順: curl -fsSL https://… ✓正解
Q: SSHでパスワードログインを禁止する方法
-> [dist:0.3992] プロセスの確認と終了: ps aux で稼働中の… ✗誤りヒット
Q: ファイルを別のサーバーにバックアップする方法
-> [dist:0.3622] ログのリアルタイム監視: journalctl -f で… ✗誤りヒット

「Dockerを導入する手順を教えて」には距離 0.4023 で正しい文書が返りました。ところが「SSHでパスワードログインを禁止する方法」では、まったく無関係な「プロセスの確認と終了」が1位になってしまいました。これは all-MiniLM-L6-v2 が英語向けに学習されたモデルで、日本語の意味的な近さを正しく捉えられていないためです。

著者アイコン
著者アイコン

ここで「なんか検索精度が低いな」と感じた方は正解です。距離(cosine distance)の数字だけ見ると0.4前後で動いているように見えますが、実際は的外れな文書を1位で返しているのが問題です。距離の絶対値より「正しい文書が1位に来ているか」で評価しましょう。次のセクションでちゃんと計測します。

日本語精度を上げる:埋め込みモデルの切り替え

どれくらい精度が変わるのか、ふんわりした印象ではなく数字で確かめましょう。同じ12件の社内文書・同じ8つの日本語質問を用意し、2つの埋め込みモデルで「rank-1(1位)が正解だった割合」を実測しました。

  • all-MiniLM-L6-v2(英語特化・ChromaDB デフォルト)
  • paraphrase-multilingual-MiniLM-L12-v2(多言語対応・sentence-transformers)
埋め込みモデル別 日本語検索の正答率(rank-1 accuracy、実測)
埋め込みモデル別 日本語検索の正答率(rank-1 accuracy、実測)

結果は明確でした。英語特化モデルは8問中4問しか正解できず、正答率50%。一方、多言語対応モデルに替えると8問すべて正解(正答率100%)になりました。誤りの中身も見てみます。

日本語クエリ8件を2モデルで検索した実測セッション(ChromaDB 1.5.9)
日本語クエリ8件を2モデルで検索した実測セッション(ChromaDB 1.5.9)

英語特化モデルが外したのは「SSHでパスワードログインを禁止する方法」「決まった時刻にスクリプトを自動で動かしたい(cron)」「ファイルを別のサーバーにバックアップする方法(rsync)」「ユーザーにsudo権限を与えるには」の4問です。いずれも日本語の言い換え(質問文と文書で表現が違う)に弱く、無関係な文書を1位にしていました。多言語モデルではSSHの質問が距離0.1927、メモリの質問が0.2061、ディスクの質問が0.2378と、正解文書がはっきり近い位置に来ています。

切り替えは簡単です。コレクション作成時に埋め込み関数を指定するだけです。




ubuntu@linuxlab: ~/rag-demo
(rag-env) $ pip install sentence-transformers
from chromadb.utils import embedding_functions
ef = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name=”paraphrase-multilingual-MiniLM-L12-v2″
)
col = client.create_collection(
“company_docs_ja”, embedding_function=ef,
metadata={“hnsw:space”: “cosine”})

日本語文書を扱うなら埋め込みモデルは必ず替える

ChromaDB のデフォルト all-MiniLM-L6-v2 は英語特化です。日本語が中心なら paraphrase-multilingual-MiniLM-L12-v2(多言語)や pkshatech/GLuCoSE-base-ja(日本語特化)に替えてください。今回の実測では正答率が50%→100%まで改善しました。

Qdrant + Docker で本番向けRAGを構築する

データを永続化したい、GUIで状態を確認したい場合は Qdrant を使います。Docker で起動して、Python から接続します。

手順1:Qdrant を Docker で起動する




ubuntu@linuxlab: ~
$ docker run -d \
–name qdrant_rag \
-p 6333:6333 \
-v $(pwd)/qdrant_data:/qdrant/storage \
qdrant/qdrant:latest
$ curl http://localhost:6333/
{“title”:”qdrant – vector search engine”,”version”:”1.18.2″}

起動した Qdrant のバージョンは 1.18.2 でした。確認できたら、ブラウザで http://localhost:6333/dashboard にアクセスすると Web ダッシュボードが開きます。

Qdrant Web コンソール(REST APIをブラウザから実行できる画面、Playwright実撮影)
Qdrant Web コンソール(REST APIをブラウザから実行できる画面、Playwright実撮影)

上が実際の Qdrant v1.18.2 のコンソール画面です(Playwright で実撮影)。左メニューの「Console」からブラウザ上で直接 REST API を叩けるので、コレクションの確認やデバッグが楽になります。

手順2:Python から Qdrant にドキュメントを投入する

多言語モデルで12件の文書を384次元のベクトルに変換し、Qdrant のコレクションに投入します。




ubuntu@linuxlab: ~/rag-demo
(rag-env) $ python3 qdrant_upload.py
from qdrant_client import QdrantClient
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(“paraphrase-multilingual-MiniLM-L12-v2”)
vecs = model.encode(docs, normalize_embeddings=True) # 384次元
client = QdrantClient(host=”localhost”, port=6333)
# size=384, distance=Cosine でコレクション作成し投入
コレクション作成完了: company_docs (size=384, Cosine)
ドキュメント投入完了: points_count=12
Qdrantコレクション一覧(company_docs / 12 points / 384 / Cosine、Playwright実撮影)
Qdrantコレクション一覧(company_docs / 12 points / 384 / Cosine、Playwright実撮影)

ダッシュボードのコレクション一覧では、company_docsSTATUS: GREEN・POINTS 12・VECTORS CONFIG: 384 / Cosine として表示されました。投入が正しく完了したことがGUIから一目で確認できます。

Qdrant コレクション詳細(各ポイントの日本語ペイロードと384次元ベクトル、Playwright実撮影)
Qdrant コレクション詳細(各ポイントの日本語ペイロードと384次元ベクトル、Playwright実撮影)

コレクション詳細画面では、各ポイントのペイロード(日本語の文書テキスト)と「Vectors: Default vector / Length: 384」が確認できます。Point 0 が Docker、Point 1 が SSH の文書というように、投入した中身がそのまま見えます。

手順3:類似検索が正しく動くか確認する

実際に「SSHでパスワードログインを禁止する方法」という質問で検索したところ、Qdrant でも正しくSSH設定の文書が cosine スコア 0.8073 で1位に返りました(スコアは大きいほど類似、ChromaDBの距離とは符号が逆です)。ChromaDBで多言語モデルに替えたときと同じく、本番向けの Qdrant でも日本語検索がきちんと当たることを確認できました。

PDFファイルを読み込む(pypdf 6.13.2)

実際の社内文書はPDF形式が多いでしょう。pypdf でPDFを読み込んでチャンク分割し、RAGに投入します。




ubuntu@linuxlab: ~/rag-demo
from pypdf import PdfReader
reader = PdfReader(“manual.pdf”)
texts = []
for page in reader.pages:
text = page.extract_text()
if text:
# 500文字ずつチャンク分割
for i in range(0, len(text), 500):
texts.append(text[i:i+500])
print(f”ページ数: {len(reader.pages)}, チャンク数: {len(texts)}”)

スキャンPDFはテキスト抽出できません

スキャン画像を含むPDFや、保護がかかっているPDFは pypdf ではテキストを抽出できません。その場合は pdf2image + OCR(Tesseract)を組み合わせてください。

使用したPythonパッケージ一覧

RAG構築に使ったPythonパッケージの実測バージョン(2026年6月実測)
RAG構築に使ったPythonパッケージの実測バージョン(2026年6月実測)

上の表は 2026年6月15日に pip show で取得した実測バージョンです。chromadb 1.5.9 / langchain 0.3.30 / sentence-transformers 5.1.2 / qdrant-client 1.16.1 / pypdf 6.13.2 でRAGパイプラインの動作を確認しています。埋め込みモデルの推論には torch 2.8.0transformers 4.57.6、ChromaDBデフォルトモデルのONNX推論には onnxruntime 1.19.2 が使われます。

よくあるエラーと解決策

①「error: externally-managed-environment」が出る

Ubuntu 24.04 では、システム Python 環境への pip install がブロックされます。本記事でも実際に再現しました。必ず仮想環境(venv)を使ってください。




ubuntu@linuxlab: ~
$ pip3 install chromadb
error: externally-managed-environment
# ✅ venv を経由すれば OK
$ python3 -m venv rag-env && source rag-env/bin/activate
(rag-env) $ pip install chromadb
Successfully installed chromadb-1.5.9

②日本語の検索精度が低い

本記事の実測どおり、デフォルトの all-MiniLM-L6-v2 は英語特化モデルで、日本語の正答率は50%程度に留まります。日本語文書が多い場合は paraphrase-multilingual-MiniLM-L12-v2(多言語対応)または pkshatech/GLuCoSE-base-ja(日本語特化)に切り替えると精度が上がります。

③Qdrantに接続できない

docker ps でコンテナが起動しているか確認し、curl http://localhost:6333/ でバージョンJSONが返るかチェックしましょう。ヘルスチェックは curl http://localhost:6333/healthz で200が返れば正常です。ポートが競合している場合は -p 16333:6333 のように変更します。




ubuntu@linuxlab: ~
$ docker ps | grep qdrant
qdrant/qdrant:latest Up 2 minutes 0.0.0.0:6333->6333/tcp qdrant_rag
$ curl http://localhost:6333/
{“title”:”qdrant – vector search engine”,”version”:”1.18.2″}

④onnxruntime の CPU 警告が出る

ARM CPU(M1/M2 Mac の Docker 等)では onnxruntime の CPU 関連警告が出ることがありますが、動作には影響しません。そのまま進めて問題ありません。

Ollama と接続してRAG回答生成まで行う

ベクトルDBで文書を検索できたら、次は Ollama と組み合わせて回答生成まで完成させます。Ollama のセットアップは Ollama インストール完全ガイド を参照してください。




ubuntu@linuxlab: ~/rag-demo
(rag-env) $ pip install ollama
import chromadb, ollama

def qa(question: str) -> str:
# 1. 類似文書を取得(多言語モデルのコレクション)
results = col.query(query_texts=[question], n_results=3)
context = “\n”.join(results[“documents”][0])
# 2. プロンプトにコンテキストを付加
prompt = f”以下の文書を参考に答えてください:\n{context}\n質問:{question}”
# 3. Ollama で推論
r = ollama.chat(model=”qwen2.5:3b”, messages=[{“role”:”user”,”content”:prompt}])
return r[“message”][“content”]

Ollama のモデル選択

  • qwen2.5:3b:3B パラメータ、低スペックでも動作(RAM 4GB〜)・日本語も比較的得意
  • llama3.2:3b:Meta 製、英語が得意(日本語は補助的)
  • gemma3:4b:Google 製、多言語対応で日本語も良好

まとめ

Ubuntu 24.04 でローカルRAGを使った社内文書QAシステムを構築できました。実測データをまとめると:

  • chromadb 1.5.9・langchain 0.3.30・qdrant-client 1.16.1・pypdf 6.13.2 を確認(2026-06-15 実測)
  • 埋め込みモデルの日本語検索 rank-1 正答率:all-MiniLM-L6-v2 は50%(4/8)、多言語モデルは100%(8/8)
  • 日本語精度向上には paraphrase-multilingual-MiniLM-L12-v2 への切り替えが有効
  • Qdrant v1.18.2 の GUI ダッシュボードで 12 points / 384次元 / Cosine の投入状況をリアルタイム確認できる
  • 機密文書を外部に送らずローカル完結で動作する

次のステップとして、このRAGシステムをVPS上に構築してチームで共有する方法も検討してみてください。月数ドルのVPSでも、社内AI検索サーバーを低コストで立ち上げられます。

より発展したRAGの活用例(LangChain エージェントとの組み合わせ、複数文書タイプ対応)については LangChain Ubuntu セットアップガイド もあわせてご覧ください。

コメント

タイトルとURLをコピーしました