▍這場往「用 SVG 強化整體檢核」的互動應用走;技術上到底有哪些細節,我們在筆記上補充給各位老師
卓欣言老師這場,主 repo 裡幾乎沒有他的程式碼——他在 main 的完整足跡只有 issue #99、issue #100 兩則規格留言,和一個沒被 merge、後來由維護者手工移植的 PR #124。
但是,我們從分享過程中展示的 SVG 引擎、DirectContext3D 預覽、Route Graph、Topology Plan,全部住在他自己的第三個 repo:NicheSam/SC-REVIT。所以這份補述層要回答同一件事:在台下的你,該如何實踐出來?讀者該怎麼學習獲得自己跑一遍的能力?
- A = 在主 repo 即可獲得
- B = 請去
git clone NicheSam/SC-REVIT- C = Revit + 部署 add-in
他台上的主題 產物在哪 再現層級 169 個成功但位置不明 → 三點對位判準 main: domain/cad-block-point-placement.md+ 三支工具A SVG 手刻引擎、證據標籤、Route Graph SC-REVIT B 送回 Revit 做準心(focus contract)+ ADR-004 SC-REVIT B/C DirectContext3D 預覽、避樑 SC-REVIT C(DirectContext3D 只能在外掛跑) 穿樑 review_required、讀 CAD 順序、單位 skill main:既有 domain/skill A 他的研究方法論 第三個 repo: NicheSam/revit-mcp-research-partnerB 三個 repo:
- 主專案:https://github.com/shuotao/REVIT_MCP_study
- 他的技術本體:NicheSam/SC-REVIT
- 他的方法論 Skill:NicheSam/revit-mcp-research-partner
- 他 fork 的主 repo
NicheSam/REVIT_MCP_study授權提醒:
SC-REVIT沒有 LICENSE 檔,依預設全權保留。本篇只引檔名、函式名、行號、常數名與最多單行片段,不轉載大段原始碼。_
建立成功,不代表工程正確
各位老師好,簡單介紹一下我自己,我叫卓欣言,我目前是在機電工程公司服務。今天我們要先從「建立成功不代表工程正確」這件事情開始。
我們在 Revit 的建模過程中,應該有很多人還是會使用外掛去做工作上的建模。外掛這個東西,它只會負責幫你把東西建出來,不會負責幫你去進行後面這個驗證。因為你在做外掛、在使用外掛的時候,其實我們已經將後面的驗證、我們已經先做完了,我們才讓他去執行。

那我們今天要用 agent 去協助我們拆出來,就是要把這些過程把它拆到我們可以讓 agent 可以去執行。那先從「建立成功」這件事開始好了。

那這是我自己個人有開發、工作上使用的外掛,然後這個是我自己開發的點位放置的功能,就是連結 CAD,然後根據圖塊去批量放置族群這樣子。那這個功能有一個問題是:它會跳出成功的畫面,有「放置完成」、「我成功了 169 個」,但我沒有辦法知道它的位置是不是正確的,甚至它放在哪裡、比例多少,我全部都不知道。
位置錯誤的話,它會導致一個蠻常見、我這邊會遇到的問題是:他可能因為比例的關係,他根據原點放在一個非常遠的地方,他的比例很小,可能會有 1 比 10 甚至 1 比 100 的問題,所以他跑得很遠,我們人是沒有辦法發現的。

你就算把整個模型縮到最小,他也會——因為你模型整個縮小了之後,你也抓不到他。然後我也不知道為什麼,我用全部選取的方式,我甚至選取不到他。那我會抓到這個錯誤,是因為我有、我發現一些模型上的異常,然後最後用 MCP 的方式去把這個錯誤抓出來。
▍「成功 169 個」的疑問,他自己在 issue 裡先寫成了規格
產物:main →
domain/cad-block-point-placement.md+get_dwg_block_instances/preview_family_instances_from_dwg_blocks/create_family_instances_from_dwg_blocks「跳出成功畫面、但不知道位置對不對」,對應到主 repo 的 issue #100
「[提案] 將 SC REVIT 的 CAD 點位放置流程整理成 AI 可用工具」
三支工具是@Rumi-3653依這份規格在 issue #113/PR #115 寫的domain 文件本身明寫著三個驗收判準(§3):Transform 必須 finite/可逆/
conformal/等比例縮放;至少 3 個不共線 anchor,每點殘差 ≤ 1 mm;
而且特別警告:殘差 0 mm 不等於工程正確——那只證明兩條計算路徑一致,
不代表 CAD 原點本身沒錯。這正是他台上「跑到很遠都抓不到」的病灶。他寫規格,別人寫實作,第三方在文件裡誠實標註未驗證——這條路徑本身就是一種協作證據鏈。
_
三種不同的證據

也因為有上面這個「看不到就等於不知道」的困擾,那我們就要開始去想說,要怎麼把這些過程把它拆出來。那這邊會有三種證據:一個是我們有建立成功,這一定是第一個;元素存不存在,這是第二個;位置正不正確,這是第三個。
那畫面上可以看到有一個 BIM Agent 工作台,這個是我個人開發、就是個人用的一個 Agent。然後我給他的任務、小任務,一開始啦——一開始其實是因為我有聽到 BIMGO AI 的那個做法,然後加上 MCP 的做法,我就想說我想把它結合成一個、我只想快速進一些小任務,我也沒有想要寫那麼多工具的東西。但我後來它的定位,在我開發過程中就變成另外一個角色,那我後面會大概再提到。
人在按下外掛之前,已經做完的判斷
先講前提是,那我們在執行外掛的時候,我們會、我們人其實在後面做了很多判斷:我們怎麼讓、我們怎麼決定這個外掛可以執行?外掛——像這是我自己做的外掛畫面,可以看到說我們人要在中間經過很多的判斷。
我們要選我要連結哪一張 CAD 圖,連結了 CAD 中我要選哪一個圖塊,那他對應的是哪一個族群、高度、樓層,這全部都要我們人去做,甚至到預覽的部分:預覽我要去看它位置是否正確,然後如果不正確的話,我們人要把它調到正確的位置,然後最後這些都確定之後才辦執行。

如果上面有任何一個不正確,我們可以立刻判斷出來,就是我們人類在工作可以立刻判斷出來——這是不可以執行的,我們就去檢查為什麼了。所以我們要把這些事情把它拆出來,把它拆成一個流程,這樣子。
所以那就是最基本的框架:一定是先看懂我們現在在哪裡、要幹嘛;那候選,你接下來要做的東西,候選出來的選擇有哪些、你可以有哪些選擇,不管是給程式的還是給你的;然後接下來是判斷,判斷你到底能不能做,不能做我們就關掉,或者是檢查、可以再執行。

那這些東西原本都是由我們的經驗和知識去總和出來,但我們要交給 Agent 之前,我們就想要把它變成流程契約。那這就是我剛剛講的,這是一個可以審查的鏈,這就是依據這個模式去做什麼。

結果驗證:除了執行,還要再做一次回查
把前面四段串起來之後,這邊講一下結果驗證部分。結果驗證,其實我們通常來說,在有外掛、還沒有 agent 的情況下,外掛出來的東西就很簡單,就是肉眼去找他在哪裡、放在哪裡,去找他。那有 agent 的情況下,甚至說程式傳過來,其實也可以變成——
但我現在這件事,是用 agent 去查所有的、他建立的位置、座標、ID,是不是跟我設定的東西是一樣的,要去做回查這個動作:除了執行以外,還要再做一個回查。

