
Claude CodeのGCPアーキテクチャ図スキルを改善する — 座標検証の自動化とデザインパターンの発見
はじめに
前回の記事で、Claude Codeに「GCPアーキテクチャ図を描いて」と言うだけでDraw.ioファイルを自動生成するスキルを作りました。
アイコンの表示やコンテナのネストは正しく動いたのですが、実際のプロジェクトで使ってみると、いくつかの問題が見えてきました。矢印がラベルの上を通って文字が読めない、要素の配置が直線的で論理的なグルーピングがない、フロー図のステップ番号が凡例を見ないと意味がわからない、といった問題です。
この記事では、これらの問題をどう解決したかを紹介します。具体的には:
- 座標検証スクリプト — 要素の重なりを自動検出するPythonツール
- Draw.ioのz-order問題 — 矢印がラベルの上に描画される根本原因と対処法
- インラインエッジラベル — ステップ番号に説明を付けて自己説明的にする
- レイアウトの改善 — 関連サービスの論理的グルーピング
問題:座標の重なりを手作業で見つけるのは大変
スキルに「RAGチャットボットのアーキテクチャ図を描いて」と指示すると、以下のようなDraw.ioファイルが生成されます。
Google Chat → チャットボット → ナレッジ検索 → AI回答生成
↓
会話履歴
生成されたXMLを見ると、各要素の座標は親コンテナからの相対位置で定義されています:
<!-- svc-cf-bot の座標は grp-project (x=280, y=130) の中の (80, 130) -->
<!-- → 絶対座標: (360, 260) -->
<mxCell id="svc-cf-bot" parent="grp-project" vertex="1">
<mxGeometry x="80" y="130" width="34" height="42" as="geometry" />
</mxCell>
問題は、要素が増えると相対座標から絶対位置を暗算するのが困難なことです。あるアイコンのラベルが別のアイコンと重なっていないか?矢印のウェイポイントがラベルの領域を避けているか?手作業での検証は非現実的です。
解決策1:座標検証スクリプト
Draw.ioのXMLをパースし、要素間の重なりを自動検出するPythonスクリプトを作りました。
仕組み
@dataclass
class BBox:
"""軸並行バウンディングボックス"""
x: float
y: float
width: float
height: float
@property
def right(self) -> float:
return self.x + self.width
@property
def bottom(self) -> float:
return self.y + self.height
def overlaps(self, other: BBox) -> bool:
"""AABB重なりテスト"""
if self.x >= other.right or other.x >= self.right:
return False
if self.y >= other.bottom or other.y >= self.bottom:
return False
return True
スクリプトの処理フローは以下の通りです:
1. XMLパース — .drawioファイルから全mxCell要素を抽出し、座標・スタイル・親子関係を取得
2. 絶対座標の再帰解決 — 親コンテナからの相対座標を絶対座標に変換
def _resolve(elem_id: str) -> tuple[float, float]:
elem = elements[elem_id]
if elem.resolved:
return (elem.abs_x, elem.abs_y)
parent_abs = _resolve(elem.parent_id)
elem.abs_x = parent_abs[0] + elem.rel_x
elem.abs_y = parent_abs[1] + elem.rel_y
elem.resolved = True
return (elem.abs_x, elem.abs_y)
3. ラベルのバウンディングボックス推定 — GCPアイコンは verticalLabelPosition=bottom でアイコンの下にラベルが表示されます。フォントサイズと文字数からラベル領域を推定します
# CJK文字は1文字あたり約9px、ラテン文字は約7px(11pxフォント時)
avg_char_w = 9.0 if any(ord(c) > 0x2E80 for c in text) else 7.0
text_width = len(text) * avg_char_w * (font_size / 11.0)
4. エッジルーティングの近似 — 明示的なウェイポイントを持つエッジは正確にセグメントを計算し、自動ルーティングのエッジはZ字型の直交パスとして近似
5. 4種類の重なり検出:
- エッジ—ラベル間の交差
- コンテナの重なり
- アイコン間の近接(最小ギャップ10px)
- ラベル—ラベル間の重なり
使い方
uv run python scripts/validate_drawio.py docs/gcp-rag-chatbot.drawio \
--export-coords docs/gcp-rag-chatbot-coords.json \
--ignore grp-project:lane-b-header
出力例:
Elements: 33 (11 edges)
[EDGE-LABEL] edge-4 overlaps svc-cf-bot label (gap: -3.5px)
[EDGE-LABEL] edge-5 overlaps svc-cf-bot label (gap: -8.2px)
[EDGE-LABEL] edge-rag-link overlaps svc-logging label (gap: -5.1px) [approx]
[approx] マークは自動ルーティングの近似から来た検出で、偽陽性の可能性があるため目視確認が必要です。--ignore ID1:ID2 で意図的な重なり(スイムレーンのヘッダーがコンテナをまたぐ等)を除外できます。
--export-coords で出力されるJSONファイルには、全要素の相対座標・絶対座標・バウンディングボックスが記録されます。デバッグ時に座標を1つずつ確認するのに役立ちます。
問題:矢印がラベルの上に描画される
検証スクリプトで重なりを検出した後、「ラベルに白背景をつければ矢印の上でも読める」と考え、全アイコンのstyleに labelBackgroundColor=#FFFFFF を追加しました。
fontColor=#999999;labelBackgroundColor=#FFFFFF;shape=image;...
しかし、これは効果がありませんでした。Draw.ioで実際にPNGにエクスポートしてみると、矢印は依然としてラベルの上に描画されています。
原因:mxGraphのエッジ描画順序
いくつかのテストファイルを作って調べた結果、Draw.ioの基盤ライブラリであるmxGraphの仕様が判明しました:
エッジ(矢印)は、XML上の順序やレイヤーに関係なく、常に頂点(アイコン・ラベル)の上に描画される
これはmxGraphの設計上の決定であり、回避策はありません。labelBackgroundColorを設定しても、XMLの順序を変えても、別レイヤーに分けても、エッジは常に最前面に描画されます。
対処法:ウェイポイントでラベル領域を避ける
唯一の解決策は、矢印のルーティングをラベル領域の外に迂回させることです。
<!-- Before: 矢印がチャットボットのラベルを横切る -->
<mxCell id="edge-4" source="svc-cf-bot" target="svc-firestore" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="377" y="401" /> <!-- ラベル領域内を通過 -->
</Array>
</mxGeometry>
</mxCell>
<!-- After: ラベルの右端(x=409)を避けて x=420 を通す -->
<mxCell id="edge-4" source="svc-cf-bot" target="svc-firestore" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="420" y="401" /> <!-- ラベル領域の外 -->
</Array>
</mxGeometry>
</mxCell>
この知見をスキルのSKILL.mdにラベル回避ルールとして追加しました:
Edges must not pass through icon label text. When an edge would cross a label area, add explicit waypoints to route above the icon or below the label. Target the icon center y for vertical centering when pointing at an icon from the side.
labelBackgroundColor は矢印対策としては無効ですが、コンテナ背景の上でラベルを読みやすくする効果はあるため、引き続き使用しています。
改善:インラインエッジラベル
前回のスキルでは、非技術者向けモードとしてステップ番号付きエッジを設計していました:
Flow A: ① ② ③ ④(白丸数字)
Flow B: ❶ ❷ ❸ ❹(黒丸数字)
凡例にステップ番号と説明のマッピングを記載する想定でしたが、実際に図を見ると番号だけでは何の操作かわからず、毎回凡例を見る必要があります。
改善後:番号+説明をインラインで
Before: ① → ② → ③
After: ①質問送信 → ②ナレッジ検索 → ③AI回答生成
各矢印に直接説明が付くため、図が自己説明的になります。凡例はフローの種類を示すだけで十分です(例:「①〜⑤ チャット応答フロー」)。
この変更はDraw.ioのXMLではedge要素のvalue属性を変えるだけです:
<!-- Before -->
<mxCell id="edge-1" value="①" ... />
<!-- After -->
<mxCell id="edge-1" value="①質問送信" ... />
改善:レイアウトの論理的グルーピング
スキルが最初に生成したレイアウトでは、全サービスが横一列に並んでいました:
チャットボット → ナレッジ検索 → AI回答生成 → ... → ログ管理
このレイアウトには2つの問題がありました:
1. ログ管理の位置が不適切 — フローの終端に配置されており、あたかもフローの最終ステップのように見えますが、実際にはボット処理の副作用(サイドエフェクト)です
2. ナレッジ検索とAI回答生成が離散的 — 横一列に並んでいますが、この2つはRAG処理という1つの概念の2ステップであり、論理的に近い関係にあります
改善後のレイアウト
チャットボット → ログ管理 ナレッジ検索
↓
AI回答生成 → 会話履歴
- ログ管理をチャットボットの隣に移動 — 副作用であることが視覚的に明確
- ナレッジ検索とAI回答生成を縦に積む — RAG処理という論理的なまとまりを表現
SKILL.mdへのフィードバック反映
これらの改善をスキルのSKILL.mdに反映し、次回以降の図生成で同じ品質が出せるようにしました。主な追加内容:
Visual QAワークフロー(ステップ5)
#### 5a. Automated coordinate validation
uv run python scripts/validate_drawio.py docs/<slug>.drawio \
--export-coords docs/<slug>-coords.json
#### 5b. Visual inspection
/opt/homebrew/bin/drawio -x -f png -s 2 -o docs/<slug>.png docs/<slug>.drawio
#### 5c. Fix and iterate
3つの新ルール
- Z-orderルール: Draw.ioではエッジは常に頂点の上に描画される。唯一の解決策はウェイポイントでラベル領域を迂回すること
- エッジ分離ルール: 同じ経路を共有するエッジは最低40pxの間隔を空けてルーティングする
- ラベル回避ルール: エッジはアイコンラベルのテキスト領域を通過してはならない
インラインエッジラベルの採用
### Inline step-numbered edges
- Flow A: ①質問送信 ②ナレッジ検索 ③AI回答生成(white circled + description)
- **Always include the description inline** — makes edges self-documenting
学んだこと
LLMに「見た目の品質」を任せきれない
LLMは正しいXML構造を生成できますが、要素間の座標関係を「見て」判断することはできません。座標検証スクリプトのようなツールで補完することで、生成→検証→修正のループを回せるようになります。
Draw.ioの描画順序は直感に反する
「XMLの順序を変えればz-orderが変わる」というのは頂点同士では正しいですが、エッジに対しては一切効かないという仕様は、実際にテストファイルで確認するまでわかりませんでした。ドキュメントにも明記されておらず、試行錯誤で発見する類の知識です。
スキルの改善は「使ってみて直す」サイクル
最初に作ったSKILL.mdは163アイコンの参照とレイアウトルールをカバーしていましたが、実際のプロジェクトで使うと「インラインラベルの方が読みやすい」「ログ管理はフロー終端ではなく副作用として配置すべき」といったデザイン上の知見が出てきます。これらをSKILL.mdにフィードバックすることで、スキルは使うほど賢くなっていきます。
まとめ
Claude CodeのGCPアーキテクチャ図スキルに、座標検証の自動化とデザインパターンの改善を加えました。
- validate_drawio.py(536行): 座標の再帰解決、ラベルBBox推定、エッジルーティング近似、4種類の重なり検出
- z-orderの発見: Draw.ioのエッジは常に頂点の上に描画される → ウェイポイントでラベル領域を迂回する
- インラインエッジラベル: ①質問送信 のように番号+説明をセットにすることで自己説明的な図になる
- レイアウトの論理的グルーピング: 関連サービスを近くに配置し、副作用的なサービスはフローの主線から外す
前回の記事で「style文字列をコピペするだけ」で正確なアイコンを出せるようにしましたが、今回の改善で「レイアウトとルーティングも自動で品質チェックできる」ようになりました。スキルは作って終わりではなく、実際に使いながらフィードバックを反映していくことで、徐々に実用レベルに近づいていきます。










