AIコーディング 2026.05.16

LangChain・ChromaDB・FAISSエラー解決方法|ImportError・メモリ不足・デプロイ問題の実装ガイド

タグ:LangChain / ChromaDB / RAG / エラー対処 / ベクトルDB

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年以降のバージョンでは、チェーン周りの大規模なリファクタリングが行われています。コードが古いバージョンを想定しているか、依存関係の競合が生じている可能性があります。

切り分け手順

  1. インストール済みのLangChainバージョンを確認する

    pip show langchain
    
  2. 利用可能なクラスを確認する

    import langchain.chains
    print(dir(langchain.chains))
    
  3. 別の場所からインポートされていないか確認

    # LangChainの新バージョンでの正しいインポート方法を試す
    from langchain_core.runnables import RunnablePassthrough
    from langchain.chains import create_retrieval_chain
    

対処方法(優先度順)

1. LangChainの公式ドキュメントで現在のAPIを確認(推奨)

最新のLangChainでは、create_retrieval_chainConversationalRetrievalChainなど、新しい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の基本形は単一の質問に対する回答を返すだけで、デフォルトではチャット履歴を保持しません。会話の文脈を保つには、明示的にメモリコンポーネントを追加する必要があります。また、ドキュメント検索と会話履歴の組み合わせで、プロンプトの書き方に工夫が必要になります。

切り分け手順

  1. 現在のメモリ設定を確認する

    # ConversationalRetrievalChainを使っているか?
    # 明示的なメモリオブジェクトは設定されているか?
    print(chain.memory)  # Noneなら未設定
    
  2. プロンプトテンプレートの内容を確認する

    print(chain.llm_chain.prompt.template)
    # chat_historyや{history}が含まれているか?
    
  3. テスト実行してログを見る

    # 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の基本的な使い方は開発向けで、永続化やマルチプロセスアクセスへの対応が十分ではありません。本番環境では、ベクトルデータの永続ストレージ、複数インスタンス間でのデータ共有、メモリ効率の向上が必要になります。

切り分け手順

  1. 現在のChromaDB設定を確認する

    import chromadb
    client = chromadb.Client()  # メモリのみモード
    collection = client.get_or_create_collection("my_collection")
    # プロセス終了後、このデータは消える
    
  2. 永続化の有無を確認する

    # 永続化ディレクトリが作成されているか?
    import os
    print(os.path.exists("./chroma_data"))
    
  3. 本番環境のリソース使用状況を確認する

    # メモリ使用量を監視
    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を使う必要があります。

切り分け手順

  1. 現在の実装を確認する

    from langchain.chains import RetrievalQA
    qa = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)
    # このQAオブジェクトは memory 属性を持たない
    
  2. 必要な機能を整理する

    • メモリが必要か?→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点が重要です:

  1. バージョンを明示的に管理する:LangChainは変化が早いため、requirements.txtpyproject.tomlでバージョンを固定することで、将来のエラーを回避できます。

  2. 本番環境の構成を早期に検討する:ChromaDBの永続化、HTTPサーバーモードなど、開発環境では見えない要件が本番環境で顕在化します。早めにプロトタイピングしておくことが重要です。

  3. 公式ドキュメントと実例を常に確認する:StackOverflowやGitHubのIssueには、同じ問題に困った開発者による解決策が記録されています。エラーが出たら、まずは検索して、同じ症状の報告がないか確認する癖をつけておくと、問題解決が早くなります。

参考ソース