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?

【Azure AI Foundry:第8回(おまけ②)】表データの極意:Document IntelligenceとマルチエージェントRAGの実戦結合

0
Last updated at Posted at 2026-08-02

【Azure AI Foundry:第8回(おまけ②)】表データの極意:Document IntelligenceとマルチエージェントRAGの実戦結合

新連載:Azure AI Foundryとマルチエージェント

※本連載は、Azure AI Foundry SDK (azure-ai-projects) を用い、実務で安全・強力に動作する「エンタープライズ仕様 of 自律チームエージェント」を構築するステップバイステップのハンズオン連載です。


1. イントロダクション(今回の到達目標)

前回は、実務RAGにおける最大の課題である「PDFの表(テーブル)構造の破壊」を防ぐため、Azure AI Document Intelligence を用いて、セルの結合関係やレイアウトを維持したままドキュメントをMarkdownテキストへと高精度変換する前処理プログラムを構築しました。

連載の最終回となる第8回は、これまでに個別に実装してきたすべてのエージェントパーツ(RAG検索、コード実行サンドボックス、エージェント間協調、および前処理)を一つに結合します。

Document Intelligence で抽出した「表構造のマークダウンテキスト」を Azure AI Search へインジェストし、第5回で構築した「マルチエージェントチーム」の Coordinator Agent に対し、「ドキュメントから表データを検索し、棒グラフを Code Interpreter サンドボックスで生成せよ」という高度な複合命令を実行させて、正確なデータ可視化とレポートをチームプレイで出力させる「実戦総括テスト」をクリアすることを目標とします。

前提条件(Prerequisites)

  • 動作確認済みライブラリ: azure-ai-projects>=2.0.0, azure-ai-documentintelligence>=1.0.0b4, azure-identity
  • Azure上のリソース:
    • これまで作成した Azure AI Foundry プロジェクトAzure AI Search(インデックス準備完了)、および Azure AI Document Intelligence
  • ローカル環境の認証: Azure CLI によるサインイン(az login)および環境変数設定が完了していること。

2. 全パーツが融合する「実戦マルチエージェントRAG」の全体設計

本連載で構築してきたすべての機能パーツを連携させた、最終的なエンタープライズアーキテクチャの全容は以下の通りです。

この構成の最大の特徴は、「情報の入力(前処理)から処理(検索・分析)までのデータの整合性が一貫してMarkdownで保たれている」点です。
Document Intelligence によって表構造が正しくマークダウン化されているため、Azure AI Search は意味的な関係を崩さずにインデックス化でき、Document Agent は正確なテーブルデータを取り出すことができます。そして、Analyst Agent はそのマークダウン形式の数値データをそのまま Python コード内のデータフレームに解釈させ、完璧なグラフを描ききることができます。


3. 【実践】一気通貫での実戦結合テスト

PDFドキュメントを解析してマークダウン化し、そのデータを前提知識(RAG)として持ったマルチエージェントに検索とデータ分析(グラフ生成)を実行させる、集大成となる完全な Python スクリプトを実行してみましょう。

# 動作確認済みライブラリバージョン: 
# azure-ai-projects==2.0.0, azure-ai-documentintelligence==1.0.0b4
import os
from azure.identity import DefaultAzureCredential
from azure.core.credentials import AzureKeyCredential
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import DocumentContentFormat
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    CodeInterpreterTool, 
    AzureAISearchTool, 
    AzureAISearchToolResource, 
    AISearchIndexResource,
    AzureAISearchQueryType,
    ConnectedAgentTool
)

