ゼロから構築!Agentic RAGで外部ツールを自律操作するAIエージェント
「RAGを導入したけれど、いまいち複雑な質問に答えられない」「AIエージェントに自律的に動いてほしいが、どう実装すればいいかわからない」――そんな悩みを抱えていませんか?従来のRAG(Retrieval Augmented Generation)は強力ですが、単一の知識源に限定され、多段階の思考や外部ツール連携が苦手という課題がありました。
この記事では、AIエージェントに「自律的な判断能力」と「外部ツール連携」を与え、複雑なタスクを実行可能にする次世代RAGアーキテクチャ「Agentic RAG」の構築方法を、LangChain/LangGraphなどのフレームワークを使った具体的なコード例とともに解説します。この記事を読めば、あなたのAIエージェントは、まるで人間のように状況を判断し、最適な情報を探し出し、複雑な問題を解決できるようになるでしょう。
Agentic RAGとは?従来のRAGとの違い
まず、Agentic RAGが何を解決し、従来のRAGとどう異なるのかを明確にします。Agentic RAGは、LLMが単なる回答生成器としてではなく、思考エンジン兼制御タワーとして機能し、状況に応じて最適な情報源の選択、検索クエリの最適化、複数ステップの推論、自己評価と修正を行うアーキテクチャです。
従来のRAGの限界
従来のRAGは、ユーザーの質問に対し、事前に用意されたドキュメント(ベクトルDBなど)から関連情報を検索し、その情報を基にLLMが回答を生成します。シンプルで強力な反面、以下のような限界がありました。
- 単一の知識ソースに限定: 用意されたドキュメント以外の情報(最新のWeb情報、外部APIなど)は参照できない。
- ワンショット検索: 質問に対して一度きりの検索しか行わず、検索結果が不十分でも再検索やクエリ修正は行わない。
- 複雑な推論の限界: 複数ステップを要するタスクや、外部ツールを使って情報を加工・分析するような複雑な問題には対応しにくい。
- ハルシネーション(幻覚)のリスク: 検索結果が不十分な場合でも、LLMが「それっぽい」情報を生成してしまうリスクがある。
Agentic RAGが解決する課題
Agentic RAGは、AIエージェントの自律的な判断能力と外部ツール連携を組み合わせることで、これらの限界を克服します。
- 動的な情報源選択: 質問内容に応じて、社内ドキュメント、Web検索、データベース、カスタムAPIなど、最適な情報源をAIエージェントが自律的に選択・利用します。
- 多段階の思考と行動: 情報を検索し、その結果を評価し、必要であればクエリを修正して再検索する、といった多段階の思考プロセス(ReAct: Reasoning + Acting)を実行します。
- 自己評価と修正: 生成された回答や検索結果をAIエージェント自身が評価し、不十分であれば改善のための行動(再検索、回答の再生成など)を指示します。
- 複雑なタスクの実行: 複数のツールを連携させ、情報収集、分析、要約、意思決定といった複雑なタスクを、AIエージェントが自律的に実行できます。
Agentic RAGの主要フレームワークと技術要素
Agentic RAGの構築には、主にLangChain/LangGraphやLlamaIndexといったフレームワークが利用されます。これらのフレームワークは、AIエージェントの思考プロセス、ツール連携、状態管理を効率的に実装するための機能を提供します。
LangChain / LangGraph (バージョン 0.1.x 以降)
-
LangChain: LLMエージェントのフレームワークであり、ツール連携、プロンプト管理、チェイン構築をサポートします。Agentic RAGにおけるエージェントの基盤となります。
- LangChain 公式ドキュメント: エージェント、ツール、RAGに関する詳細なガイド。
-
LangGraph: LangChainをベースにしたグラフベースのオーケストレーションフレームワークです。AIエージェントの思考プロセスを「ノード」と「エッジ」で表現し、有限状態機械(Finite State Machine)としてワークフローを定義します。状態管理、分岐、再試行、人間介在を設計するための中核候補です。
- LangGraph 公式ドキュメント: グラフの構築、状態管理、エージェントの定義に関する詳細。
-
create_react_agent: ReAct(Reasoning+Acting)の考え方に基づいたエージェントを簡単に構築できる関数。 - LangGraphを用いたAgentic RAGのチュートリアル: LangChain公式ドキュメントで提供されている具体的な構築方法。
LlamaIndex (バージョン 0.10.x 以降)
- RAGのデータ連携、Index、Retriever、文書処理に強いフレームワークであり、Agentic RAGの構築にも利用されます。
-
LlamaIndex Workflows: イベント駆動型で複数ステップの処理を制御する仕組みとして利用でき、文書処理、検索パイプライン、評価、再検索のように、RAGの前後処理を段階的に組み立てる場合に相性が良いとされています。
- LlamaIndex 公式ドキュメント: エージェント、RAGパイプライン、ワークフローに関する詳細。
- DeepLearning.AI: LlamaIndexを用いたAgentic RAGの構築コース: LlamaIndexを使ったAgentic RAGの実践的な学習リソース。
その他の主要技術要素
-
Pinecone: ベクトルデータベースとして、Agentic RAGのデータ前準備やベクトル検索に利用されます。
- Pinecone 公式ドキュメント: ベクトルインデックスの作成、データの投入、クエリ実行に関する情報。
-
Tavily API: Web検索ツールとして、AIエージェントが情報不足と判断した場合のWeb検索に利用されます。LangChainのツールとして簡単に統合可能です。
- Tavily API ドキュメント: APIキーの取得、検索クエリの実行方法。
-
OpenAI API: 埋め込みモデル(Embeddings)およびLLM推論に利用されます。特にGPT-4o, GPT-4 Turboなどの高性能モデルは、AIエージェントの推論能力を向上させます。
- OpenAI API ドキュメント: モデルの利用方法、APIキーの管理、料金体系。
-
Ragas / Evals: RAGシステムの検索品質、回答品質、根拠整合性の評価に用いられ、Agentic化の前後で品質を測るために重要です。
- Ragas 公式ドキュメント: RAG評価指標、評価パイプラインの構築方法。
- LangChain Evals: LangChainエコシステムにおける評価ツール。
Agentic RAGの実装例: 環境構築とLangGraphによるワークフロー定義
ここでは、LangGraphを用いたAgentic RAGの基本的なワークフローの概念と、環境構築の例を示します。
環境構築と依存パッケージのインストール
まず、必要なライブラリをインストールし、APIキーを.envファイルに設定します。
# プロジェクトディレクトリの作成と移動
mkdir agentic_rag_project
cd agentic_rag_project
# 仮想環境の作成とアクティベート
python -m venv agentic-env
source agentic-env/bin/activate # Linux/macOS
# .\agentic-env\Scripts\activate # Windows PowerShell
# 依存パッケージのインストール (バージョンは適宜調整)
# LangChain関連は最新版を推奨 (2024年5月時点の0.1.x系)
pip install langchain==0.1.x langchain-core==0.1.x langchain-community==0.0.x langchain-openai==0.0.x
pip install langgraph==0.0.x
pip install llama-index==0.10.x
pip install pinecone-client==3.x.x
pip install tavily-python==0.3.x
pip install python-dotenv==1.x.x # .env ファイルを読み込むため
pip install ragas==0.1.x # 評価ツール
# 必要なAPIキーの設定 (.env ファイルの例)
# プロジェクトルートに .env ファイルを作成し、以下を設定
# OPENAI_API_KEY="sk-..."
# PINECONE_API_KEY="your_pinecone_api_key"
# PINECONE_ENVIRONMENT="your_pinecone_environment" # 例: us-west-2
# TAVILY_API_KEY="your_tavily_api_key"
# OPENROUTER_API_KEY="your_openrouter_api_key" # OpenRouter経由でLLMを使用する場合
LangGraphによるAIエージェントフローの概念
LangGraphでは、AIエージェントの思考プロセスをノードとエッジで表現します。これにより、複雑な状態遷移や条件分岐を持つワークフローを直感的に設計できます。
状態定義 (AgentState)
エージェントの状態を管理するためのTypedDictを定義します。これには、ユーザーの質問、検索されたドキュメント、生成された回答、評価結果などが含まれます。
from typing import List, TypedDict, Annotated
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
"""
LangGraphエージェントの状態を定義するTypedDict。
エージェントの各ステップで共有・更新される情報を含む。
"""
question: str # ユーザーの元の質問
documents: List[str] # 検索されたドキュメントのリスト
generation: str # 生成された回答
grade: str # ドキュメントまたは回答の評価結果 (例: "satisfactory", "unsatisfactory")
retry_count: int # 再試行回数 (例: クエリ再構築後に再検索する際など)
messages: Annotated[List, add_messages] # LangGraphのメッセージ履歴管理。LLMとの会話履歴を保持。
主要なノードの役割
Agentic RAGのワークフローを構成する主要なノードとその役割は以下の通りです。
-
エージェントノード (Agent Node): LLMを使用して、次に取るべきアクション(例: 検索ツールを使用するか、回答を生成するか)を判断します。LangChainの
create_react_agentやカスタムロジックを使用し、ツール呼び出しを内包します。 - 文書取得ノード (Retrieve Node): ユーザーの質問に関連する文書をベクトルデータベース(Pineconeなど)から取得します。Parent Document Retrievalやウィンドウ拡張でコンテキストの断絶を防ぐロジックを実装します。
- 評価ノード (Grade Node - CRAGの実装): 検索されたテキストが質問に対する「完全な回答」を含んでいるか、LLM(軽量モデル)に判定させます。不十分な場合は再検索やクエリ再構築を促します。これはCorrective RAG (CRAG) の主要な要素です。
- クエリ再構築ノード (Rewrite Node): 質問の意図をより明確にしたクエリをLLMに再生成させ、再検索を行います。
- 回答生成ノード (Generate Node): 十分なコンテキストが確保された状態で回答を生成します。長文の場合はTree Summarizeロジックを用いることもあります。
- 自己反省ノード (Reflect Node - Self-RAGの実装): 最終回答がハルシネーションを含んでいないか、質問に完全に答えているかを検証します。必要に応じて修正や再生成を指示します。これはSelf-RAGの主要な要素です。
ワークフロー (Graph Topology) の定義
これらのノードと遷移条件をLangGraphで定義します。例えば、検索結果が不十分な場合に再検索する、回答前に評価を挟む、といった流れをグラフ構造で表現します。
from langgraph.graph import StateGraph, END
from langchain_core.messages import HumanMessage # LangChainのメッセージ型
# ここでは各ノード関数は省略しますが、実際には以下のように定義されます。
# def retrieve(state: AgentState) -> AgentState: ...
# def grade_documents(state: AgentState) -> AgentState: ...
# def generate(state: AgentState) -> AgentState: ...
# def rewrite_query(state: AgentState) -> AgentState: ...
# def reflect(state: AgentState) -> AgentState: ...
# def agent_action_node(state: AgentState) -> AgentState: ... # LLMがツール呼び出しを判断するノード
# LangGraphのチュートリアル(https://python.langchain.com/docs/tutorials/rag_with_graph/)を参照し、
# 各ノード関数の具体的な実装を補完してください。
workflow = StateGraph(AgentState)
# ノードの追加
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_documents", grade_documents)
workflow.add_node("generate", generate)
workflow.add_node("rewrite_query", rewrite_query)
workflow.add_node("reflect", reflect)
workflow.add_node("agent_action", agent_action_node) # エージェントがツールを呼び出すノード
# エッジの定義 (条件付きエッジを含む)
# エージェントの判断から開始する
workflow.set_entry_point("agent_action")
# エージェントがツールを呼び出すか、直接回答生成を試みるかの条件分岐
workflow.add_conditional_edges(
"agent_action",
# 最後のメッセージにツール呼び出しがあるか否かで遷移を決定
lambda state: state["messages"][-1].tool_calls[0]["name"] if state["messages"][-1].tool_calls else "generate",
{
"tavily_search": "retrieve", # エージェントがTavilyを呼び出したら検索へ
"generate": "generate", # エージェントが回答生成を指示したら生成へ
# 他のツール名があればここに追加していく(例: "pinecone_search": "retrieve")
}
)
# 検索後、ドキュメントの評価へ
workflow.add_edge("retrieve", "grade_documents")
# ドキュメント評価の結果に応じて、回答生成に進むか、クエリを再構築して再検索するかを決定
workflow.add_conditional_edges(
"grade_documents",
lambda state: "generate" if state["grade"] == "satisfactory" else "rewrite_query",
{
"generate": "generate",
"rewrite_query": "rewrite_query",
}
)
# クエリ再構築後、再検索へ
workflow.add_edge("rewrite_query", "retrieve")
# 回答生成後、自己反省へ
workflow.add_edge("generate", "reflect")
# 自己反省の結果に応じて、終了するか、クエリを再構築して再試行するかを決定
workflow.add_conditional_edges(
"reflect",
lambda state: END if state["grade"] == "satisfactory" else "rewrite_query", # 反省結果で終了か再検索か
{
END: END, # 満足なら終了
"rewrite_query": "rewrite_query", # 不満足ならクエリ再構築からやり直し
}
)
# ワークフローをコンパイル
app = workflow.compile()
# 実行例(実際のノード関数が定義されている前提)
# inputs = {"question": "Agentic RAGのメリットは何ですか?", "messages": [HumanMessage(content="Agentic RAGのメリットは何ですか?")]}
# for s in app.stream(inputs):
# print(s)
このコードはLangGraphの強力な状態管理と条件分岐の概念を示しています。AIエージェントが自律的に判断し、適切なツールを呼び出し、必要に応じて思考プロセスを修正していく様子がわかるでしょう。
Agentic RAGにおけるよくあるエラー・ハマりどころと回避策
Agentic RAGは強力な一方で、その複雑さゆえに多くの課題に直面する可能性があります。ここでは、実装時によく遭遇する問題とその回避策を解説します。
1. バージョン不整合とインポートエラー
-
ハマりどころ:
langchain,langchain-core,langchain-community,langchain-openai,langgraphなどのパッケージ間でバージョン不整合が発生し、ImportErrorや予期せぬ動作につながることがあります。特にLangChainはバージョン0.1.xで大幅な変更があったため、古いコードを動かす際に問題が発生しやすいです。 -
回避策:
-
requirements.txtで厳密なバージョン指定を行い、開発環境と本番環境でバージョンを統一する。 - 新しいプロジェクトを開始する際は、最新の公式ドキュメントやチュートリアルを参照し、推奨されるバージョンを使用する。
-
pip install --upgrade <package_name>で個別にアップグレードするのではなく、pip install -r requirements.txtで一括インストールを推奨します。 - バージョンXX時点: LangChain 0.1.x系、LangGraph 0.0.x系は活発に開発が進んでいるため、公式ドキュメントの最新情報を常に確認することが重要です。
-
2. コンテキスト欠落と不正確な検索結果
- ハマりどころ: 従来のRAGと同様に、Agentic RAGでもAIエージェントの検索結果が質問の意図とずれていたり、必要な情報が欠落していたりすると、不正確な回答やハルシネーションが発生します。特に、チャンク分割が不適切だと、重要な情報が分断されてしまうことがあります。
-
回避策:
- Parent Document Retrieval / Window Retrieval: ヒットしたチャンクだけでなく、その前後のより大きなテキストブロックも取得することで、文脈の断絶を防ぎます。
- ハイブリッド検索 (Hybrid Search): ベクトル検索だけでなく、キーワード検索やメタデータフィルタリングを組み合わせることで、検索精度を向上させます。
- クエリの動的な最適化 (Query Optimization): LLMに検索クエリをリライトさせることで、より適切な検索結果を得られるようにします。これにより、AIエージェントがより洗練された検索を実行できます。
- Rerankerの導入: 検索結果の関連性を再評価し、より適切なドキュメントを上位に表示させることで、LLMに渡すコンテキストの質を高めます。
3. コストとレイテンシの増加
- ハマりどころ: Agentic RAGは、1つの質問に対して複数回の検索、評価、再検索、LLM呼び出しが発生するため、従来のRAGと比較してコストと応答速度(レイテンシ)が増加します。これはAIエージェントの自律性の代償とも言えます。
-
回避策:
-
LLMの選択: 軽量なLLMを評価ノードなどに利用し、推論コストを削減します。例:
gpt-3.5-turboを評価用、gpt-4oを最終生成用。 - キャッシュの活用: 頻繁にアクセスされる情報や計算結果をキャッシュすることで、再計算や再検索の回数を減らします。
- 並列処理: 独立したタスクを並列で実行することで、処理速度を向上させます。
- 適応的ルーティング (Adaptive RAG): すべての質問に対して複雑なAIエージェントフローを実行するのではなく、シンプルな質問には直接回答し、複雑な質問にのみエージェントフローを適用するなど、動的に処理を切り替えることで効率化を図ります。
- Human-in-the-Loop (HITL): 自律的なアクション(例: 返金処理、記録更新)が必要な場合に、人間の承認を挟むことでリスクを管理し、不要なLLM呼び出しを抑制します。
-
LLMの選択: 軽量なLLMを評価ノードなどに利用し、推論コストを削減します。例:
4. プロンプトエンジニアリングの難しさ
- ハマりどころ: AIエージェントが意図した通りに思考し、ツールを適切に利用するためには、非常に精緻なプロンプト設計が必要です。特に、ツールの利用方法、思考プロセス、自己評価の基準などをLLMに明確に伝えることが難しい場合があります。
-
回避策:
- Few-shot Learning: 具体的な成功例をプロンプトに含めることで、LLMの挙動を誘導します。
- Chain-of-Thought (CoT) / ReActプロンプティング: LLMに思考プロセスを段階的に出力させることで、デバッグを容易にし、より複雑な推論を可能にします。
- ツール定義の明確化: ツールの説明、入力スキーマ、出力形式をLLMが理解しやすいように明確に定義します。
- プロンプトのバージョン管理とA/Bテスト: プロンプトの変更を管理し、異なるプロンプトの効果を評価ツール(Ragasなど)で比較します。
設計上のトレードオフとベストプラクティス
Agentic RAGを実用的なAIエージェントとして構築・運用するためには、設計上のトレードオフを理解し、ベストプラクティスを適用することが不可欠です。
設計上のトレードオフ
-
精度 vs コスト・レイテンシ: Agentic RAGは精度と信頼性を向上させる一方で、複数回のLLM呼び出しやツール利用により、コストとレイテンシが増加します。
- トレードオフの考慮: 高い精度が求められる法務・医療・コンプライアンスなどの分野ではコストやレイテンシを許容し、速度が重視されるチャットボットなどではシンプルなRAGや軽量なLLMの利用を検討します。
-
自律性 vs 制御・安全性: AIエージェントの自律性を高めるほど、予期せぬ動作や誤ったアクションのリスクが増加します。
- トレードオフの考慮: 特に業務システムに組み込む場合は、Human-in-the-Loop (HITL) を導入し、重要なアクションには人間の承認を挟むことで安全性を確保します。
-
汎用性 vs 特化性: 汎用的なAgentic RAGシステムは様々なタスクに対応できますが、特定のドメインに特化したシステムの方が高い精度を発揮する場合があります。
- トレードオフの考慮: ユースケースに応じて、汎用フレームワークをベースに特化型ツールや知識ベースを組み込むか、最初から特化型で構築するかを検討します。
ベストプラクティス
- 段階的な導入: 最初から複雑なAgentic RAGを構築するのではなく、Classic RAGやHybrid RAGで検索品質と評価基盤を固め、必要に応じてCorrective RAG、Self-RAG、Agentic RAGを段階的に導入します。
- 明確なAIエージェントの役割定義: マルチエージェントシステムを構築する場合、各AIエージェントの役割(リサーチ、分析、レポート生成、レビューなど)を明確に定義し、連携方法を設計します。
- オブザーバビリティの確保: AIエージェントの思考プロセス、ツール呼び出し、検索結果、LLMの出力、コスト、レイテンシなどを詳細にトレースできる仕組み(LangSmithやArize Phoenixなど)を導入し、デバッグと改善に役立てます。
- 入力データの品質向上: どんなに高度なRAGアーキテクチャを構築しても、「Garbage In, Garbage Out(入力がゴミなら出力もゴミ)」の原則は変わりません。高品質な入力データ整備が重要です。
- メタデータの活用: ドキュメントにバージョン、作成日、信頼度などのメタデータを付与することで、セマンティックフィルタリングが可能になり、誤回答を大幅に減らせます。
- 自己評価と修正ループの組み込み: LLM自身に検索結果や生成された回答を評価させ、不十分な場合は再検索やクエリ修正を行う「自己反省(Reflection)」や「自己修正(Self-Correction)」のメカニズムを導入します。
- ツール利用の最適化: 外部APIやデータベース、Web検索など、必要なツールを適切に選択し、LLMがそれらを自律的に呼び出せるように設計します。ツールの説明はLLMが理解しやすいように具体的に記述します。
まとめ
本記事では、AIエージェントが外部ツールを自律的に利用するAgentic RAGの仕組みを、LangChain/LangGraphなどのフレームワークを使って解説しました。
Agentic RAGは、従来のRAGが抱えていた「単一知識ソースへの依存」「複雑な推論の限界」といった課題を、AIエージェントの自律的な判断能力と外部ツール連携によって克服する強力なアプローチです。LangGraphのようなフレームワークを用いることで、AIエージェントの多段階の思考プロセスや条件分岐をグラフ構造として直感的に設計し、Web検索やデータベース検索といった外部ツールを組み込み、より複雑なタスクに対応できるAIエージェントを構築できます。
実装においては、バージョン管理、コンテキスト欠落対策、コスト・レイテンシの最適化、そしてプロンプトエンジニアリングといった課題に直面しますが、本記事で紹介した回避策やベストプラクティスを適用することで、これらの課題を乗り越え、実用的なAIエージェントを開発できるでしょう。
ぜひ、公式ドキュメントや関連チュートリアルも参照し、あなたのプロジェクトでAgentic RAGの可能性を探ってみてください。