取り組みの背景 — 図を描けばAIが動く時代
AIエージェントのワークフローを設計する際、多くの人がまず図を描き、その後コードやプロンプトに変換するという2段階の作業を行っています。「もし図をそのままプロンプトとして実行できたら?」——Draw.io(diagrams.net)を使うことで、この発想を実現できます。
Draw.io ファイルの実体はXML形式であり、各図形にカスタムメタデータを埋め込めるという特性を活かすと、人間が読みやすいフローチャートを、AIエージェントが解釈・実行できるプロンプトとして二重に機能させることが可能です。
なぜDraw.io なのか
従来のMermaid図の課題
AIエージェントにワークフローを自動生成させる手段として、Mermaid 記法がよく使われます。しかし実務では以下の課題がありましました。
- AIが生成したMermaid図は構文エラーが発生しやすい
- 複雑なフローの可読性が低い
- GUI操作で直感的に編集できない
- エージェント数の増減が文法の知識に依存する
Draw.io の優位性
Draw.io には以下の利点があります。
- GUI操作で直感的: ドラッグ&ドロップで図形を配置し、矢印でつなぐだけ
- XMLベース: ファイルの実体はXMLであり、プログラムから読み取り可能
- カスタムメタデータ: 各図形に非表示のテキスト情報を埋め込める
- VSCode統合: 拡張機能で
.dioファイルをエディタ内で編集できる - バージョン管理対応: テキストベースなのでGitでの差分管理が可能
基本原理: XMLメタデータの活用
Draw.io ファイル(.dio / .drawio)の中身は、以下のような構造のXMLです。
<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<!-- 図形要素 -->
<mxCell id="2" value="Google検索を実行"
style="rounded=1;whiteSpace=wrap;"
vertex="1" parent="1">
<mxGeometry x="100" y="100" width="200" height="60" as="geometry"/>
<!-- カスタムメタデータ -->
<object label="Google検索を実行"
SystemPrompt="指定されたキーワードでGoogle検索を行い、上位3件の結果を返す"
ToolName="web_search"/>
</mxCell>
</root>
</mxGraphModel>ポイントは object 要素の属性です。label は図上に表示されるテキスト、SystemPrompt や ToolName はAIエージェントが処理を実行する際のメタデータとして使えます。図を見る人間には通常のフローチャートに見え、AIエージェントには構造化されたプロンプトとして機能します。
実践1: シンプルな処理の実行
Step 1: Draw.io ファイルの作成
VSCode で拡張機能「Draw.io Integration」をインストールし、prompt.dio ファイルを作成します。
- 角丸四角形を配置し、「Google検索を実行」と入力
- 図形を右クリック → 「Edit Style」でカスタム属性を追加
SystemPrompt属性に処理の詳細を記述
Step 2: メタデータの読み取り
Python でDraw.ioファイルからメタデータを抽出するコードは以下の通りです。
import xml.etree.ElementTree as ET
def parse_drawio_prompt(filepath):
"""Draw.ioファイルからプロンプト情報を抽出"""
tree = ET.parse(filepath)
root = tree.getroot()
tasks = []
for cell in root.iter("mxCell"):
value = cell.get("value", "")
# object要素を持つセルを探す
obj = cell.find("object")
if obj is not None:
task = {
"label": obj.get("label", value),
"system_prompt": obj.get("SystemPrompt", ""),
"tool": obj.get("ToolName", ""),
"id": cell.get("id")
}
tasks.append(task)
return tasks
# 使用例
tasks = parse_drawio_prompt("prompt.dio")
for task in tasks:
print(f"Task: {task['label']}")
print(f" Prompt: {task['system_prompt']}")
print(f" Tool: {task['tool']}")
# 出力例:
# Task: Google検索を実行
# Prompt: 指定されたキーワードでGoogle検索を行い、上位3件の結果を返す
# Tool: web_search実践2: シーケンス処理の構築
より実用的な例として、「RSSフィードから特定条件の記事を抽出し、要約する」4段階のフローを構築してみましょう。
フロー設計
[RSSフィード取得] → [条件フィルタリング] → [データ抽出] → [100字要約]
(円形) (ひし形) (四角形) (角丸四角形)
各図形の形状にも意味を持たせます。
- 円形: 入力・データソース
- ひし形: 条件分岐・フィルタリング
- 四角形: データ変換・処理
- 角丸四角形: 出力・最終結果
接続情報の解析
矢印(Edge)の情報から処理順序を復元します。
def parse_drawio_workflow(filepath):
"""Draw.ioファイルからワークフロー(ノード+エッジ)を抽出"""
tree = ET.parse(filepath)
root = tree.getroot()
nodes = {}
edges = []
for cell in root.iter("mxCell"):
cell_id = cell.get("id", "")
source = cell.get("source")
target = cell.get("target")
if source and target:
# エッジ(矢印)
edges.append({"from": source, "to": target})
elif cell.get("vertex") == "1":
# ノード(図形)
obj = cell.find("object")
if obj is not None:
nodes[cell_id] = {
"label": obj.get("label", cell.get("value", "")),
"prompt": obj.get("SystemPrompt", ""),
"tool": obj.get("ToolName", "")
}
return nodes, edges
def build_execution_order(nodes, edges):
"""エッジ情報から実行順序を決定"""
# 入次数0のノードを開始点とするトポロジカルソート
in_degree = {nid: 0 for nid in nodes}
adjacency = {nid: [] for nid in nodes}
for edge in edges:
if edge["to"] in in_degree:
in_degree[edge["to"]] += 1
if edge["from"] in adjacency:
adjacency[edge["from"]].append(edge["to"])
queue = [nid for nid, deg in in_degree.items() if deg == 0]
order = []
while queue:
current = queue.pop(0)
order.append(current)
for neighbor in adjacency.get(current, []):
in_degree[neighbor] -= 1
if in_degree[neighbor] == 0:
queue.append(neighbor)
return order
# 使用例
nodes, edges = parse_drawio_workflow("sequence_prompt.dio")
order = build_execution_order(nodes, edges)
for node_id in order:
node = nodes[node_id]
print(f"Execute: {node['label']} (tool: {node['tool']})")
# 出力例:
# Execute: RSSフィード取得 (tool: rss_fetch)
# Execute: 条件フィルタリング (tool: filter)
# Execute: データ抽出 (tool: extract)
# Execute: 100字要約 (tool: summarize)実践3: マルチエージェントの並列実行
Draw.io のスイムレーン(プール/レーン)機能を使うと、複数のAIエージェントの並列実行を視覚的に表現できます。
スイムレーン設計
┌─────────────────────────────────────────┐
│ Agent A(市場調査担当) │
│ [競合分析] → [トレンド抽出] │
├─────────────────────────────────────────┤
│ Agent B(技術調査担当) │
│ [技術比較] → [実装コスト見積] │
├─────────────────────────────────────────┤
│ 統合レイヤー │
│ [結果集約] → [レポート生成] │
└─────────────────────────────────────────┘
各レーンが独立したエージェントに対応し、レーンを跨ぐ矢印が結果の受け渡しを表現します。GUIで直感的にエージェントを追加・削除できるため、チーム構成の変更が容易です。
並列実行の実装
import asyncio
async def execute_agent(agent_name, tasks, nodes):
"""単一エージェントのタスクを順次実行"""
results = []
for task_id in tasks:
node = nodes[task_id]
print(f"[{agent_name}] Executing: {node['label']}")
# 実際にはここでAI APIを呼び出す
result = f"Result of {node['label']}"
results.append(result)
await asyncio.sleep(0.1) # API呼び出しの模擬
return results
async def run_multi_agent_workflow(agents_config, nodes):
"""複数エージェントを並列実行し、結果を集約"""
tasks = [
execute_agent(name, task_ids, nodes)
for name, task_ids in agents_config.items()
]
all_results = await asyncio.gather(*tasks)
return dict(zip(agents_config.keys(), all_results))
# 使用例
agents = {
"Agent A(市場調査)": ["node_1", "node_2"],
"Agent B(技術調査)": ["node_3", "node_4"]
}
# results = asyncio.run(run_multi_agent_workflow(agents, nodes))
print("Multi-agent workflow configured")
# 出力: Multi-agent workflow configuredAntigravity との統合
Antigravity IDE でDraw.io のビジュアルプロンプトを活用するには、MCPサーバーとしてパーサーを公開する方法が有効です。
Antigravity のエージェント機能は、MCPサーバー経由で外部ツールを呼び出せます。Draw.io パーサーをMCPサーバー化すれば、「この図の通りに実行して」という自然言語指示で、ビジュアルプロンプトに基づく処理を起動できます。
ビジネスにおけるメリット
非エンジニアとの協業
プロンプトの設計がコードではなく図で表現されるため、ビジネスサイドのメンバーもAIエージェントのワークフロー設計に参加できます。
ドキュメントとコードの一致
図がそのままプロンプトとして機能するため、「設計書と実装が乖離する」問題が構造的に解消されます。
変更管理の容易さ
処理フローの変更がGUIのドラッグ&ドロップで完結し、Gitで差分を追跡できます。
まとめ
Draw.io をAIエージェントのプロンプトとして活用する手法は、「人間が読める図」と「AIが実行できるプロンプト」を一つのファイルに統合するアプローチです。XMLベースのメタデータ機能を活かし、シンプルな処理からマルチエージェントの並列実行まで、視覚的に設計・実行できます。
特にチーム開発やビジネスサイドとの協業において、「図を見ればワークフローがわかり、そのまま実行もできる」という利点は大きな武器になるでしょう。AIエージェントの設計パターンをさらに深く