0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LlamaIndexによるRouter Agent開発:複数データソースを自律的に切り替えるエージェントRAGの実装方法

0
Posted at

企業のナレッジマネジメントにおいて、LLMを用いたRAG(Retrieval-Augmented Generation)の導入が急速に進んでいます。しかし、単一の巨大なベクトルデータベースから一度に検索を行う従来の「Naive RAG」方式では、社内規定やPC貸出ルールなど、多種多様なドキュメントが混在する場合に検索ノイズが増加し、検索精度の低下やハルシネーション(根拠のない回答)を招くという課題があります。

この課題を解決する画期的なアプローチが、LlamaIndexを用いた**「Router Agent(エージェントRAG)」**です。ドメインごとにインデックスを分割し、ユーザーの質問をLLMが分析して最適なナレッジソースを自律的に選択・実行させることで、検索精度を飛躍的に向上させることができます。本記事では、LlamaIndexを用いたRouter Agentの構築方法と、外部知識を効率的に取り込む実装ロードマップを解説します。

Router Agentを構成する4つのコアコンポーネント

Router Agentを構築するにあたり、理解しておくべき主要なコンポーネントは以下の4つです。

  • QueryEngine: 各データソース(就業規則、PC貸出ルールなど)に対して個別に構築されたRAG検索エンジンです。
  • QueryEngineTool: クエリエンジンをエージェント用の「ツール」としてカプセル化するクラスです。LLMが自律的に選択できるよう、ツールの役割を「説明(description)」として記述します。
  • OpenAIAgentWorker: OpenAIのFunction Calling機能を利用して、どのツールをどのような引数で呼ぶべきかという「自律的な思考」を管理する推論モジュールです。
  • AgentRunner: エージェントの状態管理やユーザーとの対話ループをコントロールする実行器です。

Router Agent実装の4ステップ

自律的にデータソースを切り替えるエージェントRAGは、以下の4つのステップで実装します。

Step 1: データの読み込みとインデックス化

性質の異なるドキュメント(就業規則のPDFや、PC貸出ルールのテキストなど)をそれぞれ個別に読み込み、個別のベクトルインデックス(VectorStoreIndex)として構築します。

Step 2: 個別クエリエンジンの構築

作成した各インデックスから、自然言語で問い合わせが可能な QueryEngine を作成します。

Step 3: QueryEngineToolによるツール化

各クエリエンジンをツールに変換します。この際、description に詳細な役割を記載することが極めて重要です。LLMはこの説明を読み、ユーザーの質問に対してどちらのツールを使うべきかを判断します。

Step 4: Router Agentの初期化と実行

OpenAIAgentWorker にツール群を渡し、AgentRunner でエージェントを起動します。これにより、ユーザーの質問に応じて自律的にソースを切り替えながら回答する対話エージェントが完成します。

Pythonによる実装コード例

以下は、LlamaIndex(v0.10.x以降)を用いたRouter Agentの具体的な実装例です。

import os
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings
from llama_index.llms.openai import OpenAI
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.agent.openai import OpenAIAgentWorker
from llama_index.core.agent import AgentRunner

# 1. APIキーの設定とLLMの初期化
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0.1)

# 2. 異なるデータソースの読み込みとインデックスの作成
# data/ 配下に rules.txt (就業規則) と pc_policy.txt (PC貸出ルール) があると想定
rules_docs = SimpleDirectoryReader(input_files=["data/rules.txt"]).load_data()
pc_docs = SimpleDirectoryReader(input_files=["data/pc_policy.txt"]).load_data()

rules_index = VectorStoreIndex.from_documents(rules_docs)
pc_index = VectorStoreIndex.from_documents(pc_docs)

# 3. クエリエンジンの作成
rules_query_engine = rules_index.as_query_engine(similarity_top_k=3)
pc_query_engine = pc_index.as_query_engine(similarity_top_k=3)

# 4. クエリエンジンを「ツール」として定義(ここでの description がルーティングの鍵)
query_engine_tools = [
    QueryEngineTool(
        query_engine=rules_query_engine,
        metadata=ToolMetadata(
            name="employment_rules_tool",
            description=(
                "会社の就業規則、福利厚生、有給休暇、勤務時間などに関する質問に答えるために使用します。"
                "入力には、ユーザーの質問をそのままテキストとして指定してください。"
            )
        )
    ),
    QueryEngineTool(
        query_engine=pc_query_engine,
        metadata=ToolMetadata(
            name="pc_rental_policy_tool",
            description=(
                "社内PCや周辺機器の貸出ルール、申請手続き、返却期限、紛失時の対応などに関する質問に答えるために使用します。"
                "入力には、ユーザーの質問をそのままテキストとして指定してください。"
            )
        )
    )
]

# 5. OpenAIAgentWorker と AgentRunner を用いた自律的エージェントの作成
agent_worker = OpenAIAgentWorker.from_tools(
    tools=query_engine_tools, 
    llm=Settings.llm,
    verbose=True  # 動作の思考プロセスを表示
)
agent = AgentRunner(agent_worker)

# 6. テスト実行
print("--- クエリ 1: PC貸出ルールへの自動ルーティング ---")
response1 = agent.chat("社内PCの貸出申請はどのように行えばよいですか?期限はありますか?")
print(f"回答: {response1}\n")

print("--- クエリ 2: 就業規則への自動ルーティング ---")
response2 = agent.chat("来月、有給休暇を3日間取得したいのですが、何日前までに申請が必要ですか?")
print(f"回答: {response2}\n")

外部知識を効率的に取り込むための応用アプローチ

構築したRouter Agentを実務レベルへスケールさせ、より複雑な社内ドキュメントや膨大なナレッジベースに対応させるためには、効率的に外部知識を取り込むためのアプローチが必要です。

1. LlamaParseの活用による高度なドキュメントパース

就業規則や申請手順書といった企業文書は、PDF形式で記述されていることが多く、その中には図表や複雑なレイアウトが含まれています。単なるテキストとして抽出すると、ドキュメントの構造が崩れて検索精度が著しく低下します。この課題に対しては、LlamaIndex公式の提供する**LlamaParse**を利用します。データをMarkdown形式にパースしてからインデックス化することで、図表や見出しの構造を維持した高品質な知識ソースを構築し、エージェントの理解度を向上させられます。

2. ObjectIndexによる動的ツール選択(数多くのツールを扱う場合)

登録するツールの数が「経費精算」「セキュリティ規定」「出張申請」など数十個以上に増えると、すべてのツールの説明をLLMのコンテキスト(プロンプト)に含めることができなくなります。これはAPIコストの増加や、LLMが迷ってしまい適切な選択ができなくなる精度の低下を招きます。この場合は、LlamaIndexの**ObjectIndex**機能を使用します。ツール自体をベクトルインデックス化することで、ユーザーの質問に親和性の高い「上位数個のツール」だけを動的に取得し、LLMに渡す構成にできます。

3. LangGraphとの協調による状態管理と自己修正ループ

より複雑な自律型RAG、例えば「検索結果が不十分だった場合に、検索クエリを書き換えて別のツールで再実行する」といった「自己修正ループ」を含む高度なエージェントを構築したい場合があります。このような、複雑な状態管理や反復処理を制御したいときには、LlamaIndexのデータ接続機能と、状態管理フレームワークである**LangGraph**を協調させる設計が強力な解決策となります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?