🤖
AI・機械学習

RAG構築手順をLangChainとPythonで徹底解説!基礎から実践、最適化まで

#RAG構築 #LangChain #Python #LLM #ベクトルストア
AI

ヨミアゲAI編集部

AI音声・動画制作に関する情報をお届けします

RAGシステム構築の基礎とLangChainの役割

RAG (Retrieval Augmented Generation) は、大規模言語モデル (LLM) が外部の知識ベースから情報を検索し、その情報を基に回答を生成する技術です。これにより、LLMの幻覚(ハルシネーション)を抑制し、特定ドメインの最新かつ正確な情報に基づいた応答を可能にします。本記事では、LangChainとPythonを用いてRAGシステムを構築する具体的な手順を、2026年4月時点のベストプラクティスに基づいて解説します。

LangChainは、LLMアプリケーション開発を効率化するためのフレームワークであり、データのロード、分割、埋め込み、ベクトルストアとの連携、プロンプト管理、チェーン構築など、RAGに必要な様々なコンポーネントを提供します。

ステップバイステップ!RAGシステムの実装

1. 環境構築

まず、必要なライブラリをインストールします。LangChainの主要パッケージと、OpenAIのモデルを使用するためのライブラリ、そしてローカルベクトルストアとしてChromaDBを使用するためのライブラリをインストールします。

pip install langchain==0.1.17 langchain-community==0.0.30 langchain-openai==0.1.1 chromadb==0.4.24 pypdf==4.0.1

💡 ポイント: pypdfはPDFファイルを読み込む際に必要です。他のファイル形式(.txt, .docxなど)を扱う場合は、それぞれの形式に対応するライブラリを追加してください。

環境変数にOpenAI APIキーを設定します。

import os
os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY"

2. ドキュメントの読み込みと分割

RAGシステムの中核となるのは、外部知識ベースのドキュメントです。ここでは、PDFファイルを読み込み、LLMが処理しやすいように小さなチャンクに分割します。

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# ドキュメントの読み込み
loader = PyPDFLoader("path/to/your/document.pdf")
documents = loader.load()

# ドキュメントの分割
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,  # 1チャンクあたりの最大文字数
    chunk_overlap=100 # チャンク間のオーバーラップ文字数
)
split_documents = text_splitter.split_documents(documents)

print(f"元のドキュメント数: {len(documents)}")
print(f"分割後のチャンク数: {len(split_documents)}")

⚠️ 注意: chunk_sizechunk_overlapの最適な値は、ドキュメントの内容やLLMのコンテキストウィンドウによって異なります。一般的に、chunk_sizeは500〜1500文字、chunk_overlapは50〜200文字が推奨されます。

3. 埋め込みとベクトルストアの構築

分割されたドキュメントチャンクを数値ベクトル(埋め込み)に変換し、ベクトルデータベースに保存します。これにより、ユーザーの質問(クエリ)と関連性の高いドキュメントチャンクを高速に検索できるようになります。

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

# 埋め込みモデルの初期化
# text-embedding-ada-002 は1Kトークンあたり$0.0001のコストがかかります。
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# ベクトルストアの構築(Chromaを例に)
# persist_directoryを指定することで、ベクトルストアをディスクに永続化できます。
persist_directory = "./chroma_db"
vectorstore = Chroma.from_documents(
    documents=split_documents,
    embedding=embeddings,
    persist_directory=persist_directory
)

# 永続化したベクトルストアをロードする場合
# vectorstore = Chroma(persist_directory=persist_directory, embedding_function=embeddings)

print(f"ベクトルストアに{vectorstore._collection.count()}個のチャンクが保存されました。")

💡 ポイント: ChromaDBはローカルで手軽に利用できるベクトルストアですが、大規模なRAGシステムや分散環境では、PineconeやWeaviateといったクラウドベースのベクトルストアが適しています。Pineconeは無料枠で1つのインデックス(最大10万ベクトル)を利用可能です。

4. 質問応答チェーンの定義

ユーザーからの質問を受け取り、ベクトルストアから関連ドキュメントを検索し、それらのドキュメントと質問をLLMに渡して回答を生成するチェーンを構築します。

