我們讓六個 AI 代理使用相同的三個可列印零件進行建模,其中三個使用 CadQuery,三個使用 OpenSCAD,然後獨立驗證了每一個網格。兩種工具鏈都成功完成了任務。差異在於它們失敗的方式。
ModelRift 為平台上的每個模型生成 OpenSCAD。這個選擇值得偶爾重新測試,因此我們針對程式碼優先 CAD 最可靠的替代方案 CadQuery 進行了受控比較。CadQuery 是一個基於 OpenCascade B-rep 核心的 Python 函式庫。
問題很明確:在無人監督的情況下,哪一個工具能讓 AI 代理生成正確、可列印、功能性的零件?手動編寫的愉悅程度不在考量範圍內。
六個代理,三個任務,兩種工具。每個產生的 STL 都經過一個不信任任何一方工具的解析器檢查。
所有六個零件都能成功列印。能力證明是答案中較為枯燥的部分。兩者分歧之處在於它們失敗的方式。
這是最困難的任務,兩種工具都已解決。左邊是 OpenSCAD,右邊是 CadQuery。
所有六次運行都由 Claude Opus 5 (1M 上下文) 透過 Claude Code 驅動。每個單元都作為一個獨立的通用子代理運行,繼承相同的模型,它們之間沒有交叉通訊。每個單元一個代理,因此下方的部分差異也包含代理本身的變異,而非工具的差異。工具版本為 CadQuery 2.8.0 搭配 Python 3.14,以及 OpenSCAD 2026.06.12,兩者皆運行於 M 系列 Mac。
OpenSCAD 端運行於我們自家的 openscad-skill,這是我們發布並在內部使用的代理技能。它涵蓋了檔案和版本命名、渲染-檢查-修復 QA 循環、CLI 預覽的相機預設、橫截面除錯以及 Customizer 語法。
對於 CadQuery,我們逐一移植了該技能的操作,保持相同的結構,只替換沒有 OpenSCAD 等效項的部分。CadQuery 沒有 CLI 渲染器,因此移植需要為其編寫一個小型離屏渲染器,並用 B-rep 有效性指標取代 CSG 狀態行。然後,兩個檔案都套用了相同的 3D 列印設計規則、壁厚、間隙和懸垂,因此兩邊都沒有獲得對方所沒有的建議。檔案大小分別為 OpenSCAD 的 12.4 KB 和 CadQuery 的 13.1 KB。
一個不對稱性仍然存在:CadQuery 檔案包含一個 API 備忘單,而 OpenSCAD 檔案則不需要,因為模型本身已經熟悉 OpenSCAD 語法。這有助於 CadQuery 的語法,但對其幾何形狀沒有幫助。
每個代理最多允許 12 個版本,被告知絕不偽造成功,並要求報告每一次失敗及其確切的錯誤文字。它們是無人值守運行的。
我們沒有輕信代理的任何說法。每一個最終的 STL 都經過一個直接讀取檔案的解析器檢查,並報告三角形數量、邊界框、體積、水密性、非流形邊緣和邊界邊緣、翻轉的面以及連通的組件。這比我們預期的更重要,原因如下。
兩個代理在同一任務上獲得相同的文字,沒有工具特定的提示。
簡單的任務 T1 是一個壁掛式擱板 L 型支架:兩個 4mm 厚的板件成 90 度角,兩個三角形加強筋,兩個用於沉頭螺絲的 90 度沉孔(直徑 9mm),兩個普通孔,外側垂直角為 R3,內角為 R4 圓角,無需支撐即可列印。
T2 提高了難度,為 50 x 26 的 PCB 設計了一個兩件式卡扣式外殼。壁厚 2mm,每側腔體間隙 0.4mm,四個 M2 柱,一個 9.5 x 3.5 的 USB-C 開口,一個帶有 0.2mm 間隙周邊唇緣且能工作的卡扣的獨立蓋子,五個通風槽。這兩部分必須能夠實際組裝。
T3 是最困難的任務:一個 M24x2 的螺紋軟管接頭,帶有一個 30mm 寬(對邊)的六角法蘭,一個 12mm 長的真實螺旋螺紋,一個 25mm 長的帶有三個用於 12mm ID 軟管的倒鉤的接頭,以及一個 8mm 的通孔。規格明確禁止堆疊的圓環。螺紋必須是真實的螺旋幾何。
「乾淨」意味著水密、一個連通組件、零非流形或邊界邊緣、位於 z=0 平面上,從檔案測量而非由編寫工具報告。
迭代次數與兩者相同,均為 11 個版本。努力的廣泛形狀也相同。不同之處在於代理遇到的問題的性質。
兩者都正確,從內角顯示,可以看到加強筋。可見的差異在於解釋:規格對加強筋的大小和內嵌留有開放空間。
對四個外角進行圓角處理,清晰地區分了兩種世界模型。OpenSCAD 圓角化一個 2D 輪廓並將其擠出,因此操作不關心實體是如何組裝的:
CadQuery 必須先命名四個邊,而命名是困難的部分:
OpenSCAD 在第一次嘗試時就編譯了正確的幾何形狀,並在兩個版本內完成。CadQuery 花了約三分之一的時間處理一個單一錯誤:.fillet(3.0) 失敗,並出現 BRep_API: command not done 的訊息,該訊息既沒有命名邊也沒有命名半徑。代理必須手動二分法才能發現原因,結果發現是算術問題:兩個 R3 圓角無法裝入 4mm 的壁厚中。
兩個代理都從間隙堆疊中導出了相同的 54.8 x 30.8 x 25.0 mm 盒子。
這就是 CadQuery 的參數鏈發揮作用的地方。改變唇緣深度會一起移動邊緣、板件、槽、凹槽和倒鉤,因為每個尺寸都是導出的而非重複輸入。這種尺寸鏈與良好的參數化 UI 向用戶暴露的內容相同,我們在「Building a better OpenSCAD customizer」一文中討論過。CadQuery 沒有 Customizer 的等效項,因此常量塊是整個參數介面。
更有趣的是兩邊如何檢查配合。OpenSCAD 打印數字供人閱讀:
CadQuery 進行斷言,當斷言為 false 時,建構就會停止:
echo 只有在有人閱讀時才有幫助。assert 會自行終止建構。對於無人值守生成,這個差距幾乎說明了全部故事。
OpenSCAD 需要八個版本,而 CadQuery 需要五個版本,其中三個版本用於布林運算清理,而不是設計:清理由切線和共面組成的碎屑。
困難的任務產生了最大的意外。OpenSCAD 在一個版本內完成,第一次編譯就正確,耗時 43 毫秒,沒有使用任何函式庫。
OpenSCAD 沒有掃掠操作,因此代理編寫了螺旋線作為原始頂點和面算術:一個四點 ISO 輪廓,每圈 96 個截面,作為單一多面體輸出。這段程式碼完全沒有任何保護措施。如果繞線順序錯誤,工具不會發出任何警告。
代理在編寫任何程式碼之前就預先規避了經典的螺紋陷阱:一個 ISO 牙頂跨越正好一個螺距,因此連續的螺紋根部平面會共面,導致並集失效。它將掃掠輪廓沉入到小徑半徑以下,以便螺旋線與核心接觸而不是觸碰它。這就是為什麼布林運算沒有成為問題。
CadQuery 用六行可讀的程式碼表達了相同的幾何形狀,並且該部分第一次就成功了:
失敗發生在最後一行,也是唯一一個改變我們對 QA 循環看法的結果。
左邊是 CadQuery T3 版本 1。螺紋部分只是漂浮的螺旋線圈。
union() 靜默地丟棄了核心圓柱體,因為螺紋根部正好位於核心半徑上。沿著螺旋線的精確切線,OCCT 在沒有任何警告的情況下丟棄了一個實體。從外面看,零件看起來很完美。代理讀取了四次渲染而沒有注意到。捕捉到它的是體積測量:7065 mm³,而預期是 10323 mm³。
更糟糕的是,損壞的零件報告了 valid=True 和 solids=1。將布林公差提高到 1e-3 會產生一個體積為負的實體,該實體也報告了 valid=True。
OpenSCAD 在這方面也不是無辜的。在 T2 中,其 Manifold 後端為一個包含 4 個非流形邊緣和 60 個零面積三角形的 STL 認證了 Status: NoError。沒有一個工具的自我報告是最終的決定,這就是為什麼我們自己解析了每一個網格。
兩者都完成了螺紋。左側胎面的頂部與右側胎面相距半個螺距,這是真實單頭螺旋線的標誌,也是區分真實螺紋與堆疊圓環的檢查。
這是八個最終網格,完全按照代理導出的方式,沒有經過我們任何清理或修復。二進制 STL,毫米單位,方向為零件位於 z=0 平面上進行列印。
八個網格都是水密的,一個連通組件,零非流形邊緣,零邊界邊緣和零翻轉的面。間隙假設為 FDM 列印,噴嘴為 0.4mm,因此每一對 T2 零件都應該能夠在列印後組裝在一起。
三角形數量值得一看,它們並沒有一致地偏向某一方。CadQuery 的盒子包含的三角形數量幾乎是 OpenSCAD 盒子的五倍,而其蓋子則較少。這裡的網格密度遵循代理選擇添加的圓角細節的多少,而不是核心。
這是我們未預料到的結果。在六次運行中,圖像捕捉到了明顯的錯誤,例如被腔體減法刪除的四個安裝柱,但沒有捕捉到細微的錯誤。每一個會毀掉列印的缺陷都通過數字被發現:體積、角度、干涉測試、應力計算。在 T3 中,OpenSCAD 代理遇到了相反的問題,幾乎拒絕了正確的幾何形狀,因為近距離渲染的螺紋看起來不對。它自己的註記是,渲染在任何方向上都不是充分的證據。
CadQuery 的失敗是響亮且早期的。其訊息很差,但異常會停止運行,而停止的模型不可能意外發貨。OpenSCAD 的失敗是靜默且晚期的:在 T2 中,它在約 45 次調用中報告了零錯誤和零警告,同時生成了被刪除的柱子、錯位的槽以及一個它剛剛認證為乾淨的損壞導出。對於無人值守生成,靜默成功是更昂貴的失敗。
CadQuery 會回答關於其自身幾何形狀的問題。T1 代理通過讀取 B-rep 的圓錐半角,證明其沉頭孔是 90 度且寬度為 9,然後將規格編入斷言,在每次構建時重新運行。OpenSCAD 沒有查詢幾何形狀的方法,因此兩個 OpenSCAD 代理獨立編寫了二進制 STL 解析器,程式碼量與模型本身差不多,用於測量它們構建的內容。這有效,但它只在導出後看到網格,從未看到設計。
幾何重計算速度快 30 到 100 倍,16 毫秒對比 1.9 秒。在由模型推斷主導的代理循環中,這只是噪音。對於實時定制器或大型參數掃描,這將很重要。
在 CSG 之後只剩下三角形湯,因此 --view=edges 會繪製三角剖分而不是輪廓。CadQuery 的 B-rep 知道兩個面實際相遇的位置。由於圖像作為代理的反饋通道,這是我們設置中的一個真實不對稱性,因此我們通過渲染導出的 STL 並從相鄰面之間的角度重建輪廓來解決它。
相同的零件,三種渲染器。左:CLI 預設,無輪廓。中:--view=edges,繪製每一個面。右:從 STL 重建的特徵邊緣,這也會以紅色標記網格缺陷。所有六次運行都早於此修復。
沒有哪種工具在輸出上獲勝。六個乾淨的可列印零件,每種三件。
決定因素是可驗證性而非表達性,而 CadQuery 在這方面領先的幅度比語法差異所暗示的要大。能夠詢問核心你剛剛構建了什麼,並對答案進行斷言,在代理循環中比任何方便的語法都更有價值。
任務的形狀比工具更決定結果。簡單的棱柱形工作交給了 OpenSCAD。必須配合的兩個零件交給了 CadQuery。螺旋螺紋,這個看起來為 B-rep 核心量身定做的任務,則完全交給了 OpenSCAD。
如果生成管道依賴截圖,那麼它就依賴於在這裡沒有捕捉到任何東西的通道。數字斷言才是關鍵:壁厚、間隙、干涉體積、懸垂角度。
獨立驗證網格,因為兩種工具鏈都認證了錯誤的幾何形狀。這與 Pantheon 基準測試從不同角度得出的教訓相同,其中 Codex 在預覽循環中表現強勁,但導出了一個在門廊屋頂周圍存在幾何問題的 STL。預覽和導出不是同一回事。對於任何要列印的東西,導出的網格都需要自己的檢查步驟。
每個單元一個代理,因此部分差異是代理本身的變異,而非工具的差異。
故意沒有使用 BOSL2。一個有函式庫輔助的 OpenSCAD 運行可能會顯著改變 T2 和 T3。
所有六次運行都早於輪廓渲染器,因此在運行時視覺通道是不均勻的。
這僅僅是測量了構建過程。沒有人測量更困難的技能,即修復別人弄壞的模型。
我們仍然使用 OpenSCAD,而這次基準測試加強了原因而不是改變了答案。最初的原因仍然成立:一個 LLM 可以直接編寫的緊湊文本格式、安全的沙盒環境以及快速渲染,這些都在「Why we built ModelRift on OpenSCAD」中有介紹。CadQuery 的優勢是真實的,但主要在於驗證,而驗證是我們可以圍繞 OpenSCAD 添加的東西。其缺點對我們的案例來說是結構性的:每個會話需要一個 Python 運行時而不是 WASM 沙盒,兩秒的重建時間而不是 16 毫秒,以及沒有我們為多色 3MF 設計的那種乾淨的多對象顏色導出。
更有用的發現是關於反饋。Pantheon 基準測試以這樣的觀察結束:自動生成還不是正確的工作流程,而註釋模式(Annotation Mode),即你在渲染圖上繪製並將其交還給 AI,是實現空間迭代的關鍵。這次運行為其增加了一個界限。視覺反饋是處理體塊、比例和「柱子放錯位置」的正確工具。但對於壁厚、間隙以及布林運算是否悄悄刪除了一半零件,它卻是錯誤的工具。這些需要數字,並且必須讓代理去查看它們。
兩個更改已經回饋到已發布的 OpenSCAD 技能中。上面的特徵邊緣渲染器,以便代理獲得具有真實零件輪廓的預覽,而不是三角剖分。以及一個數字檢查步驟,代理在調用模型完成之前必須運行:壁厚、間隙、干涉,以及一個網格審計,它不詢問工具是否做得好。
工作室燈光和接觸陰影使模型的形狀更容易閱讀
我們讓六個 AI 代理使用相同的三個可列印零件進行建模,其中三個使用 CadQuery,三個使用 OpenSCAD,然後獨立驗證了每一個網格。兩種工具鏈都成功完成了任務。差異在於它們失敗的方式。
在瀏覽器中創建和探索參數化 3D 模型。