def main():
    # 接続設定のロード
    foundry_endpoint = os.environ.get("AZURE_AI_PROJECT_ENDPOINT")
    di_endpoint = os.environ.get("AZURE_DOCUMENTINTELLIGENCE_ENDPOINT")
    di_key = os.environ.get("AZURE_DOCUMENTINTELLIGENCE_KEY")
    search_connection = os.environ.get("AI_SEARCH_CONNECTION_NAME")
    search_index = os.environ.get("AI_SEARCH_INDEX_NAME")

    if not all([foundry_endpoint, di_endpoint, di_key, search_connection, search_index]):
        print("Error: 必要な環境変数が設定されていません。確認してください。")
        return

    credential = DefaultAzureCredential()

    # ==========================================
    # Step 1: Document IntelligenceによるPDFのマークダウン化
    # ==========================================
    pdf_path = "quarterly_sales.pdf" # 分析対象のPDF
    if not os.path.exists(pdf_path):
        print(f"Error: 対象ファイル '{pdf_path}' がありません。")
        return

    print("📄 1. Document IntelligenceでPDFの表構造を抽出中...")
    di_client = DocumentIntelligenceClient(endpoint=di_endpoint, credential=AzureKeyCredential(di_key))
    with open(pdf_path, "rb") as f:
        poller = di_client.begin_analyze_document(
            model_id="prebuilt-layout",
            body=f,
            output_content_format=DocumentContentFormat.MARKDOWN
        )
    di_result = poller.result()
    extracted_markdown = di_result.content
    print("✅ 表構造を崩さずにMarkdownテキスト化を完了しました。")

    # (※実務ではここで extracted_markdown を Azure AI Search インデックスに登録します。
    #  今回のデモコードでは、抽出された表マークダウンをダイレクトにエージェントの会話スレッドに前提知識として流し込みます。)

    # ==========================================
    # Step 2: マルチエージェントチームの編成と実行
    # ==========================================
    with AIProjectClient(endpoint=foundry_endpoint, credential=credential) as project_client:
        
        # 1. 検索担当 (RAG) エージェントの作成
        connection = project_client.connections.get(search_connection)
        search_tool = AzureAISearchTool(
            azure_ai_search=AzureAISearchToolResource(
                indexes=[
                    AISearchIndexResource(
                        project_connection_id=connection.id,
                        index_name=search_index,
                        query_type=AzureAISearchQueryType.SIMPLE
                    )
                ]
            )
        )
        print("\n🤖 子エージェント1: Document Agent を構築中...")
        doc_agent = project_client.agents.create_agent(
            model="gpt-4o",
            name="document-agent",
            instructions="あなたはドキュメント検索の専門家です。指示された質問に回答するため、RAGインデックスから正確なデータを検索して返してください。",
            tools=search_tool.definitions,
            tool_resources=search_tool.resources
        )

        # 2. データ解析担当エージェントの作成
        code_interpreter = CodeInterpreterTool()
        print("🤖 子エージェント2: Analyst Agent を構築中...")
        analyst_agent = project_client.agents.create_agent(
            model="gpt-4o",
            name="analyst-agent",
            instructions="あなたはデータ解析の専門家です。渡された売上テーブル(Markdown)から棒グラフを作成し、画像ファイルとして保存してください。",
            tools=code_interpreter.definitions,
            tool_resources=code_interpreter.resources
        )

        # 3. 司令塔エージェントの作成 & ラップ
        doc_tool = ConnectedAgentTool(
            id=doc_agent.id,
            name="document_search_tool",
            description="社内データや実績を検索し、正しいデータを取得するためのツールです。"
        )
        analyst_tool = ConnectedAgentTool(
            id=analyst_agent.id,
            name="data_analysis_tool",
            description="データをグラフ化したり、コードを実行して集計を行うためのツールです。"
        )

        print("🤖 親エージェント: Coordinator Agent を構築中...")
        coordinator_agent = project_client.agents.create_agent(
            model="gpt-4o",
            name="coordinator-agent",
            instructions="あなたは司令塔です。渡されたPDFのデータ(Markdown)を解析し、製品別の売上を示す棒グラフを作成させてください。データ検索には document_search_tool、グラフ化には data_analysis_tool を協調して使用します。",
            tools=[doc_tool, analyst_tool]
        )
        print("✅ マルチエージェントチームの編成が完了しました。")

        # 4. 会話の開始
        thread = project_client.agents.create_thread()
        
        # ユーザー指示と抽出したマークダウンデータを結合して送信
        prompt = f"""
以下の売上ドキュメントに基づいて、四半期ごとの売上推移を示す棒グラフを作成してください。

【ドキュメントデータ】
{extracted_markdown}
"""
        print("\n➡️ ユーザー: 売上データを集計し、グラフを生成してください。")
        project_client.agents.create_message(
            thread_id=thread.id,
            role="user",
            content=prompt
        )

        # 5. 協調処理の実行
        print("⚡ システム: コーディネーターがマルチエージェントチームを実行中...")
        run = project_client.agents.create_and_process_run(
            thread_id=thread.id,
            assistant_id=coordinator_agent.id
        )
        print(f"✅ 実行ステータス: {run.status}")

        # 6. メッセージの巡回と生成されたグラフ画像のダウンロード
        messages = project_client.agents.list_messages(thread_id=thread.id)
        latest_message = messages.data[0]

        print("\n=== Coordinator からの集計レポート ===")
        for part in latest_message.content:
            if hasattr(part, 'text'):
                print(part.text.value)
        print("=======================================")

        # 生成画像の検知とダウンロード
        for part in latest_message.content:
            if part.type == "image_file":
                output_file_id = part.image_file.file_id
                local_path = "sales_by_quarter.png"
                print(f"\n📥 グラフ画像 (ID: {output_file_id}) を検知しました。ダウンロード中...")
                project_client.agents.save_file(
                    file_id=output_file_id,
                    file_name=local_path
                )
                print(f"✅ グラフの復元に成功しました:'{os.path.abspath(local_path)}'")

        # クリーンアップ
        project_client.agents.delete_agent(coordinator_agent.id)
        project_client.agents.delete_agent(doc_agent.id)
        project_client.agents.delete_agent(analyst_agent.id)
        print("\n🧹 チームリソースを正常にクリーンアップしました。")

if __name__ == "__main__":
    main()

4. 総括:エンタープライズAIの未来へ

本連載『Azure AI Foundryとマルチエージェント』をお読みいただき、本当にありがとうございました。

私たちが構築したシステムは、単に「質問に答えるだけのチャットボット」ではありません。

  • セキュアなアイデンティティ(Entra ID)による接続
  • 永続化された会話のステート管理(Thread)
  • 意味的に正確な独自知識の検索(RAG & Document Intelligence)
  • 隔離され安全に制限されたコード実行空間(Managed Code Interpreter)
  • 高度な専門チームによる分業体制(マルチエージェント協調)
  • 運用テレメトリの完全な可視化と自動監査(Tracing & Evaluation)

これらはすべて、エンタープライズ環境でAIエージェントを本番運用するために欠かせない「設計原則」そのものです。Azure AI Foundry は、これらの複雑なインフラレイヤーを強力に隠蔽し、開発者が「エージェントの協調設計」に集中できる環境を提供してくれます。

本連載で得たインフラとコードの設計図をもとに、ぜひ皆さんのビジネス現場の複雑なワークフローを自律的に解決する、最強のマルチエージェントチームを構築してみてください!

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?