Home 論文解説: MARA — LangGraphベースのマルチエージェントRAGアーキテクチャ
投稿
キャンセル

📄 論文解説: MARA — LangGraphベースのマルチエージェントRAGアーキテクチャ

本記事は MARA: Multi-Agent RAG Architecture (arXiv:2504.04603) の解説記事です。

論文概要(Abstract)

MARAは、従来のsingle-agent RAGが抱えるスケーラビリティ・特化不足・並列処理不能の3課題に対し、Triage Agent・RAG Agent・Web Search Agentの3種の専門エージェントをLangGraphのstate machineで協調させるマルチエージェントフレームワークである。著者らは、複雑なクエリを動的にサブタスクに分解し、各エージェントの専門能力を活かした並列処理によって、multi-hopベンチマークで15-22%の精度向上と30%の処理時間削減を報告している。

この記事は Zenn記事: LangGraph×Claude 4.6で推論精度と応答速度を両立するマルチエージェントRAG の深掘りです。

情報源

  • arXiv ID: 2504.04603
  • URL: https://arxiv.org/abs/2504.04603
  • 著者: Aditi Singh, Abul Ehtesham, Saket Kumar, Tala Talaei Khoei
  • 発表年: 2025
  • 分野: cs.AI, cs.CL, cs.IR

背景と動機(Background & Motivation)

Retrieval-Augmented Generation(RAG)は知識集約型タスクの標準的アプローチとなっているが、著者らは従来のsingle-agent RAGにおける3つの構造的限界を指摘している。

1つ目はスケーラビリティの欠如である。クエリの複雑度が上がるにつれて、1つのエージェントがすべての検索・推論・生成を担当する設計では、処理パイプラインが直列的にボトルネックとなる。2つ目は特化の不足で、FAQ的な単純クエリとmulti-hop推論を要する複雑クエリを同一のプロンプト・ツール構成で処理するため、どちらも最適化できない。3つ目は並列処理の不能で、複数のデータソースからの情報取得が逐次実行となり、レイテンシが加算される。

これらの課題は、Zenn記事で解説しているLangGraph functional APIのfan-outパターン(並列ノード実行)やCommand primitiveによる動的ルーティングが解決を目指す問題と一致する。MARAはこれらの設計パターンの学術的な検証を提供している。

主要な貢献(Key Contributions)

著者らは以下の4点を主要な貢献として挙げている。

  • 貢献1: LangGraphのstate machineに基づく、3種の専門エージェント(Triage / RAG / Web Search)によるマルチエージェントRAGアーキテクチャの提案
  • 貢献2: クエリの複雑度に応じた動的ルーティングと並列処理を実現するオーケストレーションフレームワーク
  • 貢献3: multi-hop QA・open-domain QA・real-time QAの3カテゴリにおけるsingle-agent RAG比での定量的改善の実証
  • 貢献4: マルチエージェントシステムの計算コストオーバーヘッドと性能向上のトレードオフ分析

技術的詳細(Technical Details)

アーキテクチャ: 3エージェント協調設計

MARAの中核は、以下3種の専門エージェントとLangGraphによるオーケストレーション層で構成される。

Triage Agent(トリアージエージェント): 入力クエリを分析し、処理戦略を決定する。具体的には、(a)クエリを独立したサブタスクに分解し、(b)各サブタスクを適切な専門エージェントにルーティングし、(c)並列処理が有益か逐次処理が必要かを判断する。Zenn記事のrouter_agentに相当する役割である。

RAG Agent(検索エージェント): 構造化された知識ベースや文書コレクションからの検索を担当する。dense vector search、sparse retrieval、hybrid approachを使い分け、ローカルナレッジベースから関連情報を取得する。

Web Search Agent(Web検索エージェント): ローカル知識ベースでは不十分な場合や最新情報が必要な場合に、検索APIを用いてWebから情報を取得・統合する。

LangGraphによるState Machineオーケストレーション

著者らはLangGraphのstate machine frameworkを用いてエージェント間の協調を実装している。論文で述べられている設計の要点は以下の通りである。

  1. 共有状態の管理: エージェント間でステートグラフの状態を共有し、各エージェントの出力が後続エージェントの入力として利用可能
  2. 並列実行の制御: Triage Agentが独立と判定したサブタスクについて、RAG AgentとWeb Search Agentを同時に実行
  3. エラーリカバリ: 個別エージェントの失敗時のフォールバック戦略を状態遷移として定義
  4. 同期・非同期実行: 両方の実行パターンをサポートし、ユースケースに応じた使い分けが可能

