LlamaIndex のコア概念を図解で理解:Data Loader/Index/Retriever/Query Engine
LLM(大規模言語モデル)を活用したアプリケーション開発において、自社データや外部データと LLM を効率的に連携させることは非常に重要です。LlamaIndex は、この課題を解決するための強力なフレームワークとして注目を集めています。
本記事では、LlamaIndex の中核を成す 4 つのコンポーネント——Data Loader、Index、Retriever、Query Engine——について、図解を交えながら初心者の方にもわかりやすく解説いたします。これらの概念を理解することで、効率的な RAG(Retrieval-Augmented Generation)システムを構築できるようになるでしょう。
背景
LLM とデータ連携の重要性
LLM は膨大な知識を持っていますが、最新情報や企業固有のデータにはアクセスできません。ChatGPT や Claude などの LLM に自社のドキュメントや最新情報を活用させるためには、外部データを効果的に取り込む仕組みが必要です。
RAG アーキテクチャの登場
RAG(Retrieval-Augmented Generation)は、LLM の回答生成時に関連する外部データを検索・取得し、それを基に回答を生成する手法です。この仕組みにより、LLM は常に最新かつ正確な情報を基にした回答が可能になります。
LlamaIndex の役割
LlamaIndex は、RAG システムを簡単に構築するための Python ライブラリです。データの読み込みからインデックス作成、検索、回答生成まで、一連のプロセスを統一されたインターフェースで提供してくれます。
以下の図は、LlamaIndex における基本的なデータフローを示しています。
mermaidflowchart LR
raw["生データ<br/>(PDF/Web/DB)"] -->|読み込み| loader["Data Loader"]
loader -->|ドキュメント化| docs["Documents"]
docs -->|構造化・保存| index["Index"]
index -->|検索| retriever["Retriever"]
retriever -->|関連情報取得| engine["Query Engine"]
user["ユーザー"] -->|質問| engine
engine -->|LLM 活用| llm["LLM"]
llm -->|回答生成| engine
engine -->|回答| user
この図から、データが段階的に処理され、最終的にユーザーの質問に対する回答が生成される流れがわかりますね。
図で理解できる要点:
- データは Data Loader から始まり、段階的に変換される
- Index がデータを構造化し、効率的な検索を可能にする
- Retriever と Query Engine が連携してユーザーの質問に回答する
課題
データソースの多様性
現代のアプリケーションでは、PDF、Web ページ、データベース、API など、さまざまな形式のデータを扱う必要があります。それぞれのデータソースには異なるアクセス方法や形式があり、統一的に処理することが困難です。
大量データの効率的な検索
数千、数万のドキュメントから関連情報を素早く見つけ出すには、適切なインデックス構造と検索アルゴリズムが必要になります。単純な全文検索では、応答時間やコストの面で課題が生じるでしょう。
LLM との効果的な連携
LLM には入力トークン数の制限があり、すべてのデータを一度に渡すことはできません。必要な情報だけを的確に選択し、LLM に渡す仕組みが求められます。
以下の図は、これらの課題がどのように関連しているかを示しています。
mermaidflowchart TD
challenge["RAG システムの課題"]
challenge --> c1["データソースの多様性"]
challenge --> c2["大量データの効率的な検索"]
challenge --> c3["LLM との効果的な連携"]
c1 --> s1["異なる形式の統一処理"]
c2 --> s2["高速な検索アルゴリズム"]
c3 --> s3["トークン制限への対応"]
s1 --> solution["LlamaIndex の<br/>4 つのコア概念"]
s2 --> solution
s3 --> solution
図で理解できる要点:
- 3 つの主要課題が相互に関連している
- それぞれの課題に対する個別の解決策が必要
- LlamaIndex のコア概念がこれらを統合的に解決する
解決策
LlamaIndex は、4 つのコア概念を通じて上記の課題を解決します。それぞれのコンポーネントが明確な役割を持ち、連携することで強力な RAG システムを実現できるのです。
Data Loader(データローダー)
Data Loader は、多様なデータソースから情報を読み込み、LlamaIndex が扱える統一形式(Document オブジェクト)に変換する役割を担います。
主な特徴:
- 100 種類以上のデータソースに対応
- PDF、Word、Markdown、Web ページ、データベースなど
- LlamaHub からさまざまなローダーを利用可能
提供される情報:
- テキストコンテンツ
- メタデータ(作成日時、著者、URL など)
- ドキュメント ID
Index(インデックス)
Index は、読み込んだドキュメントを効率的に検索可能な構造に変換し、保存します。ベクトル埋め込みを活用することで、意味的な類似性に基づく検索を実現できるのです。
主なインデックスタイプ:
- VectorStoreIndex:ベクトル埋め込みを使った類似度検索
- ListIndex:シンプルなリスト形式
- TreeIndex:階層的な木構造
- KeywordTableIndex:キーワードベースの検索
Retriever(リトリーバー)
Retriever は、ユーザーの質問に関連する情報をインデックスから検索・取得します。検索戦略をカスタマイズすることで、より精度の高い情報取得が可能になります。
主な検索戦略:
- Top-K 検索:類似度が高い上位 K 件を取得
- 類似度閾値フィルタリング:一定以上の類似度を持つもののみ取得
- ハイブリッド検索:ベクトル検索とキーワード検索の組み合わせ
Query Engine(クエリエンジン)
Query Engine は、Retriever が取得した情報と LLM を組み合わせて、ユーザーの質問に対する回答を生成します。プロンプトテンプレートや回答生成ロジックをカスタマイズできるため、用途に応じた柔軟な対応が可能です。
以下の図は、4 つのコンポーネントがどのように連携するかを詳しく示しています。
mermaidsequenceDiagram
participant User as ユーザー
participant QE as Query Engine
participant Ret as Retriever
participant Idx as Index
participant LLM as LLM
User->>QE: 質問を送信
QE->>Ret: 関連情報を要求
Ret->>Idx: クエリ実行
Idx-->>Ret: 関連ドキュメント返却
Ret-->>QE: コンテキスト情報返却
QE->>LLM: プロンプト送信<br/>(質問+コンテキスト)
LLM-->>QE: 回答生成
QE-->>User: 最終回答返却
図で理解できる要点:
- ユーザーの質問が複数のコンポーネントを経由して処理される
- Retriever と Index の連携により効率的な情報取得が実現される
- Query Engine が全体のオーケストレーションを担当する
具体例
実際のコードを通じて、4 つのコア概念がどのように使われるかを見ていきましょう。段階的に説明していきます。
ステップ 1:必要なライブラリのインポート
まず、LlamaIndex の必要なモジュールをインポートします。
typescript// 必要なモジュールのインポート
import {
VectorStoreIndex,
SimpleDirectoryReader,
Settings,
} from 'llamaindex';
TypeScript でも LlamaIndex を使用できますが、Python の方が機能が豊富です。以降は Python での実装例を示します。
python# 必要なモジュールのインポート
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
ステップ 2:LLM と埋め込みモデルの設定
LlamaIndex で使用する LLM と埋め込みモデルを設定します。
python# LLM の設定(OpenAI の GPT-4 を使用)
Settings.llm = OpenAI(
model="gpt-4",
temperature=0.1 # 回答の一貫性を高めるため低めに設定
)
# 埋め込みモデルの設定
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-3-small"
)
この設定により、ベクトル化と回答生成に使用するモデルが決まります。
ステップ 3:Data Loader でデータを読み込む
Data Loader の実装例:
SimpleDirectoryReader を使用して、ディレクトリ内のドキュメントを読み込みます。
python# ドキュメントの読み込み
# ./data ディレクトリ内のすべてのファイルを対象とする
documents = SimpleDirectoryReader(
input_dir="./data",
recursive=True # サブディレクトリも再帰的に読み込む
).load_data()
# 読み込んだドキュメント数を確認
print(f"読み込んだドキュメント数: {len(documents)}")
各ドキュメントには、テキスト内容とメタデータが含まれています。
ステップ 4:Index でドキュメントをインデックス化
Index の実装例:
読み込んだドキュメントから VectorStoreIndex を作成します。
python# VectorStoreIndex の作成
# ドキュメントが自動的にベクトル化され、インデックスに保存される
index = VectorStoreIndex.from_documents(
documents,
show_progress=True # 進捗バーを表示
)
# インデックスを永続化(次回読み込みを高速化)
index.storage_context.persist(persist_dir="./storage")
インデックスの作成には時間がかかる場合があるため、永続化しておくと便利です。
ステップ 5:既存のインデックスを読み込む(オプション)
既に作成したインデックスを再利用する場合は、以下のように読み込めます。
pythonfrom llama_index.core import StorageContext, load_index_from_storage
# 保存済みのインデックスを読み込む
storage_context = StorageContext.from_defaults(
persist_dir="./storage"
)
index = load_index_from_storage(storage_context)
ステップ 6:Retriever でカスタム検索を実装
Retriever の実装例:
インデックスから Retriever を取得し、検索パラメータをカスタマイズします。
python# Retriever の取得
retriever = index.as_retriever(
similarity_top_k=3, # 上位 3 件を取得
similarity_cutoff=0.7 # 類似度 0.7 以上のみ取得
)
# 検索の実行
query = "LlamaIndex の主な特徴は何ですか?"
retrieved_nodes = retriever.retrieve(query)
# 取得したノードの確認
for i, node in enumerate(retrieved_nodes):
print(f"\n--- 検索結果 {i+1} ---")
print(f"スコア: {node.score:.3f}")
print(f"テキスト: {node.text[:200]}...")
この例では、類似度が高い上位 3 件のノードを取得しています。
ステップ 7:Query Engine で質問に回答
Query Engine の実装例:
インデックスから Query Engine を作成し、質問に対する回答を生成します。
python# Query Engine の作成
query_engine = index.as_query_engine(
similarity_top_k=3, # Retriever の設定
response_mode="compact" # 回答生成モード
)
# 質問の実行
response = query_engine.query(
"LlamaIndex を使うメリットを 3 つ教えてください"
)
# 回答の表示
print(f"回答: {response.response}")
response_mode には以下のオプションがあります:
| # | モード | 説明 |
|---|---|---|
| 1 | compact | 複数のチャンクをまとめて LLM に送信 |
| 2 | refine | 各チャンクを順次処理して回答を洗練 |
| 3 | tree_summarize | 階層的に要約を作成 |
| 4 | simple_summarize | シンプルな要約生成 |
ステップ 8:カスタムプロンプトの使用
Query Engine のプロンプトをカスタマイズすることで、回答の形式や内容を制御できます。
pythonfrom llama_index.core import PromptTemplate
# カスタムプロンプトテンプレートの定義
template = (
"以下のコンテキスト情報を参考にしてください。\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"上記の情報を基に、次の質問に日本語で簡潔に答えてください。\n"
"質問: {query_str}\n"
"回答: "
)
qa_template = PromptTemplate(template)
プロンプトテンプレートを Query Engine に適用します。
python# カスタムプロンプトを使用した Query Engine の作成
query_engine = index.as_query_engine(
text_qa_template=qa_template,
similarity_top_k=3
)
# 質問の実行
response = query_engine.query(
"RAG システムの利点を説明してください"
)
print(response.response)
ステップ 9:ストリーミングレスポンスの実装
リアルタイムで回答を表示したい場合は、ストリーミング機能を使用できます。
python# ストリーミング対応の Query Engine を作成
query_engine = index.as_query_engine(
streaming=True,
similarity_top_k=3
)
# ストリーミングで質問を実行
streaming_response = query_engine.query(
"LlamaIndex の使い方を教えてください"
)
# リアルタイムで回答を表示
for text in streaming_response.response_gen:
print(text, end="", flush=True)
この実装により、ChatGPT のようなリアルタイム表示が可能になります。
完全な実装例
ここまでの内容をまとめた完全な実装例を示します。
pythonfrom llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
Settings,
StorageContext,
load_index_from_storage
)
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
import os
# API キーの設定
os.environ["OPENAI_API_KEY"] = "your-api-key-here"
# LLM と埋め込みモデルの設定
Settings.llm = OpenAI(model="gpt-4", temperature=0.1)
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-3-small"
)
データの読み込みとインデックス作成を行います。
python# Data Loader: ドキュメントの読み込み
documents = SimpleDirectoryReader(
input_dir="./data",
recursive=True
).load_data()
print(f"読み込んだドキュメント数: {len(documents)}")
# Index: ベクトルインデックスの作成
index = VectorStoreIndex.from_documents(
documents,
show_progress=True
)
# インデックスの永続化
index.storage_context.persist(persist_dir="./storage")
Retriever と Query Engine を使用して質問に回答します。
python# Query Engine の作成
query_engine = index.as_query_engine(
similarity_top_k=3,
response_mode="compact"
)
# 質問と回答
questions = [
"このドキュメントの主なトピックは何ですか?",
"具体的な実装例を教えてください",
"注意すべきポイントはありますか?"
]
for question in questions:
print(f"\n質問: {question}")
response = query_engine.query(question)
print(f"回答: {response.response}\n")
print("-" * 50)
この実装により、4 つのコア概念を統合した完全な RAG システムが構築できました。
以下の図は、実装における処理の流れを示しています。
mermaidstateDiagram-v2
[*] --> Setup: 初期設定
Setup --> LoadData: Data Loader
LoadData --> CreateIndex: Index 作成
CreateIndex --> SaveIndex: 永続化
SaveIndex --> LoadIndex: 読み込み
LoadIndex --> CreateRetriever: Retriever 作成
CreateRetriever --> CreateQueryEngine: Query Engine 作成
CreateQueryEngine --> ProcessQuery: 質問処理
ProcessQuery --> RetrieveContext: コンテキスト取得
RetrieveContext --> GenerateResponse: LLM で回答生成
GenerateResponse --> ReturnAnswer: 回答返却
ReturnAnswer --> ProcessQuery: 次の質問
ReturnAnswer --> [*]: 終了
図で理解できる要点:
- 初期設定からデータ読み込み、インデックス作成までが一連の流れ
- 一度インデックスを作成すれば、読み込みから開始できる
- 質問処理は繰り返し実行可能
まとめ
本記事では、LlamaIndex の 4 つのコア概念について詳しく解説してまいりました。それぞれの役割と連携を理解することで、効率的な RAG システムを構築できるようになります。
4 つのコア概念のまとめ:
| # | コンポーネント | 役割 | 主な機能 |
|---|---|---|---|
| 1 | Data Loader | データ読み込み | 多様なデータソースから統一形式で読み込み |
| 2 | Index | データ構造化 | ベクトル化して検索可能な形式で保存 |
| 3 | Retriever | 情報検索 | 質問に関連する情報を効率的に取得 |
| 4 | Query Engine | 回答生成 | LLM と連携して質問に回答 |
実装のポイント:
- Data Loader で多様なデータソースに対応できる
- Index の永続化により、再起動時の処理を高速化できる
- Retriever のパラメータ調整で検索精度を向上できる
- Query Engine のカスタマイズで用途に応じた回答形式を実現できる
LlamaIndex を使用することで、複雑な RAG システムをシンプルなコードで実装できます。まずは小規模なデータセットから始めて、徐々に機能を拡張していくことをお勧めいたします。
今後は、より高度な機能として、カスタムノードパーサーの実装や、複数のインデックスを組み合わせた検索、エージェント機能の活用なども検討してみてくださいね。
関連リンク
articleHaystack と LangChain/LlamaIndex 徹底比較:設計思想・拡張性・学習コスト
articleLlamaIndex のコア概念を図解で理解:Data Loader/Index/Retriever/Query Engine
articleLlamaIndex トラブルシュート大全:検索ヒットしない・幻覚が増える時の対処
articleLlamaIndex の可観測性運用:Tracing/Telemetry/失敗ケースの可視化
articleLlamaIndex と LangChain を徹底比較:開発速度・可観測性・精度ベンチ
articleLlamaIndex で社内ナレッジ QA ボット:権限別回答と出典表示で信頼性担保
articleWebSocket Close コード早見表:正常終了・プロトコル違反・ポリシー違反の実務対応
articleStorybook 品質ゲート運用:Lighthouse/A11y/ビジュアル差分を PR で自動承認
articleWebRTC で高精細 1080p/4K 画面共有:contentHint「detail」と DPI 最適化
articleSolidJS フォーム設計の最適解:コントロール vs アンコントロールドの棲み分け
articleWebLLM 使い方入門:チャット UI を 100 行で実装するハンズオン
articleShell Script と Ansible/Make/Taskfile の比較:小規模自動化の最適解を検証
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来