【Azure AI Foundry:第4回】安全なコード無菌室:Managed Code Interpreterでのデータ分析
【新連載:Azure AI Foundryとマルチエージェント】
※本連載は、Azure AI Foundry SDK (
azure-ai-projects) を用い、実務で安全・強力に動作する「エンタープライズ仕様の自律チームエージェント」を構築するステップバイステップのハンズオン連載です。
1. イントロダクション(今回の到達目標)
前回は、AzureAISearchTool を用いて、エージェントへ社内の専用ナレッジベース(RAG)をセキュアに接続し、情報ソースを示しながら回答させる仕組みを構築しました。
しかし、実業務におけるデータ分析では、ドキュメントのテキスト検索だけでなく、膨大なCSVやExcelの売上データを集計したり、それをグラフにプロットして可視化したりする「計算処理・データプロット」のニーズが多々存在します。テキスト出力の確率計算しか行えないLLMにとって、厳密な数値計算や画像ファイルの作成は本来極めて苦手な領域です。
今回は、エージェント自身にPythonのコードを自動生成させ、Azure側で管理された完全に隔離された安全なコンテナサンドボックス内でコードを動的実行させるツール、「Managed Code Interpreter」を装備します。
これにより、ユーザーがアップロードした売上データなどのCSVをエージェントに解析させ、自動生成されたグラフ画像(PNG)をローカルPCへ安全にダウンロードして復元するプログラムを構築することを目標とします。
前提条件(Prerequisites)
- 動作確認済みライブラリ:
azure-ai-projects>=2.0.0 - ローカル環境の認証: Azure CLI でのサインイン(
az login)および環境変数AZURE_AI_PROJECT_ENDPOINTの設定が完了していること。 - Azureリソース要件: 接続するチャットモデル(例:
gpt-4o)がデプロイされていること。
2. 安全な隔離実行空間「Managed Code Interpreter」の設計
AIエージェントにPythonコードの実行権限を与えることは非常に強力ですが、大きなセキュリティリスクを伴います。もしエージェントが生成したコードが、開発者のローカルPCや社内の本番サーバー上で直接実行された場合、バグや悪意のあるコードによってファイルシステムが破壊されたり、情報が漏洩したりする恐れがあります。
Azure AI Foundry が提供する 「Managed Code Interpreter」 は、この問題を「マネージドな無菌サンドボックス」の自動割り当てによって解決します。
エージェントごとに動的に割り当てられるサンドボックスコンテナは、外部のインターネットやローカルサーバーのネットワークから完全に論理隔離されています。また、主要なデータ解析ライブラリ(pandas, numpy, matplotlibなど)がプリインストールされているため、エージェントはマウントされたファイルに対して自由かつ安全にデータ集計やビジュアライズ処理を走らせることができます。
3. 【実践】CSVデータの自動解析とグラフ描画
ローカルにあるサンプルの売上データ(CSV)をクラウドにアップロードし、エージェントに「Code Interpreter」を使って集計グラフを作成させ、出力された画像ファイルをローカルに復元する完全な Python スクリプトを実行してみましょう。
事前にカレントディレクトリにダミーの売上データ sales.csv を作成してからスクリプトを実行してください。
sales.csv の中身の例:
Product,Sales
ProductA,120000
ProductB,85000
ProductC,150000
ProductD,45000
# 動作確認済みライブラリバージョン: azure-ai-projects==2.0.0
import os
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import CodeInterpreterTool, FilePurpose
def main():
endpoint = os.environ.get("AZURE_AI_PROJECT_ENDPOINT")
if not endpoint:
print("Error: 環境変数 AZURE_AI_PROJECT_ENDPOINT が設定されていません。")
return
csv_path = "sales.csv"
if not os.path.exists(csv_path):
print(f"Error: 分析対象のCSVファイル '{csv_path}' が見つかりません。")
return
credential = DefaultAzureCredential()
with AIProjectClient(endpoint=endpoint, credential=credential) as project_client:
# 1. 解析用CSVデータをプロジェクトへ安全にアップロード
# 最新のSDKでは、agents経由で upload_file_and_poll を使用してアップロードし、処理待ちを行います
print(f"📤 データファイル '{csv_path}' をアップロード中...")
uploaded_file = project_client.agents.upload_file_and_poll(
file_path=csv_path,
purpose=FilePurpose.AGENTS
)
print(f"✅ アップロード完了 (File ID: {uploaded_file.id})")
# 2. Code Interpreter ツールの構成
# アップロードしたファイルIDをツールに関連付けます
code_interpreter = CodeInterpreterTool(file_ids=[uploaded_file.id])
# 3. Code Interpreter を装備した「Analyst Agent」の作成
print("\n🤖 Analyst Agent を作成中...")
agent = project_client.agents.create_agent(
model="gpt-4o",
name="data-analyst-agent",
instructions="あなたは優秀なデータアナリストです。提供されたCSVデータを読み込み、matplotlibを使用して見やすい棒グラフを描画し、画像ファイルとして保存してください。",
tools=code_interpreter.definitions,
tool_resources=code_interpreter.resources
)
print(f"✅ エージェント作成完了 (ID: {agent.id})")
# 4. 会話スレッドの開始と指示メッセージの送信
thread = project_client.agents.create_thread()
user_prompt = "アップロードされた売上データを集計し、製品ごとの売上を示す棒グラフを作成してください。"
print(f"\n➡️ ユーザー: {user_prompt}")
project_client.agents.create_message(
thread_id=thread.id,
role="user",
content=user_prompt
)
# 5. 実行のトリガー(サンドボックス内でのPythonコード動的実行)
print("⚡ システム: エージェントがコードを生成し、サンドボックス内で分析を実行中...")
run = project_client.agents.create_and_process_run(
thread_id=thread.id,
assistant_id=agent.id
)
print(f"✅ 実行ステータス: {run.status}")
# 6. メッセージ一覧を巡回し、生成された画像をローカルにダウンロードして保存
messages = project_client.agents.list_messages(thread_id=thread.id)
latest_message = messages.data[0]
print("\n=== AIからのテキスト回答 ===")
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_output_path = "sales_chart.png"
print(f"\n📸 生成された画像ファイルを検出しました (File ID: {output_file_id})")
print(f"📥 画像をダウンロードして '{local_output_path}' として保存中...")
# SDKの save_file メソッドを使用してローカルにダウンロードします
project_client.agents.save_file(
file_id=output_file_id,
file_name=local_output_path
)
print(f"✅ グラフの復元に成功しました:'{os.path.abspath(local_output_path)}'")
# クリーンアップ(任意)
project_client.agents.delete_agent(agent.id)
project_client.agents.delete_file(uploaded_file.id)
print("\n🧹 リソースをクリーンアップしました。")
if __name__ == "__main__":
main()
4. まとめと次回の展望
今回は、CodeInterpreterTool のサンドボックスを活用して、エージェント自身が安全な隔離領域でコードを書き、データをグラフ画像(PNG)へ自動プロットして抽出する「データアナリストとしての物理アーム」を実装しました。
これによって、私たちのエージェントは、「クラウドでの安全接続」「記憶」「自社データの検索(RAG)」、そして「コードの安全実行(データ分析)」という4つの強力な能力を手に入れました。
しかし、1つの巨大なエージェントに対して「ドキュメントの検索」と「データ集計・コード実行」の双方を1つのプロンプトで処理させようとすると、次第に役割の競合やプロンプトの混濁が発生し、ミスやハルシネーションの確率が高くなってしまいます。
次回、第5回。
今回の「ドキュメント検索(Document Agent)」と「データ分析(Analyst Agent)」を個別のエージェントとして独立させ、エージェント同士がチャットで協調しながらプロジェクトを完了させる組織設計、「Agent-to-Agentによるマルチエージェント協調」のチームプレイ回路を彼に装着します。
知能の形態が、孤立した個人から「高度な分業チーム」へと進化する瞬間へと進みましょう。