【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 は、これらの複雑なインフラレイヤーを強力に隠蔽し、開発者が「エージェントの協調設計」に集中できる環境を提供してくれます。
本連載で得たインフラとコードの設計図をもとに、ぜひ皆さんのビジネス現場の複雑なワークフローを自律的に解決する、最強のマルチエージェントチームを構築してみてください!