この設計はZenn記事で紹介しているCommand primitiveのgotoパラメータによる動的遷移と同じ概念をstate machineレベルで実現している。

並列検索のアーキテクチャ

MARAの並列処理は、Zenn記事のfan-out/fan-inパターンと対応する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from langgraph.func import entrypoint, task

@task
async def rag_retrieval(query: str, knowledge_base) -> list[dict]:
    """ローカル知識ベースからの検索(dense + sparse hybrid)

    Args:
        query: 検索クエリ
        knowledge_base: 検索対象のナレッジベース

    Returns:
        検索結果のリスト(content, metadata, score)
    """
    dense_results = await knowledge_base.dense_search(query, k=5)
    sparse_results = await knowledge_base.sparse_search(query, k=5)
    return merge_and_deduplicate(dense_results, sparse_results)

@task
async def web_retrieval(query: str) -> list[dict]:
    """Web検索APIを使用したリアルタイム情報取得

    Args:
        query: 検索クエリ

    Returns:
        Web検索結果のリスト(title, url, snippet)
    """
    results = await web_search_api.search(query, max_results=5)
    return [{"content": r.snippet, "url": r.url} for r in results]

@entrypoint(checkpointer=checkpointer)
async def mara_pipeline(query: str) -> str:
    """MARAスタイルの並列検索パイプライン"""
    # Triage: クエリ分析とルーティング判定
    triage_result = await triage_agent(query)

    if triage_result["strategy"] == "parallel":
        # fan-out: RAG検索とWeb検索を並列実行
        rag_future = rag_retrieval(query, knowledge_base)
        web_future = web_retrieval(query)

        # fan-in: 全結果を集約
        rag_docs = await rag_future
        web_docs = await web_future
        all_docs = rag_docs + web_docs
    elif triage_result["strategy"] == "rag_only":
        all_docs = await rag_retrieval(query, knowledge_base)
    else:
        all_docs = await web_retrieval(query)

    # 統合・生成
    return await generate_answer(query, all_docs)

このコードは論文のアーキテクチャをLangGraph functional APIで再現したものである。Triage Agentの判定結果に基づき、独立したサブタスクを並列実行し、結果を集約する。

実装のポイント(Implementation)

Triage Agentのルーティング精度が全体性能を決定する

著者らの分析によると、Triage Agentのルーティング精度がシステム全体の性能に最も大きく影響する。適切なエージェントにルーティングできなければ、専門化の恩恵は得られない。

実装上の注意点は以下の通りである。

  • ルーティングロジックの設計: 著者らはrule-basedとLLM-basedのルーティングを検討しており、LLM-basedの方が柔軟性は高いがレイテンシが増加する。Zenn記事のeffortルーティング(classify_query関数)と同じトレードオフが存在する
  • 並列実行時のレート制限: fan-outで同時リクエスト数がAPIの上限を超過しうるため、max_concurrencyの設定が必要
  • coordination overhead: マルチエージェント間の状態管理・メッセージパッシングにより、一部の単純クエリではsingle-agent RAGよりもレイテンシが増加する可能性がある

JSON-serializable制約

LangGraphのstate machineでは、エージェント間で共有される状態はJSON-serializableである必要がある。LangChainのDocumentオブジェクト等を直接渡すとシリアライズエラーが発生するため、必ずdictに変換して返す設計が求められる。

1
2
3
4
5
6
# NG: Document オブジェクトを直接返す
# return [Document(page_content="...", metadata={...})]

# OK: dict に変換して返す
return [{"content": doc.page_content, "metadata": doc.metadata}
        for doc in results]

Production Deployment Guide

AWS実装パターン(コスト最適化重視)

MARAアーキテクチャのAWSデプロイでは、3種のエージェントを個別にスケーリングできる構成が有効である。

トラフィック量別の推奨構成:

規模月間リクエスト推奨構成月額コスト主要サービス
Small~3,000 (100/日)Serverless$50-150Lambda + Bedrock + DynamoDB
Medium~30,000 (1,000/日)Hybrid$300-800Lambda + ECS Fargate + ElastiCache
Large300,000+ (10,000/日)Container$2,000-5,000EKS + Karpenter + EC2 Spot

Small構成の詳細(月額$50-150):

  • Lambda: Triage Agent用(1GB RAM, 30秒タイムアウト, $20/月)
  • Bedrock: Claude 3.5 Haiku, Prompt Caching有効($80/月)
  • DynamoDB: 検索結果キャッシュ, On-Demand($10/月)
  • CloudWatch: 基本監視($5/月)

