LangChain・ChromaDB・FAISSエラー解決方法|ImportError・メモリ不足・デプロイ問題の実装ガイド
LangChain・ChromaDB・FAISSで発生しやすいエラーと対処策
検索拡張生成(RAG)システムの開発では、LangChain・ChromaDB・FAISSなどのライブラリを組み合わせて使います。これらのツールは便利である一方で、バージョン差異やAPI変更によるエラーが頻発します。本記事では、実開発で遭遇しやすい4つの典型的な問題と解決方法をまとめました。
1. RetrievalQAのImportError:バージョン互換性の問題
症状
ImportError: cannot import name 'RetrievalQA' from 'langchain.chains' in Python project
このエラーは、LangChainのバージョンアップデートでRetrievalQAが廃止されたり、パッケージ構成が変わったときに発生します。
想定される原因
LangChainは頻繁にAPIを変更しており、古いドキュメントやサンプルコードの多くは現在の最新バージョンに対応していません。特に2024年以降のバージョンでは、チェーン周りの大規模なリファクタリングが行われています。コードが古いバージョンを想定しているか、依存関係の競合が生じている可能性があります。
切り分け手順
-
インストール済みのLangChainバージョンを確認する
pip show langchain -
利用可能なクラスを確認する
import langchain.chains print(dir(langchain.chains)) -
別の場所からインポートされていないか確認
# LangChainの新バージョンでの正しいインポート方法を試す from langchain_core.runnables import RunnablePassthrough from langchain.chains import create_retrieval_chain
対処方法(優先度順)
1. LangChainの公式ドキュメントで現在のAPIを確認(推奨)
最新のLangChainでは、create_retrieval_chainやConversationalRetrievalChainなど、新しいAPIが提供されています。古いRetrievalQAを使うのではなく、以下のように修正してください:
# 古い書き方(非推奨)
# from langchain.chains import RetrievalQA
# 新しい書き方
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("""
質問に答えてください:
{context}
質問: {input}
""")
document_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(retriever, document_chain)
2. 依存関係を明確にする
requirements.txtで明示的にバージョンを指定してください。StackOverflowに報告された事例では、複数のパッケージが異なるLangChainバージョンに依存していることが原因になることがあります:
langchain==0.1.0
langchain-core>=0.1.0
3. 仮想環境を再構築する
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install --upgrade langchain
それでも解決しないとき
- LangChainのGitHubリポジトリでIssueを検索し、同じエラーが報告されていないか確認してください
- ドキュメントのバージョンセレクタで、インストール済みバージョンに合わせた説明を読む
- 最後の手段として、古いバージョンをピン留めするのではなく、コードを新しいAPIに合わせることを強くお勧めします
2. RAGでのチャット履歴の不具合:メモリ管理とコンテキスト
症状
会話をしているのに、前のメッセージの内容を認識していない
新しい質問をするたびに、チャット履歴が失われたように見える
RAGシステムでは、会話を続けるのに必要なメモリ(チャット履歴)の管理が重要です。
想定される原因
RetrievalQAの基本形は単一の質問に対する回答を返すだけで、デフォルトではチャット履歴を保持しません。会話の文脈を保つには、明示的にメモリコンポーネントを追加する必要があります。また、ドキュメント検索と会話履歴の組み合わせで、プロンプトの書き方に工夫が必要になります。
切り分け手順
-
現在のメモリ設定を確認する
# ConversationalRetrievalChainを使っているか? # 明示的なメモリオブジェクトは設定されているか? print(chain.memory) # Noneなら未設定 -
プロンプトテンプレートの内容を確認する
print(chain.llm_chain.prompt.template) # chat_historyや{history}が含まれているか? -
テスト実行してログを見る
# 2つの会話を順番に実行し、2番目の回答に1番目の文脈が反映されているか確認 result1 = chain({"question": "私の名前はTaroです"}) result2 = chain({"question": "私の名前は?"}) print(result2["answer"]) # "Taro"と回答するか?
対処方法(優先度順)
1. ConversationalRetrievalChainを使う(推奨)
ConversationalRetrievalChainは、チャット履歴を自動的に処理します:
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
qa_chain = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=retriever,
memory=memory,
verbose=True
)
# 複数回の会話が自動的に履歴として保持される
result1 = qa_chain({"question": "LangChainの概要は?"})
result2 = qa_chain({"question": "それはどのように実装されていますか?"})
2. カスタムプロンプトを組み込む
ConversationalRetrievalChainにカスタムプロンプトを指定して、より詳細な指示を与えることができます:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
condense_question_prompt = ChatPromptTemplate.from_messages([
("system", "与えられた会話履歴とフォローアップの質問に基づいて、元のドキュメント検索クエリを作成してください。"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{question}")
])
qa_prompt = ChatPromptTemplate.from_messages([
("system", "以下の文脈に基づいて質問に回答してください:\n{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{question}")
])
qa_chain = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=retriever,
condense_question_prompt=condense_question_prompt,
combine_docs_chain_kwargs={"prompt": qa_prompt},
memory=memory
)
3. メモリタイプを選択する
用途に応じてメモリの種類を選択してください:
ConversationBufferMemory:全履歴を保持(短い会話向け)ConversationSummaryMemory:履歴を要約して保持(長い会話向け)ConversationBufferWindowMemory:最新N件を保持(リソース制約下向け)
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(
k=5, # 最新5件を保持
memory_key="chat_history",
return_messages=True
)
それでも解決しないとき
- ドキュメント検索に使うクエリが、前のターンの文脈に基づいて正しく作成されているか確認する(
condense_question_promptをデバッグする) - LLMの応答が実は正しいのに、RAGシステムの外部で履歴を失っていないか確認する(例:Webアプリケーションのセッション管理)
- メモリサイズが制限されていないか、メモリオブジェクトの設定を見直す
3. ChromaDBの本番デプロイ:永続化とスケーリング
症状
開発環境ではうまく動いていたが、本番環境でベクトルデータベースが起動しない
複数のプロセスからアクセスするとデータが競合する
メモリ使用量が多すぎて、本番サーバーでスケールしない
ChromaDBはデフォルトではメモリ内に動作し、プロセス終了時にデータが失われます。
想定される原因
ChromaDBの基本的な使い方は開発向けで、永続化やマルチプロセスアクセスへの対応が十分ではありません。本番環境では、ベクトルデータの永続ストレージ、複数インスタンス間でのデータ共有、メモリ効率の向上が必要になります。
切り分け手順
-
現在のChromaDB設定を確認する
import chromadb client = chromadb.Client() # メモリのみモード collection = client.get_or_create_collection("my_collection") # プロセス終了後、このデータは消える -
永続化の有無を確認する
# 永続化ディレクトリが作成されているか? import os print(os.path.exists("./chroma_data")) -
本番環境のリソース使用状況を確認する
# メモリ使用量を監視 ps aux | grep python df -h # ディスク容量
対処方法(優先度順)
1. ChromaDBを永続化モードで起動する(推奨)
ディスクに保存されることで、プロセス再起動後もデータが残ります:
import chromadb
from chromadb.config import Settings
# 永続ディレクトリを指定
settings = Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="./chroma_data",
anonymized_telemetry=False
)
client = chromadb.Client(settings)
collection = client.get_or_create_collection("my_collection")
# データを追加
collection.add(
ids=["doc1", "doc2"],
embeddings=[[1.1, 2.3], [4.5, 6.9]],
documents=["This is doc1", "This is doc2"]
)
# 明示的にデータを保存(オプション)
client.persist()
2. 本番環境用の設定を分離する
開発環境と本番環境で異なる設定を使い分けます:
import os
from chromadb.config import Settings
if os.getenv("ENVIRONMENT") == "production":
settings = Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="/mnt/data/chroma", # 共有ストレージ(NFS等)
anonymized_telemetry=False
)
else:
# 開発環境ではメモリ内
settings = Settings(anonymized_telemetry=False)
client = chromadb.Client(settings)
3. HTTPサーバーモードでの運用(スケーラビリティ重視)
複数のアプリケーションがChromaDBにアクセスする場合、HTTPサーバーモードで一元管理します:
# ChromaDBサーバーを起動(別プロセス)
chroma run --path /data/chroma --port 8000
# クライアント側は遠隔接続
import chromadb
client = chromadb.HttpClient(host="localhost", port=8000)
collection = client.get_or_create_collection("my_collection")
この方式により、複数のアプリケーションインスタンスが同じベクトルDBにアクセスできます。
4. ディスク容量の計画
ベクトルデータはディスク容量を消費します。本番環境では事前に必要な容量を見積もり、ストレージを確保しておきます:
# データサイズの目安:1エンベッディング(1536次元)≈ 6KB
# 100万ドキュメント = 約6GB
それでも解決しないとき
- ChromaDBの公式ドキュメントで、使用しているバージョンの永続化方法を確認する
- ファイルシステムの権限設定が正しいか確認(書き込み権限があるか)
- ディスクI/Oのボトルネックが問題なら、SSD使用やRAID構成を検討する
- 超大規模なベクトルDBが必要な場合は、Milvus・Weaviate・Pineconeなどのエンタープライズソリューションの導入を検討する
4. RetrievalQAへのメモリ追加とカスタムプロンプト
症状
RetrievalQA.from_chain_type()にメモリを追加したいが、パラメータが見当たらない
プロンプトをカスタマイズしようとしてもうまくいかない
RetrievalQAの基本的な実装では、メモリとカスタムプロンプトの追加が直感的ではありません。
想定される原因
RetrievalQA.from_chain_type()メソッドは、シンプルなQ&A用に最適化されており、複雑な設定(メモリ、カスタムプロンプト)を直接サポートしていません。その代わり、ConversationalRetrievalChainや、より低レベルのチェーン組み立てAPIを使う必要があります。
切り分け手順
-
現在の実装を確認する
from langchain.chains import RetrievalQA qa = RetrievalQA.from_chain_type(llm=llm, retriever=retriever) # このQAオブジェクトは memory 属性を持たない -
必要な機能を整理する
- メモリが必要か?→
ConversationalRetrievalChainを使う - プロンプトのカスタマイズだけか?→
RetrievalQA.from_chain_type(chain_type_kwargs={"prompt": ...})で対応可能
- メモリが必要か?→
対処方法(優先度順)
1. メモリが必要ならConversationalRetrievalChainに移行する
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
qa_chain = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=retriever,
memory=memory
)
# メモリを保持しながら複数回の質問に回答
print(qa_chain({"question": "AIとは?"}))
print(qa_chain({"question": "それはどのように学習するのか?"}))
2. メモリが不要でプロンプトのみ変更したい場合
from langchain.chains import RetrievalQA
from langchain_core.prompts import PromptTemplate
# カスタムプロンプトを定義
prompt_template = """以下の情報を使って、質問に答えてください。
詳細で正確な回答を心がけてください。
文脈:
{context}
質問:{question}
回答:"""
prompt = PromptTemplate(
input_variables=["context", "question"],
template=prompt_template
)
# RetrievalQAにプロンプトを渡す
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever,
chain_type="stuff",
chain_type_kwargs={"prompt": prompt}
)
result = qa.run("LangChainの基本的な使い方は?")
3. さらに複雑なカスタマイズが必要な場合は、低レベルAPIで組み立てる
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
system_prompt = """You are a helpful AI assistant. Answer questions based on the following context:
{context}
If you don't know the answer, say so explicitly."""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{input}")
])
document_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(retriever, document_chain)
result = retrieval_chain.invoke({"input": "What is LangChain?"})
print(result["answer"])
それでも解決しないとき
- LangChainの最新ドキュメントで、推奨される実装パターンを確認する
ConversationalRetrievalChainを使い、オプショナルなパラメータ(condense_question_promptなど)を段階的に追加していく- コミュニティのサンプルコード(GitHub、ブログなど)を参考にしながら、独自の実装に合わせていく
まとめ:開発を進める際のポイント
RAG開発で安定性を確保するには、以下の3点が重要です:
-
バージョンを明示的に管理する:LangChainは変化が早いため、
requirements.txtやpyproject.tomlでバージョンを固定することで、将来のエラーを回避できます。 -
本番環境の構成を早期に検討する:ChromaDBの永続化、HTTPサーバーモードなど、開発環境では見えない要件が本番環境で顕在化します。早めにプロトタイピングしておくことが重要です。
-
公式ドキュメントと実例を常に確認する:StackOverflowやGitHubのIssueには、同じ問題に困った開発者による解決策が記録されています。エラーが出たら、まずは検索して、同じ症状の報告がないか確認する癖をつけておくと、問題解決が早くなります。
参考ソース
- ImportError: cannot import name 'RetrievalQA' from 'langchain.chains' in Python project
- RAG model chat history does not work properly
- How to deploy chroma database (vector database) in production
- How do i add memory to RetrievalQA.from_chain_type? or, how do I add a custom prompt to ConversationalRetrievalChain?