ローカルLLMのRAG構築手順(Ollama+ChromaDB+LangChain)で発生する問題の概要
生成AIの活用が広がる中、外部データを参照して回答するRAG(Retrieval-Augmented Generation)システムの構築需要が高まっています。特に、Ollama(ローカルLLM実行環境)、ChromaDB(ベクトルデータベース)、LangChain(フレームワーク)を組み合わせたローカルRAG構築は、データ漏洩の心配がなく、カスタマイズ性が高いため人気です。しかし、開発初心者から中級者がこの環境を構築する過程では、以下のような典型的な問題に遭遇します。
- Ollamaサーバーが起動しない、またはモデルのダウンロードに失敗する
- LangChainとChromaDBの連携で「Collection not found」や「Connection refused」エラーが発生する
- 文書の読み込み(Document Loading)や分割(Splitting)が想定通りに行えない
- 類似検索(Similarity Search)の結果が関連性の低いものばかり返ってくる
- LLMへのプロンプト連鎖(Chain)が機能せず、コンテキストが正しく渡されない
本記事では、これらの問題を解決し、スムーズにローカルRAG環境を構築・実行するための具体的な手順とトラブルシューティング方法を解説します。
問題の原因解説
上記の問題は、主に以下の3つの原因に分類されます。
1. 環境設定と依存関係の不整合
Ollama、ChromaDB、LangChainはそれぞれ独立して開発が進んでおり、バージョン間の互換性問題が発生しがちです。特に、LangChainの更新は頻繁で、過去のコードが突然動作しなくなることがあります。また、Pythonの仮想環境を適切に構築していないと、パッケージの競合が起きる可能性があります。
2. ネットワークとサービス間の接続問題
Ollamaはデフォルトでlocalhost:11434でHTTPサーバーを起動し、ChromaDBもクライアント-サーバーモードで動作させることがあります。ファイアウォールの設定やポートの競合、サービス起動順序の誤りにより、コンポーネント間で通信できないエラーが発生します。
3. ベクトル化と検索のパラメータ設定ミス
RAGの核心は、文書を適切なサイズに分割し、意味を捉えたベクトル(埋め込み)に変換し、効率的に検索することです。文書の分割サイズ(チャンクサイズ)やオーバーラップが不適切だと、検索精度が低下します。また、使用する埋め込みモデル(Embedding Model)とLLMの能力が整合していない場合も、質の低い回答の原因となります。
解決方法:ステップバイステップ構築ガイド
以下に、問題を回避しながら確実に環境を構築する手順を示します。
ステップ1: 前提環境の整備
まず、Python環境とDocker(ChromaDBサーバー利用時)を準備します。
# 1. Python仮想環境の作成と有効化(推奨)
python -m venv rag_env
source rag_env/bin/activate # Linux/macOS
# rag_envScriptsactivate # Windows
# 2. 必要なパッケージのインストール(バージョンを固定することが重要)
pip install langchain==0.1.0 langchain-community==0.0.10
pip install chromadb==0.4.22
pip install sentence-transformers
pip install pypdf # PDF読み込み用
pip install ollama
ステップ2: Ollamaのセットアップとモデルダウンロード
Ollamaをインストールし、軽量なLLMモデルをプルします。公式サイトからOllamaをインストールした後、ターミナルで以下を実行。
# Ollamaサーバーの起動(通常、インストール時に自動起動するが確認)
ollama serve &
# 利用するLLMモデルのダウンロード(例:Mistral 7B)
ollama pull mistral:7b-instruct-q4_K_M
# モデルがリストされているか確認
ollama list
【よくあるエラー】 Error: connect ECONNREFUSED 127.0.0.1:11434 が表示された場合、Ollamaサーバーが起動していません。別のターミナルでollama serveを実行してください。
ステップ3: ChromaDBの準備と文書のベクトル化
ChromaDBをインメモリまたは永続化モードで起動し、文書を読み込んでベクトルストアを作成します。
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
# 1. 文書の読み込み(例:sample.pdf)
loader = PyPDFLoader("./sample.pdf")
documents = loader.load()
# 2. 文書の分割
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # チャンクサイズ(文字数)
chunk_overlap=50, # オーバーラップ(文字数)
separators=["nn", "n", "。", "、", " ", ""] # 分割区切り(日本語対応)
)
split_docs = text_splitter.split_documents(documents)
# 3. 埋め込みモデルとベクトルストアの設定
embeddings = OllamaEmbeddings(model="nomic-embed-text") # 軽量な埋め込みモデル
# ベクトルストアの作成(永続化する場合はpersist_directoryを指定)
vectorstore = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory="./chroma_db" # ディレクトリを指定すると永続化
)
print(f"ベクトルストアに {len(split_docs)} 個のチャンクを登録しました。")
【注意点】 埋め込みモデルnomic-embed-textはollama pull nomic-embed-textで事前にダウンロードが必要です。また、chunk_sizeは小さすぎると文脈が失われ、大きすぎると検索精度が下がります。日本語文書の場合はseparatorsに句読点を追加することが有効です。
ステップ4: 検索連鎖(Retrieval Chain)の構築と実行
LangChainのチェーンを組み立て、質問に対してベクトル検索を行い、その結果をコンテキストとしてLLMに渡して回答を生成します。
from langchain_community.llms import Ollama
from langchain.chains import RetrievalQA
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
# 1. LLMの設定(Ollama経由)
llm = Ollama(
model="mistral:7b-instruct-q4_K_M",
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
temperature=0.2 # 創造性を低めに設定
)
# 2. 既存のベクトルストアを読み込む(永続化した場合)
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
# 3. RetrievalQAチェーンの構築
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 検索結果をそのままプロンプトに「詰め込む」方式
retriever=vectorstore.as_retriever(
search_kwargs={"k": 3} # 上位3件を取得
),
return_source_documents=True, # ソース文書も返す
verbose=True # 処理の詳細を表示
)
# 4. 質問の実行
query = "この文書で説明されている主要な技術は何ですか?"
result = qa_chain({"query": query})
print("nn回答:", result["result"])
print("n参照されたソース文書:")
for i, doc in enumerate(result["source_documents"]):
print(f"[{i+1}] {doc.page_content[:200]}...") # 最初の200文字を表示
【よくあるエラー】 ValueError: Check your openai api key or model name.のようなエラーがLangChain内部で出る場合、古いバージョンのChatOpenAIがデフォルトで呼び出されている可能性があります。Ollamaクラスを明示的に使用しているか確認してください。また、chain_type="stuff"は検索結果が長すぎるとコンテキストウィンドウを超えるエラーが発生します。その場合はchain_type="map_reduce"などを検討します。
コード例・コマンド例まとめ
完全な動作スクリプト例 (main.py)
import sys
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.llms import Ollama
from langchain.chains import RetrievalQA
def create_vector_store(pdf_path):
"""PDFからベクトルストアを作成"""
loader = PyPDFLoader(pdf_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
split_docs = text_splitter.split_documents(documents)
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(split_docs, embeddings, persist_directory="./chroma_db")
return vectorstore
def ask_question(query):
"""ベクトルストアに対して質問する"""
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
llm = Ollama(model="mistral:7b-instruct-q4_K_M", temperature=0.2)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True
)
return qa_chain({"query": query})
if __name__ == "__main__":
# 初回のみ:ベクトルストア作成
# create_vector_store("your_document.pdf")
# 質問実行
result = ask_question("あなたの質問をここに書く")
print("回答:", result["result"])
トラブルシューティングコマンド集
# Ollama関連
ollama ps # 実行中のモデルを確認
ollama stop # モデルを停止
curl http://localhost:11434/api/tags # API経由でモデルリスト取得(接続確認用)
# ChromaDB関連(永続化データのリセット)
rm -rf ./chroma_db # ベクトルストアを完全削除(再構築時)
# Python環境確認
pip list | grep -E "langchain|chroma|ollama" # インストール済みパッケージ確認
python -c "import chromadb; print(chromadb.__version__)" # ChromaDBバージョン確認
まとめ・補足情報
Ollama、ChromaDB、LangChainを用いたローカルRAG構築は、初期設定での環境問題を乗り越えれば、非常に強力でプライベートなAIアシスタントシステムを構築できます。成功のポイントは以下の通りです。
- バージョン固定: 特にLangChainは更新が早いため、
requirements.txtでバージョンを明示的に固定し、再現性を確保しましょう。 - 段階的デバッグ: いきなりフルチェーンを実行せず、文書読み込み→分割→ベクトル化→検索→LLM呼び出しの各ステップを個別にテストし、問題を切り分けます。
- リソース管理: 使用するLLMモデルと埋め込みモデルは、ローカルマシンのメモリ(RAM)とGPU VRAM容量に合わせて選択してください。軽量モデル(例:Phi-3, Llama 3.1 8B, Gemma 2B)から始めるのが無難です。
- 日本語特化対応: 日本語文書を扱う場合は、埋め込みモデルに
multilingual-e5-largeをOllamaで利用する(ollama pull heiku/multilingual-e5-large)か、langchain_community.embeddingsのSentenceTransformerEmbeddingsで日本語対応モデル(例:`intfloat/multilingual-e5-large`)を指定するなどの工夫が必要です。
本記事で紹介した手順とトラブルシューティングを参考に、データを活用した自律的なローカルAIアプリケーションの構築に挑戦してみてください。環境構築が完了したら、Webインターフェース(GradioやStreamlit)の追加や、検索アルゴリズムのカスタマイズなど、次のステップへ進むことができます。