from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA

# LLMの初期化
# gpt-3.5-turbo は入力1Kトークンあたり$0.0005、出力1Kトークンあたり$0.0015のコストがかかります。
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# リトリーバーの作成
# 検索するドキュメントの数をkで指定します。
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# RetrievalQAチェーンの構築
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff", # "stuff"は全てのドキュメントをプロンプトに詰め込む方式
    retriever=retriever,
    return_source_documents=True # 回答生成に使用したソースドキュメントを返す
)

💡 ポイント: chain_typeにはstuffの他にmap_reduce, refine, map_rerankなどがあります。ドキュメントの量やLLMのコンテキストウィンドウに合わせて選択してください。

5. RAGシステムの実行とテスト

構築したRAGシステムに質問を投げかけ、回答と参照元ドキュメントを確認します。

query = "あなたのドキュメントに関する具体的な質問は何ですか?"
result = qa_chain.invoke({"query": query})

print(f"質問: {query}")
print(f"回答: {result['result']}")
print("\n--- 参照元ドキュメント ---")
for i, doc in enumerate(result['source_documents']):
    print(f"ドキュメント {i+1}:")
    print(f"  ソース: {doc.metadata.get('source', '不明')}")
    print(f"  ページ: {doc.metadata.get('page', '不明')}")
    print(f"  内容の冒頭: {doc.page_content[:200]}...")
    print("-" * 20)

パフォーマンス最適化とコスト管理

RAGシステムの性能と運用コストは、いくつかの要因によって大きく変動します。

チャンキング戦略

ドキュメントのチャンクサイズとオーバーラップは、検索の精度に直結します。

  • チャンクサイズが小さい: 細かい粒度で検索できるため、特定の情報を見つけやすいですが、文脈が失われる可能性があります。
  • チャンクサイズが大きい: 文脈を保持しやすいですが、関連性の低い情報も含まれやすくなり、LLMのトークン消費が増えます。
  • オーバーラップ: チャンク間の文脈の連続性を保ち、重要な情報がチャンクの境界で分断されるのを防ぎます。

最適なチャンキング戦略は試行錯誤が必要です。

LLMと埋め込みモデルの選択

使用するLLMと埋め込みモデルは、回答の品質とAPIコストに直接影響します。

モデルタイプ モデル名 2026年4月時点のコスト例 (1Kトークンあたり) 特徴
LLM gpt-3.5-turbo 入力$0.0005 / 出力$0.0015 高速、低コスト、汎用性が高い
LLM gpt-4-turbo 入力$0.01 / 出力$0.03 高品質、複雑な推論に強いがコストは高め
埋め込み text-embedding-ada-002 $0.0001 コスト効率が高く、多くのユースケースで十分な性能

💡 ポイント: コストを抑えたい場合は、OpenAIの他にGoogle GeminiやAnthropic Claudeなどのモデルも検討できます。特に、埋め込みモデルは一度生成すれば再利用できるため、大量のドキュメントを処理する際にはコスト効率の高いモデルを選ぶことが重要です。

ベクトルストアの選定

ベクトルストアは、検索速度、スケーラビリティ、可用性、そしてコストに影響します。

ベクトルストア 特徴 コスト例
ChromaDB ローカル利用、手軽に開始 無料 (ホスティングは別途)
FAISS ローカル利用、高速な検索 無料 (ホスティングは別途)
Pinecone クラウドサービス、スケーラブル 無料枠あり (1インデックス、最大10万ベクトル)
Weaviate クラウドサービス/オンプレミス、柔軟なデータモデル 無料 (セルフホスト) / 有料 (クラウド)

開発初期段階ではChromaDBやFAISSのようなローカルベクトルストアが便利ですが、本番環境ではPineconeやWeaviateなどのマネージドサービスが運用負荷を軽減し、高可用性を提供します。システムの要件に合わせて最適なベクトルストアを選択しましょう。

AI音声でナレーションを作ってみませんか?

ヨミアゲAIを試す(無料)