ローカルLLMとRAG構築における問題の概要
生成AIの実践的なアプリケーションとして注目されるRAG(Retrieval-Augmented Generation)を、ローカル環境でOllama、ChromaDB、LangChainを使って構築しようとする際、開発者、特に初心者から中級者の方は様々なエラーや課題に直面します。これらは、環境構築の複雑さ、ライブラリ間のバージョン非互換性、メモリ不足、そして設定ミスに起因することがほとんどです。具体的には、「モデルのダウンロード失敗」、「ベクトルデータベースとの接続エラー」、「LangChainのDeprecationWarning」、「CUDA/GPU関連のエラー」などが頻発します。本記事では、これらの問題を未然に防ぎ、スムーズにRAGシステムを構築するための実践的な手順とトラブルシューティングを詳細に解説します。
RAG構築失敗の主な原因
ローカルRAG構築の失敗は、主に以下の4つのカテゴリに分類されます。
1. 環境構築と依存関係の不整合
Ollama、ChromaDB、LangChainはそれぞれ独立して開発が進んでおり、使用するバージョンによって互換性が失われることがあります。特にLangChainは更新が頻繁で、わずか数ヶ月でAPIが非推奨(deprecated)となることが珍しくありません。古いチュートリアルに沿ってコードを書くと、ImportError や DeprecationWarning が発生します。
2. リソース(メモリ/ストレージ)不足
Ollamaで7Bパラメータ規模のLLMを動かすには、少なくとも8GB以上のRAMが必要です。さらに、文書を embedding 化してChromaDBに保存するプロセスでは、追加のメモリを消費します。ストレージについても、モデルファイル自体が数GBのサイズとなるため、空き容量不足がダウンロードエラーの原因となります。
3. モデルやEmbedding関数の不適切な選択
Ollamaで利用可能なモデルと、LangChainでChromaDBと連携させるための embedding モデルは別物です。ここを混同すると、「入力されたテキストをベクトル化できない」というエラーが発生します。また、英語用に最適化された embedding モデルで日本語テキストを処理すると、検索精度が著しく低下します。
4. ネットワークとプロキシ設定
Ollamaの初期モデルダウンロードや、Hugging Faceからの embedding モデルの取得時、企業内ネットワークなどではプロキシ設定が阻害要因となることがあります。エラーメッセージが接続タイムアウトを示す場合、この可能性が高いです。
ステップバイステップ解決手順
以下に、Ubuntu 20.04/22.04 または WSL2 環境を想定した、堅牢な構築手順を示します。各ステップで確認すべきポイントを明記します。
ステップ1: 基盤環境の準備
まず、Python仮想環境を作成し、基本的なツールをインストールします。これにより、プロジェクトごとの依存関係を分離できます。
# Python仮想環境の作成と有効化
python3 -m venv rag_venv
source rag_venv/bin/activate # Windows: rag_venvScriptsactivate
# 必須ツールのインストール(Ollama)
# Ubuntu/WSLの場合
curl -fsSL https://ollama.com/install.sh | sh
# インストール確認
ollama --version
# 期待する出力: "ollama version x.x.x"
トラブルシューティング: curl: (7) Failed to connect to ollama.com port 443 というエラーが出る場合は、プロキシ環境下にいる可能性があります。シェルのプロキシ設定を確認してください。
ステップ2: LLMモデルのダウンロードと起動 (Ollama)
軽量で性能バランスの取れたモデル(例: Llama 3.1 8B)をプルします。まずはCPUモードで動作確認します。
# モデルのダウンロード(初回実行時)
ollama pull llama3.1:8b
# モデルが正常にダウンロードされたかリストで確認
ollama list
# モデルをサーバーモードで起動(別ターミナルで実行推奨)
ollama serve
# 別のターミナルで対話的に動作確認
ollama run llama3.1:8b
トラブルシューティング: Error: pull model manifest: ... no such host はネットワーク問題。 Error: insufficient RAM available はメモリ不足です。後者の場合は、より小さいモデル(例: llama3.2:3b や mistral:7b-instruct)を試してください。
ステップ3: Pythonライブラリのインストールとバージョン固定
互換性が保証されるバージョンの組み合わせをインストールします。以下は2024年後半時点で安定した組み合わせです。
pip install --upgrade pip
pip install langchain==0.1.10
pip install langchain-community==0.0.20
pip install chromadb==0.4.22
pip install sentence-transformers==2.2.2
pip install pypdf # PDF読み込み用
pip install langchain-chroma # LangChainとChromaDBの統合用
重要: langchain のバージョンによっては、Chroma のインポート方法が from langchain.vectorstores import Chroma から from langchain_chroma import Chroma に変わっています。本記事では後者を使用します。
ステップ4: 日本語対応Embeddingモデルの準備
日本語テキストのベクトル化には、多言語対応または日本語特化のモデルが必須です。intfloat/multilingual-e5-large は強力ですが重いため、ローカルでは sentence-transformers モデルが現実的です。
from langchain.embeddings import HuggingFaceEmbeddings
# 軽量で日本語性能が比較的良好なモデル
model_name = "intfloat/multilingual-e5-small" # または "cl-nagoya/sup-simcse-ja-large"
embeddings = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs={'device': 'cpu'}, # GPUがあれば 'cuda'
encode_kwargs={'normalize_embeddings': True}
)
# テスト
test_vector = embeddings.embed_query("これはテスト文章です。")
print(f"ベクトル次元数: {len(test_vector)}")
エラー例と解決: OSError: Unable to load weights from pytorch checkpoint file は、モデルファイルのダウンロード失敗。インターネット接続を確認し、場合によっては手動でHugging Faceからダウンロードする必要があります。
ステップ5: 文書の読み込み、分割、ベクトルDBへの格納
PDFやテキストファイルを読み込み、適切なサイズに分割してChromaDBに保存します。
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
# 1. 文書の読み込み(例: sample.pdf)
loader = PyPDFLoader("./sample.pdf") # ファイルパスを指定
documents = loader.load()
# 2. 文書の分割(チャンキング)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 1チャンクの文字数(目安)
chunk_overlap=50, # 重複文字数
separators=["nn", "n", "。", "、", " ", ""] # 日本語に配慮
)
split_docs = text_splitter.split_documents(documents)
print(f"元のドキュメント数: {len(documents)}, 分割後チャンク数: {len(split_docs)}")
# 3. ChromaDBへの永続化保存
persist_directory = "./chroma_db"
vectordb = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory=persist_directory
)
vectordb.persist() # ディスクに保存
print(f"ベクトルDBが {persist_directory} に保存されました。")
ステップ6: Ollama LLMと連携したRAGチェーンの構築
保存したベクトルDBから類似文書を検索し、その結果をコンテキストとしてLLMに渡すチェーンを構築します。
from langchain.llms import Ollama
from langchain.chains import RetrievalQA
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
# 1. 保存済みのベクトルDBを読み込み
vectordb = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
retriever = vectordb.as_retriever(search_kwargs={"k": 3}) # 上位3件を取得
# 2. Ollama LLMの設定
llm = Ollama(
model="llama3.1:8b",
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
temperature=0.2 # 創造性を低めに設定
)
# 3. RAGチェーンの作成
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 単純にコンテキストを連結
retriever=retriever,
return_source_documents=True, # ソース文書も返す
verbose=True # 処理の詳細を表示
)
# 4. 質問の実行
query = "ドキュメントで説明されている主要な技術は何ですか?"
result = qa_chain({"query": query})
print("nn回答:", result["result"])
print("n参照されたソース文書:")
for doc in result["source_documents"][:2]: # 上位2件を表示
print(f"- {doc.page_content[:200]}...")
よくあるエラー: ConnectionError: HTTPConnectionPool(host='localhost', port=11434): Max retries exceeded は、ollama serve が起動していないか、別のポートを使用しています。Ollamaサーバーの起動状態を確認してください。
まとめと補足情報
Ollama、ChromaDB、LangChainを用いたローカルRAGシステムの構築は、環境の初期設定とライブラリのバージョン管理が成功の鍵を握ります。本記事で紹介した手順とバージョン組み合わせは、現在の安定性を考慮したものです。構築後は、以下の点をさらに調整することで、システムの性能を向上させることができます。
- チャンキング戦略の最適化:
chunk_sizeとchunk_overlapは、文書の性質(技術文書、会話録、ニュース記事など)に応じて調整が必要です。小さすぎると文脈が失われ、大きすぎると検索精度とLLMの処理負荷が高まります。 - 高度な検索手法の導入: 単純な類似度検索(
similarity_search)に加え、MMR (Max Marginal Relevance)を用いることで、検索結果の多様性を保ちつつ関連性を高められます。 - プロンプトの改良:
RetrievalQAのデフォルトプロンプトをカスタマイズし、「答えがわからない場合は『わかりません』と答える」などの指示を加えることで、LLMの幻覚(hallucination)を抑制できます。
ローカル環境で完全に動作するRAGシステムを構築することは、データの機密性を保ちながら、特定の知識に基づいた高精度なAIアシスタントを開発するための強力な第一歩となります。本記事がその実現の助けとなれば幸いです。