我怎麼跟 Agent 合作:把輸出拉到我看得懂的層級
我要怎麼跟 agent 合作去做開發?那合作開發,其實我根本就看不到、原來講說,事實上就是這樣。剛剛講一大部分、前面講的很多東西,其實我相信很多人也沒有聽懂吧。
可是要怎麼做合作?我就需要把他的輸出把它拉到跟我同一個層級、拉到我可以理解的層級。但我很不建議的一個方式叫做類比:有些人會把 AI 講一大串東西,我看不懂,我說你類比給我、解釋給我聽,那中間他其實會整個細節就全都掉,它就只會用讓你可以理解的方式解釋給你聽,你什麼細節都聽不懂,因為你跳過了。
那我的方式,因為我現在要做的是建模,我要看圖、我要讀圖,所以我用的是 SVG 的方式。SVG 它有向量的資訊,甚至程式本身產生出的 SVG,它可以再回推鎖定去對應到你要建立的那個區域的物件,這後面會再判斷。

▍為什麼是 SVG
產物:
NicheSam/SC-REVIT→sc_revit/fire_branch/network_diagram.py(1,579 行)這支檔案的 import 只有五個:
html、math、collections.defaultdict、pathlib.Path、typing.Any。沒有 svgwrite、沒有 graphviz、沒有 networkx、
沒有 D3——SVG 字串是用 f-string 一段一段拼出來的,例如<svg ...>
標籤本身就掛著data-coordinate-space/data-orientation-source/data-cad-verified/data-cad-status這些屬性。
data-*不是裝飾,是連動鍵:每個管段的<g>元素(network_diagram.py:1253)
掛著data-plan-entity-id/data-row/data-sequence/data-diameter-mm/data-source-color/data-evidence——這串屬性後來被用來反查回 Revit(見 A12)。_
CAD 圖塊放置:先確認物件身分
說完方法,好,那我們先從我主要的外掛、這個圖塊放置這個外掛開始。我要先第一件要做的就是:我要確認這個我今天要幹嘛、我要確認物件的身份——它從哪裡來、它是誰、接下來它要變成什麼樣子。
但這個部分,這是我判斷下來,這是我們目前還是要由人工去處理。就是你既然要做圖塊放置這個功能,這是你人必須要介入的,這個不可以交給 agent 去處理,不然就是會變成你其實你也不知道你在做什麼了。
那我這邊有遇到一個問題,然後也還在研究中:就是我可能、因為我是做機電的,所以我會遇到的是族群,很多族群他的放置方式會限制有主體。那這個主體在我目前外掛是沒有解決方法,就是我可以、我通常來說我可以限制說我想要放在 300、我可以放在 200,可是目前貼附族群的部分還沒有辦法被解決,它就是我現在遇到的一個問題。那我現在實務上的做法,就是我去畫一個一模一樣、把貼附族群這件事拿掉。

先查單位,再查座標:三點對位

身分確認完之後,那既然要做點位放置,其實就是會有對位的問題,對位就是最主要的問題。那會有兩個方向、兩個方向的問題要去解決:第一個是座標,第一個是單位。
那座標這件事其實算是比較好解決的,因為我是用連結的方式,所以理論上我只要在該樓層把 CAD 的圖已經定位完成了,它就可以自動抓好原點,原點就可以自動抓好。所以它原點不太會是一個大問題,最大問題是單位的問題。
單位,我們人在做就是公分、millimeter,這個就設定好就好;可是回到 Agent 或程式,我要怎麼去判斷它是對還是錯?因為我剛剛有講原點會是對的,但是你單位錯的時候,它會整個放大十倍、縮小十倍,然後當你、你想要去找的時候,你還找不到它。
那我想出來的一個方法是,用三點對位去做驗證:我自動從原本連接的 CAD 去抓出三個不共線、不共軸的點去做設定。那我放到 Revit 裡面的時候,我要讓他去做這件事的時候,他得——因為單位這件事就是,他就是那幾個單位在跑而已,他就是自動在那個座標去驗證,這三個點它必須完全一致,這樣我就可以辦法去證明說:在確定座標狀況下,這個單位會是正確的。

▍三點對位的信任門檻:投影片上「比例 X = 10」不是舉例,是真實實測
main →
domain/cad-block-point-placement.md§3P12 投影片印的屬性表上寫著「比例 X 10 / 比例 Y 10 / 比例 Z 10」「位置 X 293610892.5」,
這就是他講的 1:10 單位錯誤實際跑出來的樣子——原點理論上是對的,但單位一錯,
座標直接飛到天邊。主 repo 的 domain 文件把「三點對位」寫成四條判準(§3):
Transform 必須 finite(無 NaN/Infinity)、可逆(determinant ≠ 0)、
conformal(角度保持)、等比例縮放(X/Y/Z 縮放係數一致);
鏡射可以繼續但要警告,非等比例縮放判定不可信、必須停止。
可信度至少需要 3 個不共線的 anchor 點,每點殘差 ≤ 1 mm。投影片上那個跑到天邊的物件,和文件裡那條「0 mm 不等於工程正確」的警告,講的是同一件事。
_
那會遇到一個問題是 CAD 圖本身的品質問題:是圖塊假設你的原點亂設,我也沒、沒救嘛。對啊,因為我還是以座標為主,所以你圖塊亂設,他就會很精準的放在錯的位置。
但是這邊其實還是有好處,因為你的排列上他是穩定的,所以——而且我的設定上是你放下去的族群他會是一個群組,所以假設你今天真的沒辦法、你真的錯誤了,你就把想辦法拉到回來原來位置,你只要拉對一個,接下來全部都會對。但建議還是把 CAD 的原本的設定做好了。
預覽:一開始的模型線,變成了模型污染

那我們剛剛已經講完那個身份確認的部分,那接下來就會到預覽的部分。我們要——我們終究還是會相信自己的眼睛啦,所以預覽是一個很重要的階段。
那預覽,我一開始想到、就是這一開始還沒有跟 agent 一起開發、不能說 agent 一起開發,就是還沒有想這麼遠的時候,我想到的是我要在平面上檢查,我也要在 3D 上檢查,因為我有高度問題,所以我想要在 3D 上也要檢查。
怎麼檢查?我一開始想到的方法是用模型線,然後在模型線我也可以設一個群組,這樣我只要他對位的方式、對位位置錯了,我就可以直接整個拖動群組到他對的地方,這樣做校正的方式。一開始其實都蠻順利的,一開始都很順很順。
然後接著就發現一樣跟那個、跟座標一樣,跟單位有一樣的問題,就是在很遠的地方那個預覽線被留下來了。所以像圖上就會看到:模型在右上角,結果我預覽線在右下角,然後我發現不了它。我是後來去找它、特地去找它,用 agent 去找它,我才找到它的。
所以它 agent 在這邊,作用主要是幫我定位出這個錯誤在哪邊,接下來我應該用什麼樣的方式去解決它。那我後來就將預覽改成不寫模型的方式,那也是 agent 跟我討論完說:那建議可以用 DirectContext3D 這個方式去做,然後也嚴格限制說:在我執行外掛的每一個階段,這個預覽都會精準的被刪除,不要留在我的模型裡面的。