Medium構成の詳細(月額$300-800):

  • Lambda: Triage Agent($50/月)
  • ECS Fargate: RAG Agent + Web Search Agent, 0.5 vCPU × 2タスク($120/月)
  • Bedrock: Claude 3.5 Sonnet, Batch API活用($400/月)
  • ElastiCache Redis: 検索結果キャッシュ, cache.t3.micro($15/月)

コスト削減テクニック:

  • Spot Instances使用で最大90%削減(EKS + Karpenter)
  • Bedrock Batch API使用で50%削減(非リアルタイム処理)
  • Prompt Caching有効化で30-90%削減(Triage Agent用システムプロンプト固定)

コスト試算の注意事項: 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です。実際のコストはトラフィックパターン、リージョン、バースト使用量により変動します。最新料金は AWS料金計算ツール で確認してください。

Terraformインフラコード

Small構成(Serverless): Lambda + Bedrock + DynamoDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# --- IAMロール(最小権限) ---
resource "aws_iam_role" "triage_lambda" {
  name = "mara-triage-lambda-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy" "bedrock_invoke" {
  role = aws_iam_role.triage_lambda.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
      Resource = "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-haiku*"
    }]
  })
}

# --- Lambda: Triage Agent ---
resource "aws_lambda_function" "triage_agent" {
  filename      = "triage_agent.zip"
  function_name = "mara-triage-agent"
  role          = aws_iam_role.triage_lambda.arn
  handler       = "index.handler"
  runtime       = "python3.12"
  timeout       = 30
  memory_size   = 1024

  environment {
    variables = {
      BEDROCK_MODEL_ID = "anthropic.claude-3-5-haiku-20241022-v1:0"
      DYNAMODB_TABLE   = aws_dynamodb_table.cache.name
    }
  }
}

# --- DynamoDB: 検索結果キャッシュ ---
resource "aws_dynamodb_table" "cache" {
  name         = "mara-retrieval-cache"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "query_hash"

  attribute {
    name = "query_hash"
    type = "S"
  }

  ttl {
    attribute_name = "expire_at"
    enabled        = true
  }
}

Large構成(Container): EKS + Karpenter + Spot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = "mara-cluster"
  cluster_version = "1.31"
  vpc_id          = module.vpc.vpc_id
  subnet_ids      = module.vpc.private_subnets

  cluster_endpoint_public_access = true
  enable_cluster_creator_admin_permissions = true
}

# Karpenter: Spot優先の自動スケーリング
resource "kubectl_manifest" "karpenter_provisioner" {
  yaml_body = <<-YAML
    apiVersion: karpenter.sh/v1alpha5
    kind: Provisioner
    metadata:
      name: mara-spot
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]
        - key: node.kubernetes.io/instance-type
          operator: In
          values: ["m6i.xlarge", "m6i.2xlarge"]
      limits:
        resources:
          cpu: "32"
          memory: "128Gi"
      ttlSecondsAfterEmpty: 30
  YAML
}

運用・監視設定

CloudWatch Logs Insights: エージェント別レイテンシ分析

1
2
3
4
5
6
fields @timestamp, agent_name, duration_ms, query_type
| stats avg(duration_ms) as avg_latency,
        pct(duration_ms, 95) as p95,
        pct(duration_ms, 99) as p99
  by agent_name, bin(5m)
| filter agent_name in ["triage", "rag", "web_search"]

CloudWatch アラーム(コスト監視):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import boto3

cloudwatch = boto3.client('cloudwatch')

cloudwatch.put_metric_alarm(
    AlarmName='mara-bedrock-token-spike',
    ComparisonOperator='GreaterThanThreshold',
    EvaluationPeriods=1,
    MetricName='TokenUsage',
    Namespace='AWS/Bedrock',
    Period=3600,
    Statistic='Sum',
    Threshold=500000,
    AlarmDescription='Bedrockトークン使用量異常'
)

