昨天整理的三個問題,本質上都是「缺乏產圖依據」。在著手制定規格文件前,我們得先釐清 draw.io 的底層檔案結構;唯有搞懂它的資料格式,才能知道當 AI 產圖不符預期時,該在哪個節點進行資料比對,並在規格中給出更具體的約束條件(Constraints),避免 AI 持續產生無效或破版的圖形。
本文的目的不是要手刻 XML,生成代碼依然交給 AI。
但既然 AI 產出的是 XML,我們的繪圖規範最終就是在約束這些代碼。如果看不懂底層結構,指令就只能寫出「請畫整齊一點」這種空泛的形容詞。因此,本文只聚焦會用到的關鍵結構與標籤,其餘細節直接略過。
以下的範例來自我手上一份真實的圖檔——同樣是麥克風權限檢查那段流程,在 draw.io 裡手工畫出來的版本。
打開任何一個 .drawio 檔,最外層長這樣:
<mxfile host="app.diagrams.net">
<diagram name="第 1 頁" id="7r_DkBgYFqEWnr_maO-v">
<mxGraphModel dx="2406" dy="1120" grid="1" gridSize="10"
page="1" pageWidth="827" pageHeight="1169">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- 圖的內容都在這裡 -->
</root>
</mxGraphModel>
</diagram>
</mxfile>
由外往內是四層:
mxfile:整個檔案。一個檔案可以裝很多頁。diagram:一頁。多頁檔案就有多個 diagram,Day 6 提過 MCP 的 list_pages / get_page / set_page 操作的就是這一層。mxGraphModel:這一頁的畫布設定,gridSize 是格線間距、pageWidth / pageHeight 是紙張大小(827×1169 是 A4 直式)。root:圖的內容。root 裡固定會有兩個空的 mxCell:id="0" 是根,id="1" 是預設圖層。所有實際的節點與連線,parent 都指向 1。這兩行不用管,每張圖都一樣。
真正要看的是 root 底下的 mxCell。它只有兩種身分,靠屬性區分:
vertex="1":節點,也就是圖上的框、菱形、圓形。edge="1":連線,也就是箭頭。一張流程圖再複雜,拆開來也就是這兩種東西的組合。
<mxCell id="7" parent="1" vertex="1"
value="使用者麥克風是否已授權?"
style="shape=mxgraph.flowchart.decision;whiteSpace=wrap;html=1;strokeWidth=2;">
<mxGeometry x="312" y="265" width="170" height="115" as="geometry" />
</mxCell>
拆開來看:
id:這顆節點的編號,連線要靠它來指認。value:節點上顯示的文字。style:長什麼樣子。分號隔開的一串設定,這裡的 shape=mxgraph.flowchart.decision 就是流程圖的菱形。mxGeometry:放在哪、多大。x / y 是左上角座標,width / height 是尺寸。<mxCell id="6" parent="1" edge="1" source="7" target="17"
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="140" y="322" />
</Array>
</mxGeometry>
</mxCell>
關鍵是 source 和 target:這條線從 id="7"(剛才那顆菱形)連到 id="17"。連線本身沒有座標,位置由兩端的節點決定;Array as="points" 裡的 mxPoint 是轉折點,用來指定線要繞哪裡走。
至於連線上的「是」「否」標籤,在這份檔案裡是另外做成獨立的文字節點(style 帶 text;),不是掛在連線上。這也是同一件事有多種畫法的例子之一。
看完結構,可以歸納出一組對應關係:
| XML | 決定 |
|---|---|
value |
節點上寫什麼字 |
style |
節點長什麼樣(形狀、顏色、線寬、字級) |
mxGeometry |
節點放在哪裡、多大 |
後面要寫的繪圖規格,管的就是這三件事。這也是為什麼規格能寫得具體——因為它們最後都會落到明確的欄位上,而不是停留在「畫整齊一點」。
舉個實際會遇到的狀況:同樣是判斷菱形,這份手繪檔案用的是 shape=mxgraph.flowchart.decision,但 AI 產圖時經常直接用 rhombus。兩者畫出來都是菱形,肉眼幾乎看不出差別,但 style 字串不同,尺寸與文字排版的預設行為也不一樣。如果規格只寫「判斷用菱形」,這件事就管不到。
有了 XML 的概念,昨天那三個問題會變得比較好處理。
一句話拆成幾個節點——就是產出幾個 vertex="1" 的 mxCell。數一下就知道 AI 這次拆成幾顆,跟上次比對也很直接。
迴圈被畫成直線——這個最有用。回頭看那條「返回錯誤訊息彈窗」:如果 AI 畫對了,這條 edge 的 target 會指向前面那顆彈窗節點既有的 id;如果畫錯了,XML 裡會多出一顆 value 一模一樣、但 id 不同的節點。看圖不容易發現,看 XML 一秒就知道。
沒有驗收基準——value 對得上流程文件的步驟嗎?每個判斷的兩條分支都有對應的 edge 嗎?這些都是可以逐項核對的問題,不再只能靠印象。
還有一件事值得留意。手動在 draw.io 編輯器裡調整過的圖,value 會被塞進編輯器產生的 HTML:
value="<span style="font-size: 14px;">使用者進入語音對話頁</span>"
光是隨手把字體改成 14px,XML 就會生出一大段標籤,改得越多,雜訊越可怕。這也是為什麼我在 Day 16 強調「依據要寫在文件裡,別留給 XML 雜訊」。手動改圖的痕跡缺乏系統性邏輯,下次要 AI 重產時,這些辛辛苦苦微調的細節全都會被洗掉
關於 draw.io XML 底層結構的解析,講到這裡已經足夠我們制定規格了。明天我們換個視角:把幾張實際的流程圖攤開來比對,找出那些不斷重複出現的共通結構,並藉此梳理出一張完整工作流的「全局圖」。