▍模型線污染 → DirectContext3D:main 做不到,這是硬邊界
產物:
NicheSam/SC-REVIT(DirectContext3D 繪圖)他一開始用模型線做預覽,結果跟座標一樣栽在單位問題上:預覽線被留在很遠的
地方,肉眼找不到,得靠 Agent 去定位。後來改成 DirectContext3D——不寫模型、
每個階段結束都精準清除。羅老師在 Q&A 給了
明確裁決(見 A21):DirectContext3D 是直接對 GPU 下繪圖指令,跳過 Revit
主體程式,只能在外掛裡做,MCP 無法觸發這個層級的動作。這跟 A03 的 SVG 選擇形成對照:SVG 是「離開 Revit 看清楚問題」的工具,
DirectContext3D 是「留在 Revit 裡但不污染模型」的工具——兩者解決的是
同一個症狀(預覽會弄髒東西)的不同階段。能不能做,不是技術選擇的問題,是 Revit API 分層本身劃出的邊界。
_
安全執行:整組回退害我卡了一整週

預覽解決了,那接下來是要證明安全執行,我們就要先放有失敗的東西在裡面。那這邊其實是我踩過了一個坑,就是,呃,我一開始把這件事——理論上我們就會想的比較嚴格一點:只要有錯誤,我就不該留在模型、不該留在模型裡面,所以我整組回退。
然後接著我就陷入了大概一整週的開發迴圈,因為我忘記了他只要一個小錯誤,他就會全部回退,所以我一直覺得我做錯,結果發現只是我一個小小的地方、根本就不重要的地方做錯,所以他全部回退了。
所以後面的策略是:驗證成功的絕大多數、成功的都會留下來,只有失敗的他不會被建立。然後這在後面的案例中也會再次出現。

那建立完之後,我們還要再回到模型再檢查一次。通常來說我們用肉眼檢查就可以了,但是我前面的 agent 在這時候就是他發揮作用的時候,就是我個人開發 agent 的話,我讓他接下來的任務其實主要是:他要能夠讀取我每次建立的東西的座標的狀態的位置,然後去核對跟我的要求是不是符合我的要求的。那基本上這部分還沒有出什麼問題,所以我們就完成了 CAD 圖塊這件事的驗證。

那前面的物件身份和族群控制,這些東西就保證還是——這分工上,還是你該做的就要把它做好;但是後面的預覽、座標,這些當然這些是給人看的,但是給 Agent 用這些驗證方法就直接過去了,就是後面 3、4、5、6 的部分都交給 Agent,目前來說是沒有問題的。

穿樑:候選不是許可,Agent 要知道在哪裡停
以上是圖塊放置這個案例。那接下來是穿樑。穿樑的部分,那其實穿樑這個東西不管是有沒有 Agent,從這一開始由外掛的時候,這個東西已經講到爛了啦,就是已經講了不知道多少次了,大家做了很多種不同的應用。
那我在這邊其實要做出來的判斷是:什麼工作我們可以交給 agent,什麼工作我們要保留自己做。其實穿樑這個東西,你甚至都不用交給 agent,他用程式就可以把它跑完,他可以判斷出哪裡有穿過、哪裡需要審查,就基本上可以列出表給你了。

所以這邊要決定出來的東西,其實是 Agent 應該在哪裡做停止。因為穿樑過去不是——因為我只是建立模型,我沒有辦法決定說這裡到底可不可以這樣穿。所以我要做的只是讓 Agent 去讀取程式分析出來的結果,然後去判斷說:那你應該用什麼樣的資料、什麼樣的條件去跟其他專業做溝通、去跟其他專業做溝通。