コスト最適化チェックリスト

  • ~100 req/日 → Lambda + Bedrock (Serverless)
  • ~1000 req/日 → ECS Fargate + Bedrock (Hybrid)
  • 10000+ req/日 → EKS + Spot (Container)
  • EC2: Spot Instances優先(Karpenter自動管理)
  • Bedrock Batch API使用で50%削減
  • Prompt Caching有効化で30-90%削減
  • Lambda: メモリサイズ最適化
  • ECS/EKS: アイドル時スケールダウン
  • AWS Budgets: 月額予算設定(80%で警告)
  • CloudWatch: トークン使用量スパイク検知
  • Cost Anomaly Detection: 自動異常検知
  • 日次コストレポート: SNS/Slackへ送信
  • タグ戦略: 環境別(dev/staging/prod)
  • S3ライフサイクル: キャッシュ30日自動削除
  • 開発環境: 夜間停止(Auto Start/Stop)

実験結果(Results)

著者らは以下の3カテゴリのベンチマークで評価を行っている。

ベンチマーク結果:

ベンチマークカテゴリsingle-agent RAGMARA改善率
HotpotQAmulti-hop QAベースライン+15-22%accuracy
MuSiQuemulti-hop QAベースライン+15-22%accuracy
Natural Questionsopen-domain QAベースライン改善relevance
TriviaQAopen-domain QAベースライン改善relevance
Real-time QAreal-timeベースライン改善accuracy

(出典: 論文Section Experimental Results)

著者らの報告による主要な知見は以下の通りである。

  1. 並列処理の効果: 独立したサブタスクの並列実行により、合計処理時間が約30%削減された
  2. 専門化の効果: ドメイン固有のクエリに対して、専門エージェントが非専門エージェントよりも高い検索品質を達成
  3. Triage Agentの重要性: ルーティングの正確さがシステム全体の性能に最も大きく寄与する
  4. LangGraphの有用性: state machineによる明示的な状態遷移定義がデバッグと透明性を向上させる

制約: 著者らは、一部のクエリではcoordination overheadによりsingle-agent RAGよりもレイテンシが増加しうることを述べている。また、評価は英語ベンチマークに限定されており、多言語環境への適用は未検証である。

実運用への応用(Practical Applications)

MARAのアーキテクチャは、Zenn記事で解説しているLangGraph functional APIの@task/@entrypointパターンで実装可能である。

プロダクション視点での適用先:

  • 社内ナレッジベース検索: RAG Agentがドキュメントを検索し、Web Search Agentが最新情報を補完するハイブリッド構成
  • カスタマーサポート: Triage Agentがクエリを分類し、FAQ(RAG Agent)と問い合わせ(Web Search Agent)を適切に振り分け
  • リサーチアシスタント: 論文(RAG Agent)とWeb上の最新情報(Web Search Agent)を並列取得し、統合的な回答を生成

運用上の考慮事項: 著者らの実験では並列実行で30%のレイテンシ削減を報告しているが、coordination overheadが存在するため、クエリの大半が単純な場合はsingle-agent構成の方が効率的である可能性がある。

関連研究(Related Work)

  • Agentic RAG Survey (Singh et al., 2025, arXiv:2501.09136): single-agent / multi-agent / hierarchicalの3パターンを分類したサーベイ。MARAはmulti-agentパターンの具体的実装と位置付けられる
  • AgenticRAG (Kosba et al., 2025, arXiv:2501.15228): 5種のエージェント(Query Decomposition / Retrieval / Web Search / Synthesis / Verification)を用いたマルチエージェントRAG。MARAは3エージェントで簡潔さを優先した設計
  • Adaptive-RAG (Jeong et al., 2024, arXiv:2404.19756): クエリ複雑度に基づく検索戦略の適応的選択。MARAのTriage Agentの設計思想と共通する

まとめと今後の展望

MARAは、LangGraphのstate machineを活用したマルチエージェントRAGの実装と評価を提供する論文である。multi-hop QAで15-22%の精度向上、並列実行で30%の処理時間削減を著者らは報告している。

Zenn記事で解説しているfunctional APIのfan-outパターンやCommand primitiveによる動的ルーティングは、MARAが検証したアーキテクチャパターンをAPIレベルで実現するアプローチと位置付けられる。特にTriage Agentのルーティング精度が全体性能を決定するという知見は、effortルーティングの分類器設計においても重要な示唆である。

ただし、coordination overheadによるレイテンシ増加や英語ベンチマーク限定の評価など、本番環境への適用時には追加検証が必要である。

参考文献


:::message 本記事はAI(Claude Code)により自動生成されました。内容は論文に基づいていますが、実際の利用時は原論文もご確認ください。 :::

この投稿は CC BY 4.0 でライセンスされています。

論文解説: JSONSchemaBench — 構造化出力フレームワークの体系的ベンチマーク

論文解説: syftr — Bayesian最適化によるRAGパイプラインのPareto最適構成探索