▍review_required 就印在他自己的投影片上
main →
scan_opening_candidates(MCP/Core/OpeningCandidateScanner.cs,412 行)
domain/mep-opening-candidate-scan.md定義了candidate/review_required
兩種狀態,review_required有 7 條觸發門檻(§〈狀態判定與 warningCodes〉),
一旦觸發不得自動晉升為 candidate。文件實測依據寫明:13 筆掃描結果中,
12 筆為穿樑(review_required),僅 1 筆為穿樓板(candidate)——
多數真實案例本來就會落在需要人審的那一格。投影片表格上的三條要求(說明候選、說明理由、指出缺口)跟 domain 文件的
精神一致,但這份 domain 文件的實作不是他寫的——他提規格(issue #99),由他人實作。
_
因為我們還要經過、可能還是要問專業技師,去說這樣可不可以,還是要去做溝通,所以這部分還是要保留,去分出人跟 agent 的工作邊界。

消防支管:從純手畫到逐步內化規則
從幾何判斷再往前推一步,那接下來是花了我蠻多時間的一個部分,這是消防支管的部分。那最早來說,沒有外掛的時候就是純手畫:一個一個灑水頭、一個一個放,然後管一直一直畫。那我就覺得這樣很浪費時間,複製過來我還要在那邊換接頭、重新拉。
所以我就先做了一個外掛,它可以——因為我前面已經做好點位放置了,那我是不是把那個灑水頭都放好,然後想辦法讓支管連回主管就可以,理論上是這樣子,所以一開始的想法是這樣。
所以早期外掛可以就是說:我可以讓支管自動連回主管,但是管徑沒有辦法自動做變化,然後路徑沒辦法自動偵測。所以我假設框選一個地方的灑水頭,他有可能連到的是錯誤的主管。
那我接下來把它處理到、就是接下來要講的部分,就是讓他怎麼樣可以處理變徑,和怎麼樣處理、怎麼樣去偵測主管和接頭。但是目前還沒有辦法做到整個樓層自動生成這樣,我還應該研究出來,但沒那麼快這樣。
那第一版我自動化的,只是把這個東西畫出來,我只是把它畫出來而已。後續的,你要去根據圖面去做變徑,然後要連對主管、走特殊路徑,這些全部都是要、還是要自己處理,而且路徑限制其實也蠻大,因為路徑很特殊就沒有辦法處理了。

▍第一版外掛的三個限制,後來各自被哪個模組解掉
產物:
NicheSam/SC-REVIT
第一版限制 解掉的模組 管徑無法自動變化 diameter_analysis.py(1,128 行):parse_diameter_text、analyze_diameter_evidence路徑無法自動偵測(只能單向度) cad_route_graph.py(684 行):build_cad_route_graph、build_revit_route_candidate_decisions整層自動生成 未解 _
先決定路徑,再從路徑抓管徑的證據

第一版做完之後,那接下來下一個我們要發展的是:我們要怎麼去判斷路徑和管徑?那我們怎麼判斷管徑?我們人就直接看圖啊,看圖上面長什麼樣就怎麼樣啊。那 agent——要不要說 agent,程式要怎麼看圖?程式要怎麼看圖?
那就要先決定他的先後順序是怎麼樣。我們應該先判讀出來路徑,就是這在我們人的腦海裡是一眼過去就是了的東西,但我們要先把順序決定出來:先把路徑決定好,再從路徑去抓管徑的證據。
那接下來的,我先講怎麼抓,因為這前後有點放錯,先講我是怎麼抓管徑的。管徑的話,我是依我們看圖的習慣下去:圖上面它就是會標一個 1 又 4 分之 1 寸,那我們就會判定這一段它就是這個管、它就是這個管徑。
那我們還會看到圖面,技師可能會備註說:沒有標註的管是多少,所以你也要去掃這些東西,把它變成規則。那接下來就是顏色,有一些是它可能就標三四個管的顏色,標完之後剩下就是反正同顏色就是同一支嘛、同一個管徑的。

▍管徑證據排序 11 種標籤
產物:
NicheSam/SC-REVIT→network_diagram.py:58-70_EVIDENCE_LABELS文字標註 > 線段顏色 > 圖層——在程式裡是一份 11 項的字典:
代碼 顯示標籤 explicit_color文字+線色 explicit_nearby鄰近文字 line_color_reference線段顏色 layer_reference圖層參考 drawing_defaultCAD備註預設 conflicting_label/conflicting_color文字衝突 / 線色衝突 diameter_increase_conflict反向增徑待確認 unresolved待確認 uniform_user_setting統一設定 user_revision使用者修正 解析邏輯在
diameter_analysis.py(1,128 行)的parse_diameter_text,
含_UNICODE_FRACTIONS常數處理「1 又 4 分之 1 寸」這類中文分數標註。
_
那把這些證據建立起來,然後去建立先後順序。現在圖上面有點錯誤啦,但其實線段顏色應該其實是第二啦,他排名應該是第二;第一應該是標註文字;然後最低最低的是圖層,因為有些技師會用圖層去分類的。但一樣嘛,圖層就是一個最容易出錯的東西了,所以不要相信他。對,真的我們前面都沒救了,我們才看圖層,但通常前面沒救的時候,圖層通常也沒救了這樣,哈哈哈哈。
支管這東西他其實規則是很簡單,但是我們還是遇到少數因應空間需求去做變化的路徑,但這目前我還沒有把它做到可以自動偵測。但這理論上是不會太難的啦,但我現在還沒有辦法把它做好,所以少數路徑還是需要由我們去做處理,目前是這樣子。

以主管為基準,長出十字形候選

那接下來講說,那我們找到管徑的規則之後,那最重要就是路徑的規則了。原本的外掛他只能偵測一個向度的主管,所以他只能一個直直的管,你一個 L 型的管他就直接跟你報錯了。那我要怎麼做到可以讓他選取一大段主管之後,可以正確的找到他要的路徑呢?
那我採取的方法就是:我當然還是會、我還是需要先建立主管,我可以把一大段主管都畫出來,那我框選的那些灑水頭,我讓他自動長出十字形的候選線,每一個灑水頭都有他候選線。
然後因為我剛前面有講到點位那個、圖塊放置的時候,我有講到三點對位嘛,那個時候那個東西就可以拿來這裡用。我這樣把圖面對上去之後他就可以抓到:那這個候選路徑上面,他的連接的、背後是不是有連接到主管的那條線,讓他自動去抓出來去做候選。
那這邊就出現一個出錯的功能。其實我是會很框一大區、隨意框一大區的灑水頭,我一定會框到不屬於這個主管的灑水頭。這個時候就要做一個出錯:是這個灑水頭出來的候選,他好像候選到主管的,可是他的 CAD 沒有證據、他的 CAD 沒有連到,那他應該要自動排除,他不應該讓他自動生成——只有有 CAD 證據的那些灑水頭,他才應該被生成出來。
▍十字形候選 + 無 CAD 證據自動排除
產物:
NicheSam/SC-REVIT→sc_revit/fire_branch/cad_route_graph.py(684 行)
cad_route_graph.py裡對應的三個函式:build_cad_route_graph(建立路徑圖)、compare_cad_route_candidates(比對候選與 CAD 實際連線)、build_revit_route_candidate_decisions(產出最終要不要建的決策)。
_
第一張 SVG 就證明策略錯了

也因為候選判斷變複雜了,那 SVG 在這一階段就出現了。我一開始他給我回報的東西看不懂,就是我要一個字一個字看嘛,然後又看不懂。我們最喜歡看什麼?我最喜歡看圖了,所以我們就生一張圖來給自己看:他怎麼判斷的,他就怎麼生圖。
所以他生出來的圖,第一張就像左邊這張一樣,就很明顯這絕對不會是對的東西嘛:就顏色也不對、路徑也不對,然後放的位置也不對,就就是非常奇怪,甚至方向也都是錯誤的。
那我就要一個一個去修、一個一個去修,修到像右邊這樣,這個看起來就穩定多了。這個時候你才會知道:誒,程式生出來的東西跟你看到的東西、誒,跟你想的東西是不是一樣的?這是你們的溝通介面。
然後而且這邊我覺得一個很好的點是:因為我在做外掛的時候其實會需要一直更新 DLL,然後我就要一直重開 Revit,然後重開 Revit 我就要等很久;然後 SVG 它可以在 GUI 裡面去做更新,所以它只要更新完 GUI,我只要重跑一次就好。所以這個修正其實是看起來很麻煩,但其實是我做裡面最快的。
SVG 可以承載資訊,反向定位回 Revit

那接下來就是一些那個實機的畫面。為什麼要用 SVG?這是我外掛的畫面。那 SVG 在這裡的價值是,我可以觀測到他的錯誤到底是在哪裡,這是他根據我的現況去抓出來的 SVG。
那我就要開始找:喔,這個東西在哪裡?怎麼找?用 SVG 就好了,SVG 可以承載資訊。那 SVG 承載資訊,他是不是可以自動送回 Revit 去幫我做準心?我就可以找到他在哪裡。不然我看那個東西,假設在第四排第五個,我還去算 1、2、3、4,1、2、3、4、5,就不用做這件事了,直接對應就好了,而且這樣就會很快的去抓到錯誤在哪邊、為什麼會有這個錯誤。
SVG 圖這個規則其實跟我們建模規則他是不一樣的,建模規則不一樣。所以最終接下來要做的,就是讓 SVG 圖的規則跟你建模的規則要用同一個計畫,讓他是依據同一個計畫去做。不然你 SVG 建得很開心、很開心,結果錯了之後,然後建模完全不是照你意願來,就那做爽的嘛。

▍送回 Revit 做準心,他已經做出來了;ADR-004
產物:
NicheSam/SC-REVIT→queue_protocol.py:552(create_fire_branch_focus_request)
→client.py→revit_addin/.../FireBranchHandler.cs
queue_protocol.py:552 create_fire_branch_focus_request產生action="focus_fire_branch_preview_segment"的請求,寫入檔案式 JSON
queue(ensure_queue_dirs/_write_request_json,Python↔Revit 是走
檔案,不是 WebSocket 8964)。Revit 端FireBranchHandler.cs收到後
呼叫uiDocument.GetOpenUIViews()+uiView.ZoomAndCenterRectangle()。
契約測試test_fire_branch_focus_contract.py的方法名寫死是test_revit_handler_zooms_open_active_view_without_model_mutation——
唯讀縮放定位,不動模型。
_
穩定規則回外掛,不確定的留給 Agent 和人
回到結論,所以這邊就回到說,我剛講那麼多,其實 Agent 部分沒有那麼多的。最後我是將穩定下來已經確定的規則,我們就人工就不要再做了,我們回到外掛做就好了。在這個案例中,Agent 是拿來建立說:去觀測錯誤在哪裡、規則是怎麼樣的、要怎麼整理、要怎麼定位,去把這些事情資訊整理出來給我,然後再幫我寫修正計劃。

那這是目前做出來的成果。可以看到有一條主管跟超多灑水頭,我的做法就是將這一整段圈起來,我沒有選擇,甚至我圈到其他電箱我不管,可是因為這我已經先篩選過、就是程式上有篩選過,所以我不管他。
所以我先選取主管,主管他偵測到了之後,知道管徑嘛、高度抓多少,然後我有做自動避樑,但是這個功能相對簡單,這邊就先不講。然後讀取到灑水頭之後就可以開始分析,當時去進行分析,稍微等一下。
好,然後這就是預覽的部分,可以看到螢光路徑,就可以看到說、這邊就可以看到說,我剛選了這麼多灑水頭,他其實是有一部分他是不符合這個主管的。我們再看一次好了,螢光路徑的部分就可以看到他理論上會長什麼樣,這時候你已經有信心了。
有信心了之後,然後接下來他等一下會出現說一個錯誤——哎,跳掉了,不好意思。這個你可以看到「部分灑水頭已略過」,因為我選了一大堆的灑水頭,但其實我的主管沒有點到這麼多灑水頭。那這時候要做的不是錯誤全部退回重做,這時候是把這些錯誤略過,然後不要給他們任何的候選。
然後接下來就可以看圖了,就可以看 SVG 的圖了。這就看,這跟你的想像、你可能拿 CAD 來快速迅速兩眼去對一下,其實大致上不會有什麼太大的問題,就快速的對一下,就不用一個文字一個文字看,因為你也沒有耐心。然後接下來確定都沒有問題了,就可以建立了。
那這邊展示的不是、不是說 agent 有多厲害,而是說這些都是已經很確定的東西。我覺得這時候你教 agent 反而是有點、這時候有點浪費時間,因為他要跑、他還是要跑,那這東西就交回去給外掛,讓他甚至說——因為我現在規則已經穩定下來,甚至之後我可以把這個錯交給 agent 去用也可以。
然後這就是目前建出來可以達到的成果:就是他也可以自動避開你連結的圖面模型的樑,然後做到自動變徑這樣子,然後自動可以偵測他應該連到哪一支主管。

▍成果三件事,各自對應哪個模組;外加 30 支契約測試
產物:
NicheSam/SC-REVIT他說做到的三件事——自動避開連結圖面模型的樑、自動變徑、自動偵測該連
到哪一支主管——對照的模組:
成果 模組 自動避樑 structural_avoidance.py(133 行)自動變徑 diameter_analysis.py(1,128 行)自動偵測主管連接 cad_route_graph.py(684 行)+model_plan.py(465 行)repo 根目錄有 30 支
test_*.py契約測試,其中 17 支是test_fire_branch_*(涵蓋cad_route_graph、diameter_analysis、model_plan、structural_avoidance、focus_contract等)。
這批測試不是事後補的驗收文件,是他讓「候選→分析→建模→定位」這條
鏈條在改動時不會悄悄壞掉的機制。成果展示是一次性的畫面,30 支測試才是他每次改動都要過的關卡。
_
我們跟 Agent 到底該如何協作
所以其實上一次參加這個讀書會的時候,我就其實在想一件事就是:我們跟 agent 到底該如何去協作,在日常的工作中?因為在我教同事怎麼使用這些東西的時候,其實會有狀況是——同事超會用外掛、超會建模,他弄超快,他問:「所以我要這個幹嘛?有比較快嗎?」會有這個問題。
那我就回到工作流程上去思考:那我到底 agent 可以幫我去做什麼?那我得出的一個方法就會是:要將那些我們已經想好、已經固定的規則把這些時間省下來,讓它變成一個更強的外掛。
但是我還是要保留 agent 在裡面的能力,還是要讓它有觀測的空間。甚至把我這個更強外掛——不是說他功能更強,當然這也是我認知邊界的問題,就是我認知到的外掛只能這麼強,當然跟 Agent 協作之後外掛可以更強,只是我想不到。

但另外一個部分是,他更強之餘,而是他把規則都定下來了。規則定下來之後,我後續要再交、轉交給 Agent 去做操作,這件事也是完全做得到的。

那我的結論就會是:外掛它還是一個很重要的東西,我還是需要它去做一些很穩定的規則、要重複做的事情,我也沒有想要把它浪費我的 Token,不想要,我每週額度就那樣子,我不想要給它用。對,主要是這一點,額度很重要、額度很重要的。
那我就將這個研究的方法、這個思考的脈絡把它整理下來變成一個 skill。那它這個不是讓你去整理成一個外掛、整理成一個 tool skill,它只是要協助你去釐清說:你今天要做這件事情、你想優化這件事情,它應該要給誰。

▍他的 skill = revit-mcp-research-partner,P34 的五個交付去向
產物:
NicheSam/revit-mcp-research-partner(README.md、SKILL.md、agents/openai.yaml、9 份references/*.md、4 張assets/*.svg)他把整場研究方法沉澱成一個 Codex Skill。README 明寫:「重點不是自動產生 MCP Tool,而是把既有
外掛、人工流程、Domain SOP、Issue/PR 討論、模型證據與失敗紀錄,轉換
成能力地圖、最小試驗,以及可審查、可交接、可驗證的下一步」,
「判斷成果應該回到哪一層」。
「產生可審查的表格、SOP、Issue draft 或 SVG 脈絡圖」。repo 裡有 9 份
references/*.md,其中revit-mcp-study-contribution.md
專門討論怎麼把研究成果貢獻回shuotao/REVIT_MCP_study——這個 skill
本身就是他自己在 A01/A07 那條「規格→他人實作→維護者收編」路徑的方法論版本。
_
它不是什麼東西都要去做成 MCP 工具,他有一些東西他該回到外掛就回到外掛,該交給人就交給人,該怎麼做就要怎麼做,而不是所有東西都把它做成一個工具。那右邊的話是我個人開發外掛,就是單純是開、讓工作比較順利的,所以大家可以用用看。
小結論是,那我的想法就會是,在這個過程中,就是 Agent 去幫我們做到的事情,其實是像流程顯微鏡的行為:他幫我們把我們、我們藏在腦海裡面的知識和過程把它整理出來,而不是——在我的邏輯中,他不是一個超級厲害的建模、是一個超級快的建模員,是幫我把這些東西都拆出來的。那今天分享到這邊,謝謝大家。

問答:貼附族群、接頭與清 CAD
碩濤:你一定要去認識幾個人。第一個就是羿謙,對對對,你剛剛要做那個自動管線的部分;還有另外一個是鈺傑,他們兩位都是之前有分享的老師,特別在MEP這一塊部分都算深耕的!會後你可以去跟他們討論,那你們可以交換 LINE。
那另外一點,其實我想要問問題。第一個是,你剛剛在做 Revit,你的那個高度沒有辦法設定的原因是發生在那邊?高度沒有辦法設定的原因?
卓欣言:其實是因為我的測試中它會、我只要——因為我是設定在樓層上,就是我會指定它在哪一個樓層,然後在偏移多少高度,然後我才做這一步,它就會吸附到那個樓層。
卓欣言:我現在是他沒有辦法自動判讀有沒有 host。所以我現在實務上的解法是:這個族群他有 host、我想用他,然後我就只能去再建立一個有那個沒 host 的。
主持人:所以是可以勾成那個嗎?
卓欣言:不是不是,他是兩個族群,應該會是——我的理解應該是兩個。
主持人:所以你應該在剛開始的時候,你就要先決定你到底是要用 host 還是不要。
卓欣言:我可能就要把 host 這個條件放到外掛裡面,但我還沒有把它優化上去。
碩濤:那另外一個其實是想問你的,你剛剛在說接點的部分,如果 Revit 裡面沒有接點的話你怎麼辦?沒有接點的族群的話你怎麼辦?他沒有彎頭也沒有接點的話怎麼辦?
卓欣言:沒有彎頭沒有接點,你要先做給他。還是得先做給他,你的佈線偏好得先設定好。不能——我目前是沒有說自己去編輯佈線偏好的部分。
碩濤:我建議是直接你可以,因為我最近也是做很多 MVP 的東西,你可以讓 MCP 去呼叫,就是 Auto、就是 Revit 裡面他可以去 load 的就是元件下來,他在 Insert 裡面可以去找官方的,去把他的彎頭那些都拉下來就可以了。那相關的細節我們在——我再錄給大家看好了。
用球體定位接點、用 DFS 算管徑
羿謙:我做過類似的,就是前面那個放置設備的、那個圖塊原點問題的話,我覺得現在我會先用 CAD 的 MCP 去看,就是 CAD 的 MCP 看的話,它可以先把檢查部分都抓出來。那以前沒有 CAD 的 MCP 的時候我會、就是把那個——我直接取線,然後線在虛擬的擠出,那個就是剛剛那個 3D 的幾何,然後用那個 3D 幾何的剖面框來檢測放的位置有沒有對,直接在 CAD 裡面做這件事。我剛剛講那個擠出幾何跟剖面框,那個是 Revit API,我是沒有用那個 SVG。
因為我後來發現,那個變徑的規則是一條法規,就是它的、這個我還沒有把它整合進去,它是取決於就是他連接到多少個灑水頭。所以說你可以做的事情是,就是跟他說:從每個灑水頭就是發射一條路徑、就是 DFS 路徑之類的,然後路徑經過幾次,代表那個管就是支援幾個灑水頭,然後他就要導出,可以把這個資訊這樣子截取出來,然後你就不用看那個 CAD 上到底寫什麼、還寫在哪邊,那個都亂七八糟的,那個不可靠。
我之前碰到的問題是,他那些有些設備可能什麼一齊開放閥還是什麼,那個會讓那個整個路線先斷掉。那我後來就是反正都先給我接起來,然後接起來我算完管徑之後再放,就是有點像是放管配件的那種方式,然後就把它再斷掉這樣子,就會離一次做完整棟樓層比較近一點。
徐灝:我有兩個問題,我先問他。你剛剛說那個疊線、不是疊線,那個看通過多少支管然後去算管徑那件事情,那如果說這個 CAD 圖本來沒有清過的話、裡面有疊到的話,會發生什麼事?
羿謙:那個就是看你要怎樣把它整個接起來。我的做法是:立管長出來之後做一個球體,然後球體包含到的接點,就是在生成三通、或是十字通、或是彎頭,就看數量。
徐灝:所以說你要就是——這個是比剛才那個一齊開放閥、我們把它接不起來還要小的問題,因為那個通常是比較容易接起來,接點就在那邊了,反正怎樣他都會通就對了,但是他必須要先把接點做定位,所以他才會用那個圓圈圈。
羿謙:這段沒有問題我就沒有講。這一段我的解法是:我的灑水頭的立管長上去之後,我就生成一個球體,然後球體的半徑是可以設定,可能 60 公分或多少,看你那個 CAD 圖塊多大;然後那個球體裡面包含到的接點,就代表接頭的數量,接頭的數量就生成三通、十字通或彎頭,然後接起來。
▍球體定位接點:容差寫死在常數裡
產物:
NicheSam/SC-REVIT→model_plan.py:12_JUNCTION_TOLERANCE_FEET = 5.0 / 304.8model_plan.py裡對應的常數是_JUNCTION_TOLERANCE_FEET = 5.0 / 304.8
——換算回來是 5 mm 容差(304.8 是 mm→feet 的換算係數,Revit 內部
長度單位是 feet)。這個常數被build_fire_branch_topology_plan用在
判斷兩個接點是否應該被視為同一點(_point_distance(...) >的多處判斷)。
_JUNCTION_TOLERANCE_FEET
_
同事願不願意用:讓他們參與開發過程
現場提問:我還有第二個問題想要問卓老師。其實我之前在某一次小聚的時候,有聽到一個東西是說:我們開發了外掛、開發了功能,要讓其他 user 真的願意去用,才是最難的那件事。我還蠻好奇,就是你現在做的這些看起來真的很好用,沒有錯,可是你們公司裡面真的開始撒下去了嗎?這一個狀況怎麼樣?
卓欣言:因為我們的、在畫圖的大概就是三個人。那其實在畫過程、就是在開發過程,我就先長一個初步的功能,我的想像是什麼樣子,那我就會請他們來看:你們的想像是什麼樣子?
他們就會跟我——其實我覺得你這樣弄我會比較喜歡,就是我會在開發到最初一個版本的時候,我就會請他們先過來看,然後他們覺得你再多一個這個東西、或者是這個按鈕怎麼樣,是不是可以一鍵這樣子。
他們就會覺得其實他們是有參與到一點點,然後開發完之後他們也更願意下去使用,然後使用完之後他們還會再跟我講說,我覺得這個東西還可以再加什麼,然後會再自己跟我說他的想法。但是是因為我們三位的關係都還蠻近的,所以我可以比較直接去聽到他們的想法這樣子,然後也讓他們參與一下過程。
讀 CAD 的順序:先文字,再說明,最後才顏色
碩濤:大部分初學者進去的時候,他會花很大的力氣在先去辨別 CAD 的圖層,但是你會發現,就像嘉祥最近他分享的一件事情就是:你看到這一張 CAD 裡面是彩色的,結果它裡面是沒有圖層、只有一個圖層,所以大家都去換顏色。
所以像剛剛這樣的做法你看喔,他會先抓文字。原因很簡單:文字往往就已經是一個向量了,他有可能是一個——除非今天這個畫圖的人很缺德,又連文字都把它炸掉。所以能夠讀圖的大部分文字,他就是一個可以被定座標的東西,所以先讀文字;然後呢再來它的圖面的說明,它旁邊會有圖框、它會有一些說明文字,這個東西也可以做;然後再來才去對顏色。所以如果你今天是倒著做的話,你往往會先失敗。所以我覺得這個是一個、我認為在討論上面一個很重要的事情。
▍讀 CAD 的順序:先文字,再說明,最後才顏色
產物:main →
domain/dwg-column-import.md/domain/dwg-beam-import.md
的textLayerName機制 再現層級:Amain repo 裡最接近的落地機制是
dwg-column-import.md:
用 CAD 上的柱號文字(textLayerName參數)去比對既有族群類型,
「依 CAD 柱號文字比對族群類型;找不到回unmatchedLabels、不亂建」。
文件明寫:讀柱號文字只能 Link CAD——Import CAD 因為GetExternalFileReference()會丟例外、無法取得原始檔路徑,工具會
直接擋下並提示改用 Link。dwg-beam-import.md也有對應的textLayerNameX/textLayerNameY兩邊的順序邏輯一致:文字標註優先於圖層/顏色這類容易被亂改的視覺屬性,
這不是他或主持人各自發明的巧合,是同一類 CAD 判讀問題收斂出的同一個答案。「先讀文字」不是這個社群的共識口號,是兩個獨立系統各自被 CAD 髒圖燙過後,收斂出的同一條規則。
_
DirectContext3D 能做什麼、不能做什麼
嘉祥:我覺得他這次發表裡面最重要的一個東西是,他帶一個東西是之前全沒有人做過、可是很重要的功能。這個功能就是你以前在跑 Dynamo 的時候,Dynamo 裡面的 Geometry,他會在 Revit 的模型裡面,他會去秀出一個一樣的幾何圖形裡面來,他會修正那個幾何圖形來。
第一個,這件事情 MCP 不能做,他只能在外掛裡面做。對,你可以叫 MCP 讀這個資料,可能叫 MCP 做的時候他會做,因為他是直接——雖然他是透過 Revit API,可是他是直接跳過 Revit 的主體程式,直接對 GPU 去下,他要去做繪圖指令。第一件事情是這件事。
然後第二件事情是,他的座標系統啊,他是跟你的——因為你都做平面圖,所以平面圖的座標系統跟、除非你有做專案北跟正北,不然你的座標系統會跟你的世界地圖一樣,就是 X 軸跟 Y 軸的,他不會出錯。可是你一旦剖到剖面圖,或者是你圖面有經過旋轉的時候,他吃的是那個、就是你的裁切視框的那個範圍,他的視窗是他的、那個應該講說他的左邊跟上面那個座標系統。所以如果你要做到其他的視圖的時候,他座標系統要轉換。
可是實際上就是兩件事:第一個 MCP 觸發這件事,第二件事情是他的系統是要透過視圖的裁切範圍去定位。但是問題是這個系統就讓你用了會很強,他可以在你做之前去幫你把那個路徑圈出來,不然那麼多東西,你要突然跟他講說:我路徑長怎樣,其實人沒有辦法想像。對,這是我們這一次第一次看到有人用這個、這一招。
▍羅老師的技術裁決:DirectContext3D 只能在外掛做,MCP 不能
產物:邊界說明,非可執行產物
羅老師的裁決分兩部分。第一,DirectContext3D 這件事「MCP 不能做,
他只能在外掛裡做」——因為它雖然透過 Revit API,卻是直接跳過 Revit
主體程式、對 GPU 下繪圖指令;MCP 可以叫它讀資料,但無法觸發這個
層級的繪圖動作。這與 A05 的判斷完全一致,是同一件事的兩種說法。第二,座標系統的警告:平面圖的座標系統通常跟世界座標軸對齊,
不太會出錯;但一旦是剖面圖,或圖面經過旋轉,DirectContext3D
吃的是裁切視框(crop box)本身的座標系——換視圖就要轉換座標系統
_
卓欣言:其實我有看到之前、前兩天盧家強老師你有發表那個看 Revit 的物件的那個 API,然後其實我有參考說:裡面的機制,然後去優化我的 BIM Agent、自己做的個人代理。
卓欣言:就是說,因為我剛剛前面有提到說,我的 BIM Agent 其實它主要是拿來觀測的,其實我是讀它建立的位置、建立的座標、建立的編號在哪裡,然後位置多高什麼的。可是給您提供的那個專案,我就可以有參考的依據,所以我可以再寫入更多資訊,讓我的 agent 有更多的上下文,然後我自己實測下來,其實效果還蠻好的。
動手做:不用 Revit、不用 Windows,也能跑出他那張「帶屬性的 SVG」
這一節是 workshop,不是逐字稿。 內容是筆記整理者依他公開的 repo 實際重跑一遍後寫成的操作指南。
欣言老師台上最關鍵的一句話,是這個問句:
「那 SVG 承載資訊,他是不是可以自動送回 Revit 去幫我做準心?」
這個 workshop 就是要讓你親眼看到那個「準心」是怎麼做到的——而答案短到一行就能講完:他把 Revit 的 ElementId 直接寫進 SVG 的屬性裡。
台上示範的完整流程要 Windows + Revit + 部署好的外掛。但他的 repo 裡留了一支實機驗證腳本,把當時從 Revit 讀回來的真實資料內嵌在程式碼裡,所以這一段任何人都能在自己的筆電上重跑。
⚠️ 先講授權
NicheSam/SC-REVIT 目前沒有 LICENSE 檔案,依 GitHub 服務條款,這代表著作權全部保留。
- ✅ 可以:clone 下來、在自己機器上跑、閱讀、學習。
- ❌ 不建議:在未取得他授權前改作、再散布、或把程式碼併進你自己的專案。
本篇因此只指路、不轉載——只引檔名、函式名與單行輸出,不貼他的原始碼。
你會做到什麼
| 步驟 | 要 Revit 嗎 | 要裝套件嗎 | 你會看到 |
|---|---|---|---|
| ① clone SC-REVIT | ❌ | ❌ | 一份 286 檔的 repo |
| ② 跑實機驗證腳本 | ❌ | ❌ | 兩張真的 SVG |
③ 讀 SVG 的 data-* | ❌ | ❌ | Revit ElementId 就嵌在裡面 |
| ④ 對回 Topology Plan | ❌ | ❌ | 為什麼 SVG 跟建模不會各走各的 |
| ⑤ 送回 Revit 下準心 | ✅ Windows + Revit + 外掛 | — | 本 workshop 不做 |
只做 1–4。第 5 步的機制我會告訴你在哪一行,但跑不了。
事前準備
只需要 Python 3 與 git。不需要 pip install 任何東西——待會會實際驗證這件事。
步驟 1:把 repo 抓下來
git clone --depth 1 https://github.com/NicheSam/SC-REVIT.git
cd SC-REVIT
先確認「零依賴」不是我隨口說的:
ls requirements.txt pyproject.toml setup.py Pipfile poetry.lock
實際輸出(全部不存在):
ls: requirements.txt: No such file or directory
ls: pyproject.toml: No such file or directory
ls: setup.py: No such file or directory
ls: Pipfile: No such file or directory
ls: poetry.lock: No such file or directory
再看畫圖的那支模組開頭 import 了什麼:
sed -n '1,7p' sc_revit/fire_branch/network_diagram.py
from __future__ import annotations
import html
import math
from collections import defaultdict
from pathlib import Path
from typing import Any
html、math、collections、pathlib、typing —— 五個全部是 Python 標準函式庫。這 1,579 行的 SVG 產生器沒有用 svgwrite、沒有用 graphviz、沒有用 networkx、沒有用 D3,是一行一行用 f-string 手刻出來的。台上那張圖不是套件畫的,是他自己寫的。
步驟 2:跑實機驗證腳本
PYTHONPATH=. python3 docs/validation/fire_branch_svg_live_20260821/generate_live_svg_validation.py
實際輸出(路徑會換成你自己的):
{
"renderer_svg": ".../fire_branch_live_topology_renderer_fixture.svg",
"component_sheet_svg": ".../fire_branch_live_component_sheet.svg",
"payload": ".../fire_branch_live_component_readback.json",
"renderer_svg_bytes": 12051,
"component_sheet_svg_bytes": 7702,
"renderer_plan_ids": 11,
"component_plan_ids": 5
}
跑完就有兩張 SVG 了。這裡面的資料不是編的——是 2026-08-21 他在 Revit 2024 裡唯讀回讀出來的:276 段管、168 個消防管件(三通 50、四通 17、變徑 66、彎頭 35)。那次驗證沒有部署新 DLL、沒有建立或修改任何元件,他在該目錄的 README.md 裡把這個邊界寫得很清楚。
用瀏覽器打開 docs/validation/fire_branch_svg_live_20260821/fire_branch_live_component_sheet.svg 就能看到管、彎頭、三通、四通、變徑五類元件的卡片。
步驟 3:這一步是重點——打開 SVG 看屬性
grep -o 'data-plan-entity-id="[^"]*"' \
docs/validation/fire_branch_svg_live_20260821/fire_branch_live_component_sheet.svg | sort -u
實際輸出:
data-plan-entity-id="component:cross:13563873"
data-plan-entity-id="component:elbow:13563857"
data-plan-entity-id="component:pipe:13563852"
data-plan-entity-id="component:reducer:13737368"
data-plan-entity-id="component:tee:13722992"
看那串數字。 13563852 不是流水號,是那根管在 Revit 裡的 ElementId;13722992 是那個三通的 ElementId。格式是 component:<類型>:<Revit ElementId>。
這就是他說的「SVG 可以承載資訊」的實際長相:畫面上每一個圖形,都知道自己在模型裡是誰。所以他不必再數「第四排第五個」——點到哪一段,那一段自己就帶著 ElementId。
再看根標籤,它連「這張圖的座標是哪來的」都寫在屬性裡:
<svg ... data-coordinate-space="topology_canvas"
data-orientation-source="revit_view"
data-main-shape="linear"
data-cad-verified="true"
data-cad-status="fixture">
以及每一段管都標了它的管徑證據是怎麼來的:
grep -o 'data-evidence="[^"]*"' \
docs/validation/fire_branch_svg_live_20260821/fire_branch_live_topology_renderer_fixture.svg \
| sort | uniq -c
6 data-evidence="live_revit_readback"
這次的六段全是「從 Revit 實機回讀」。而在真實的 CAD 判讀情境裡,這個欄位會是 explicit_color(文字+線色)、line_color_reference(線段顏色)、layer_reference(圖層參考)之類的值——他台上講的「文字第一、顏色第二、圖層最低」那個排序,就是被寫成這個欄位的。
滑鼠移到線上還會有提示,因為 SVG 裡有 <title>:
<title>1" / DN25|2.60 m|live_revit_readback</title>
<title>1 1/2" / DN40|2.50 m|live_revit_readback</title>
<title>1 1/4" / DN32|2.20 m|live_revit_readback</title>
管徑、長度、證據來源,三件事一次講完。這不是一張圖,是一份可以被查核的報告。
步驟 4:為什麼 SVG 不會跟建模各走各的
欣言老師台上說:
「所以最終接下來要做的,就是讓 SVG 圖的規則跟你建模的規則要用同一個計畫。」
聽起來像是還沒做的事。但打開這份決策紀錄:
sed -n '1,10p' docs/decisions/ADR-004-topology-execution-and-diagnostic-payload.md
狀態欄寫著「採用,2026-08-17」,決策第 1 條逐字是:
「
topology_plan是 SVG 與 Revit 建模共同且唯一的建置計畫。」
分享日是 8/29,這件事 8/17 就拍板了——早了 12 天。 他投影片 P29 畫的那張「Route Graph 管路地圖 / Topology Plan 建模計畫 / 共同輸入:管徑、接頭、順序」,就是這份 ADR 的圖解版。
那「送回 Revit 做準心」呢?也已經做完了。跑這個看契約:
sed -n '18,30p' test_fire_branch_focus_contract.py
測試方法的名字自己就把答案講完了:
test_revit_handler_zooms_open_active_view_without_model_mutation
鏈路是 queue_protocol.py 的 create_fire_branch_focus_request → 送出 action="focus_fire_branch_preview_segment" → sc_revit/fire_branch/client.py 的 request_focus_fire_branch_segment → revit_addin/src/Handlers/FireBranchHandler.cs 收到後呼叫 GetOpenUIViews() 與 ZoomAndCenterRectangle。
縮放定位,不動模型。 這正是「準心」兩個字最精確的實作——它只負責讓你看到,不負責改。
順帶一提,他的 Python 跟 Revit 之間走的是檔案式的 JSON queue(queue_protocol.py 的 ensure_queue_dirs / _write_request_json),不是這個讀書會主專案用的 WebSocket 8964。兩條路各有取捨,不是誰比較對。
你剛剛順手做到的一件事:發現 renderer 漂移了
跑完腳本後下 git status,你會看到:
M docs/validation/fire_branch_svg_live_20260821/conversion_checks.json
M docs/validation/fire_branch_svg_live_20260821/fire_branch_live_topology_renderer_fixture.svg
元件卡片那張逐位元完全一樣(SHA256 e682a6a9… 前後不變),但路網那張變了:renderer_svg_bytes 從 repo 裡記錄的 11123 變成 12051,diff 是 30 行新增、33 行刪除。
看 diff 就知道發生什麼事:舊版每個標籤後面墊了一個白底 <rect> 卡片,新版把卡片拿掉,改成 class="segment-label" / segment-detail / main-label 的純文字,並加上 <title> 提示。
關鍵是:data-plan-entity-id 一個都沒變。 變的只有視覺層。
這剛好證明了他在 P27 投影片上寫的那句話——「SVG 的價值不是美化,而是讓我檢查 Agent 的判讀」。契約(id 與屬性)是穩定的,好不好看是可以隨時改的。這兩件事被他刻意分開了,這是設計,不是巧合。
第 5 步為什麼跑不了
focus_fire_branch_preview_segment 這個請求要有東西去收。收的那一端是 revit_addin/src/Handlers/FireBranchHandler.cs,那是一個要編譯成 DLL、載進 Revit 的外掛。所以第 5 步需要:Windows + Revit + 編譯部署好的 add-in。
而且這件事沒辦法用 MCP 繞過去。羅老師在現場講得很直接:DirectContext3D 那類繪圖是「直接跳過 Revit 的主體程式,直接對 GPU 去下繪圖指令」,只能在外掛裡做。這不是欣言老師懶得做成 MCP,是那條路本來就不通。
誠實邊界
- 這個 workshop 證明的是「Revit 的資料可以被轉成帶身分的結構化 SVG」,不能被讀成「CAD 路徑對位已通過」或「Revit 建模已驗證」。他自己在該目錄的
README.md「尚未由本次驗證證明的項目」裡列了四條,比我這裡寫得更嚴格,建議直接讀。 - 路網那張 SVG 的畫布座標是為了契約測試正規化過的,不是 CAD 的實際位置。真實的是 ElementId、族群名、連接器數量與管徑。
- 該 fixture 內嵌了一個真實案場的專案名稱,本篇依主專案
domain/anti-lessons.md的規則予以遮蔽;技術數值(ElementId、管徑、數量)照實引用。 - 我沒有 Windows + Revit,第 5 步完全沒有實測,關於 focus 鏈路的敘述全部來自原始碼與契約測試的閱讀,不是執行結果。
- SC-REVIT 沒有 LICENSE,上述所有引用均為說明性質;要用他的東西請直接問他。
本文用到的連結
| 資源 | 連結 |
|---|---|
| 主專案 | https://github.com/shuotao/REVIT_MCP_study |
| 他的技術本體 | NicheSam/SC-REVIT |
| 他的方法論 Skill | NicheSam/revit-mcp-research-partner |
| 他 fork 的主 repo | NicheSam/REVIT_MCP_study |
| PR #115 作者 | Rumi-3653 |
| issue #99 | shuotao/REVIT_MCP_study#99 |
| issue #100 | shuotao/REVIT_MCP_study#100 |
| PR #115 | shuotao/REVIT_MCP_study#115 |
| 實機 SVG 驗證資料夾 | docs/validation/fire_branch_svg_live_20260821 |