HN 日本語サマリー

← 一覧へ戻る
AI・機械学習

ベンチマーク:エージェントによるCAD作業におけるCadQuery対OpenSCAD

Benchmark: CadQuery vs. OpenSCAD for agentic CAD work (modelrift.com)

26 pointsby jetter36 コメント

要約

この記事では、AIエージェントがCAD作業を行う際に、CadQueryとOpenSCADのどちらが優れているかを比較しています。6つのAIエージェントと3つのタスクを用いたテストでは、両ツールとも印刷可能な部品を作成できましたが、失敗の仕方やエラーメッセージの分かりやすさに違いが見られました。CadQueryはパラメトリック設計に強みを示し、OpenSCADは複雑なジオメトリ生成で優位性を示しました。

全文翻訳

AI生成機能部品のためのCadQuery対OpenSCAD

ModelRiftはプラットフォーム上のすべてのモデルに対してOpenSCADを生成しています。その選択は時折再テストする価値があるため、コードファーストCADの最も信頼できる代替手段であるCadQuery(OpenCascade B-repカーネル上のPythonライブラリ)との比較テストを実施しました。

質問は狭いものでした:AIエージェントが誰も見ていない状態で、正しい、印刷可能な、機能的な部品をどちらのツールで作成できるか? 手書きでの使いやすさは考慮しませんでした。

6つのエージェント、3つのタスク、2つのツール。生成されたすべてのSTLは、どちらのツールも信頼しないパーサーによってチェックされました。

6つの部品すべてが印刷可能でしたが、比較はそこに至るまでのトラブルに集約されました:6回の実行で16件の異なる失敗があり、そのうち9件はツールが全く言及しませんでした。

[画像: 2つのねじ付きホースアダプターが並んでおり、一方はOpenSCADで、もう一方はCadQueryで構築されており、ほぼ同一]

セットの中で最も難しいタスクで、両方のツールで解決されました。左がOpenSCAD、右がCadQuery製です。

セットアップ

すべての6回の実行は、Claude Opus 5(1Mコンテキスト)をClaude Code経由で実行しました。各セルは、同じモデルを継承した独立した汎用サブエージェントとして実行され、それらの間でのクロス・トークはありませんでした。セルごとに1つのエージェントなので、以下のスプレッドの一部はツールの違いではなくエージェントのばらつきです。ツールバージョンは、MシリーズMac上でPython 3.14上のCadQuery 2.8.0と、OpenSCAD 2026.06.12でした。

OpenSCAD側は、私たちが公開し社内で使用しているエージェントスキルであるopenscad-skillで実行しました。これには、ファイルとバージョンの命名、レンダリング・検査・修正のQAループ、CLIプレビュー用のカメラプリセット、断面デバッグ、およびCustomizer構文が含まれます。

CadQueryについては、そのスキルを操作ごとに移植し、同じ構造を維持し、OpenSCADに相当するものがないものだけを置き換えました。CadQueryにはCLIレンダラーがないため、移植には小さなオフスクリーンレンダラーが必要となり、CSGステータスラインの代わりにB-repの有効性メトリクスが配置されました。両方のファイルには同じ3Dプリンティング設計ルール、壁厚、クリアランス、オーバーハングが適用されたため、どちらの側も不利になるようなアドバイスはありませんでした。サイズはOpenSCADが12.4 KB、CadQueryが13.1 KBでした。

1つの非対称性が残りました:CadQueryファイルは、モデルが既にOpenSCAD構文をよく知っているため、OpenSCADファイルには必要のないAPIチートシートを含んでいます。これは構文面でCadQueryに役立ちますが、ジオメトリ面では何も影響しません。

各エージェントは12バージョンに制限され、成功を偽らないように指示され、すべての失敗をその正確なエラーテキストとともに報告するように要求されました。それらは無人で実行されました。

私たちはエージェントの言葉を鵜呑みにしませんでした。最終的なSTLはすべて、ファイルを直接読み取り、三角形数、バウンディングボックス、体積、水密性、非多様体エッジ、境界エッジ、反転した面、接続されたコンポーネントを報告するパーサーを通過しました。これは、後述の理由により、予想以上に重要であることが判明しました。

3つのタスク

タスクごとに両方のエージェントは同じテキストを受け取り、ツール固有のヒントはありませんでした。

T1は簡単なもので、壁掛け棚のL字ブラケットでした:90度の2つのプレート、厚さ4mm、2つの三角形のガセット、フラットヘッドネジ用の皿穴(90度、ヘッド径9mm)2つ、プレーンな穴2つ、外側の垂直コーナーにR3、内側のコーナーにR4のフィレット、サポートなしで印刷可能。

T2は、50 x 26mmのPCB用2ピーススナップフィットエンクロージャーに難易度を上げました。壁厚2mm、片側0.4mmのキャビティクリアランス、M2ポスト4本、USB-C cutout 9.5 x 3.5mm、周囲に0.2mmのクリアランスを持つリムと機能するスナップを備えた別個の蓋、5つのベントスロット。2つの部品は実際にフィットする必要がありました。

T3は難しいものでした:M24x2のねじ付きホースバーブアダプターで、六角フランジ(フラット間30mm)、実際のヘリカルねじ(長さ12mm)、3つのバーブ(内径12mmホース用、長さ25mm)、および8mmのスルーチャネル。仕様では積み重ねられたリングは明確に禁止されていました。ねじは真のヘリカルジオメトリである必要がありました。

結果

T1 OpenSCADT1 CadQueryT2 OpenSCADT2 CadQueryT3 OpenSCADT3 CadQuery
バージョン数238513
コード行数103135220266150172
ツールが報告したエラー数140011
サイレントな不正ジオメトリ005301
エージェントの壁時計時間461 s562 s1058 s909 s542 s935 s
エージェントのトークン数77 k89 k138 k139 k82 k119 k
ジオメトリ再計算時間12 ms1.56 s16 ms1.93 s43 ms1.95 s
最終STL判定クリーンクリーンクリーンクリーンクリーンクリーン

3つのタスクを合計すると:

OpenSCADCadQuery
バージョン数1111
コード行数473573
ツールが報告したエラー数25
サイレントな不正ジオメトリ54
エージェントの壁時計時間2061 s2406 s
エージェントのトークン数297 k347 k

「クリーン」とは、水密性、単一の接続コンポーネント、非多様体エッジまたは境界エッジゼロ、z=0上に配置され、ツールが報告したものではなくファイルから測定されたことを意味します。

イテレーション回数はそれぞれ11バージョンで同一となり、総労力は17パーセントの範囲内に収まりました。この記事の残りは、これらの数字の背後にある問題についてであり、両サイドで同じ種類ではありませんでした。

T1:簡単なブラケット

[画像: 2つのL字ブラケットが内側のコーナーから表示されており、ガセット、4つの穴、内側のフィレットが見える]

両方とも正しい。内側のコーナーから表示されており、ガセットが見える。見える違いは解釈:仕様ではガセットのサイズとインセットはオープンだった。

4つの外側コーナーの丸め処理が、2つの世界のモデルを明確に分離します。OpenSCADは2Dプロファイルを丸めてから押し出すため、ソリッドがどのように組み立てられたかは操作に関係ありません:

module corner_mask() {
    translate([0, 0, -eps]) linear_extrude(vert_h + 2*eps)
        offset(r = corner_r) offset(delta = -corner_r) square([plate_w, horiz_d]);
}

CadQueryは最初に4つのエッジに名前を付ける必要があります。そして、名前付けが難しい部分です:

result = result.edges("|Z").edges(
    BoxSelector((-WIDTH, -EPS, -EPS), (WIDTH, EPS, V_HEIGHT + EPS))
    + BoxSelector((-WIDTH, H_DEPTH - EPS, -EPS), (WIDTH, H_DEPTH + EPS, V_HEIGHT + EPS))
).fillet(R_OUTER)

OpenSCADは最初の試行で正しいジオメトリをコンパイルし、2バージョンで完了しました。CadQueryは、単一のエラーに実行時間の約3分の1を費やしました:.fillet(3.0)がBRep_API: command not doneというメッセージで失敗しました。このメッセージはエッジも半径も示しませんでした。エージェントは手動で二分法を実行して原因を発見する必要があり、それは算術的な問題であることが判明しました:2つのR3フィレットは4mmの壁に収まりません。

T2:フィットする必要がある2つの部品

[画像: マウントポストとリリーフスロットを備えた2つのエンクロージャーボックスが並んでいる]

両方のエージェントが、クリアランスのスタックアップから同じ54.8 x 30.8 x 25.0 mmのボックスを導き出しました。

ここでCadQueryのパラメータチェーンがその価値を発揮しました。リップの深さを変更すると、リム、プレート、スロット、溝、バーブがすべて一緒に移動しました。なぜなら、各寸法はタイプミスではなく派生していたからです。このような寸法チェーンは、優れたパラメトリックUIがユーザーに公開するものと同じであり、Building a better OpenSCAD customizerで書いたものです。CadQueryにはCustomizerに相当するものがないため、定数ブロックがパラメータインターフェース全体となります。

より興味深いのは、各サイドがどのようにフィットをチェックしたかです。OpenSCADは、人が読むための数値をプリントします:

echo(str("cavity LxW = ", cav_l, " x ", cav_w, "  (clearance/side ", pcb_clr, ")"));

CadQueryはアサートし、アサートが偽の場合にビルドが停止します:

assert BOX.val().intersect(LID.val()).Volume() < 1e-6, "box and lid interfere"

echoは、誰かがそれを読んだ場合にのみ役立ちます。アサートはビルド自体を失敗させます。T2では、これが追加作業として現れました:OpenSCADエージェントは、CadQueryがインラインでアサートできるものをチェックするために、独自のバイナリSTLパーサーを作成しました。

OpenSCADはCadQueryの5バージョンに対して8バージョンを必要とし、そのうち3バージョンは設計ではなくブーリアン演算の衛生処理(接線や共面する面から生じるスライバーのクリーンアップ)に使われました。

T3:実際のねじ

難しいタスクは最大の驚きをもたらしました。OpenSCADは1バージョンで完了し、最初のコンパイルで正しく、43ミリ秒で、ライブラリなしでした。

OpenSCADにはスイープ操作がないため、エージェントはねじを生の頂点と面の演算として記述しました:1つの4点ISOプロファイル、1回転あたり96セクション、単一のpolyhedronとして出力。このコードには一切のガードレールがありません。巻き方向を間違えると、ツールは何も言いません。

module helical_thread(turns, z0) {
    prof = [ [r_in, -flank_hz], [r_maj, -crest_hz],
             [r_maj, crest_hz], [r_in, flank_hz] ];
    n = round(turns * STEPS);
    pts = [ for (i = [0:n]) let(a = i * 360 / STEPS,
                                zo = z0 + i * thread_pitch / STEPS)
                for (j = [0:3])
                    [ prof[j][0] * cos(a), prof[j][0] * sin(a), prof[j][1] + zo ] ];
    fcs = concat(
        [ [3, 2, 1, 0] ],
        [ for (i = [0:n-1]) for (j = [0:3]) let(k = (j + 1) % 4)
              [ 4*i + j, 4*i + k, 4*(i+1) + k, 4*(i+1) + j ] ],
        [ [4*n + 0, 4*n + 1, 4*n + 2, 4*n + 3] ]
    );
    polyhedron(points = pts, faces = fcs, convexity = 8);
}

エージェントは、コードを一行書く前に、古典的なねじの落とし穴を先回りしました:ISO歯は正確に1ピッチを占めるため、連続する根元の平坦面が共面になり、ユニオンが悪くなります。ねじの根元をマイナー半径より下に沈めることで、ヘリックスがコアに触れるのではなく交差するようにしました。これがブーリアン演算が問題にならなかった理由です。

CadQueryは同じジオメトリを6行の読みやすいコードで表現しており、その部分は最初の試行で動作しました:

helix = cq.Wire.makeHelix(pitch=THREAD_P, height=h, radius=R_ROOT, center=(0, 0, z0))
prof = (cq.Workplane("XZ", origin=(0, 0, z0)).center(R_ROOT, 0)
        .polyline(thread_profile_points()).close())
ridge = prof.sweep(path, isFrenet=True)

core = cq.Workplane("XY", origin=(0, 0, z0)).circle(R_ROOT).extrude(h)
rod = core.union(ridge)

失敗は最後の行で発生し、これが私たちのQAループに対する考え方を変えた結果です。

[画像: 2つの断面図:左はコア円筒がなく浮いているねじのターンを示し、右はソリッドボディを示す]

CadQuery T3バージョン1(左)。ねじ部分は浮いているヘリカルターンの塊です。

union()は、ねじの根元がコア半径と正確に一致していたため、コア円筒をサイレントに破棄しました。ヘリカルカーブに沿った正確な接線、そしてOCCTは何も言わずにソリッドをドロップしました。外側からは部品は完璧に見えました。エージェントは4回のレンダリングを見ても気づきませんでした。それを捉えたのは体積測定でした:予想される10323mm³に対して7065mm³でした。

さらに悪いことに、壊れた部品はvalid=Trueとsolids=1を報告しました。ブーリアン許容値を1e-3に上げると、負の体積を持つソリッドが生成され、これもvalid=Trueを報告しました。

OpenSCADも無実ではありません。T2では、そのManifoldバックエンドは、4つの非多様体エッジと60個のゼロ面積の三角形を持つSTLに対してStatus: NoErrorを認定しました。どちらのツールの自己報告も最終的な言葉ではありません。だからこそ、私たちはすべてのメッシュを独自に解析しました。

[画像: 両方の完成したアダプターの軸断面図。ねじのクレストが半ピッチずれて配置されている]

両方ともねじが完成しました。左側の面のクレストは右側の面より半ピッチずれています。これは真のシングルスタートヘリックスの兆候であり、積み重ねられたリングから実際のねじを区別するチェックです。

部品をダウンロード

ここに8つの最終メッシュがあります。エージェントがエクスポートしたそのままの状態です。私たちの手によるクリーンアップや修復はありません。バイナリSTL、ミリメートル単位、部品がz=0上に配置されるように向きが調整されています。

8つすべてが水密性、単一の接続コンポーネント、非多様体エッジゼロ、境界エッジゼロ、反転した面ゼロです。クリアランスは0.4mmノズルでのFDMを想定しているため、T2の各ペアは印刷時にスナップ結合するはずです。

トライアングル数は注目に値しますが、どちらかのツールに一貫して有利ではありません。CadQueryのボックスはOpenSCADのボックスの5倍近くのトライアングルを運びますが、その蓋はより少ないです。ここのメッシュ密度は、カーネルではなく、エージェントが追加することを選択した丸められた詳細の量に従います。

発見したこと

レンダリングは重要なものを何も捉えなかった

これは予想外の結果でした。6回の実行全体で、画像は4つのマウントポストがキャビティ減算によって削除されたような粗い間違いを捉えましたが、微妙なものは何もありませんでした。印刷を台無しにする可能性のあるすべての欠陥は、体積、角度、干渉テスト、ひずみ計算などの数値によって発見されました。T3では、OpenSCADエージェントは逆の問題を抱え、間違って見えるようにレンダリングされたねじのクローズアップのために、正しいジオメトリをほぼ却下するところでした。それ自体の注記は、レンダリングはどちらの方向にも十分な証拠ではないということでした。

失敗モードは鏡像である

CadQueryは、大声で早期に失敗します。メッセージは貧弱ですが、例外が発生すると実行が停止し、停止したモデルは誤って出荷されることはありません。OpenSCADは、サイレントに遅れて失敗します:T2では、約45回の呼び出しでエラーも警告も報告せず、削除されたポスト、配置ミスしたスロット、およびクリーンであると認定したばかりの破損したエクスポートを生成しました。無人生成の場合、サイレントな成功はより高価な失敗です。

CadQueryは問い合わせ可能だが、OpenSCADは不可能

CadQueryは自身のジオメトリに関する質問に答えます。T1エージェントは、コーンの半角をB-repから読み取ることで、カウンターシンクが90度で9mmであることを証明し、その後、ビルドごとに再実行されるアサートに仕様を組み込みました。OpenSCADにはジオメトリをクエリする方法がないため、両方のOpenSCADエージェントは独立してバイナリSTLパーサーを作成しました。これはモデル自体と同程度のコード量で、構築したものを測定しました。これは機能しますが、エクスポート後のメッシュしか見えず、デザインは決して見えません。

スピードはOpenSCADを支持するが、ほとんど問題にならない

ジオメトリ再計算は30倍から100倍高速で、16ミリ秒対1.9秒です。モデル推論に支配されたエージェントループ内では、これはノイズです。ライブカスタマイザーや大規模なパラメータスイープでは重要になるでしょう。

OpenSCADのレンダリングには部品のエッジの概念がない

CSGの後には三角形のスープしか残らないため、--view=edgesはアウトラインではなく、三角測量を描画します。CadQueryのB-repは、2つの面が実際に meeting する場所を知っています。画像はエージェントのフィードバックチャネルであるため、これはセットアップにおける実際の非対称性でした。そのため、エクスポートされたSTLをレンダリングし、隣接する面の角度からアウトラインを再構築することで修正しました。

[画像: 同じブラケットが3つの方法でレンダリングされています:フラットなデフォルト、散らかった三角測量のエッジ、そしてクリーンなアウトライン]

同じ部品、3つのレンダラー。左:CLIデフォルト、アウトラインなし。中央:--view=edges、すべてのファセットを描画します。右:STLからのフィーチャーエッジ再構築。これはメッシュの欠陥も赤でペイントします。すべての6回の実行は、この修正より前に行われました。

まとめ

どちらのツールも出力では勝ちません。6つのクリーンで印刷可能な部品、それぞれから3つ。

CadQueryの利点は、その作業をモデルの内部からチェックできることです。カーネルに構築したものを尋ね、その回答にアサートすることは、両方のOpenSCADエージェントが手動でSTLパーサーを再構築しなければならなかったことです。エージェントループでは、便利な構文よりも重要です。

タスクの形状がツールよりも多くを決定します。単純な直方体の作業はOpenSCADに行きました。フィットする必要がある2つの部品はCadQueryに行きました。ヘリカルねじ、B-repカーネルに最適に見えるタスクは、直接OpenSCADに行きました。

生成パイプラインがスクリーンショットに依存している場合、ここでは何も捉えなかったチャネルに依存しています。壁厚、クリアランス、干渉体積、オーバーハング角度などの数値アサートが重要です。

メッシュは独立して検証してください。なぜなら、両方のツールチェーンが間違ったジオメトリを認定したからです。これは、Pantheonベンチマークが異なる角度から得た教訓と同じです。Codexはプレビューループで強力に見えましたが、ポートコ屋根の周りにジオメトリの問題があるSTLを出荷しました。プレビューとエクスポートは同じものではありません。印刷されるものについては、エクスポートされたメッシュには独自の検査パスが必要です。

注意事項

セルごとに1つのエージェントなので、ばらつきの一部はツールの違いではなくエージェントのばらつきです。

BOSL2は意図的に使用されませんでした。ライブラリ支援のOpenSCAD実行は、T2とT3を大幅に変更する可能性があります。

すべての6回の実行は、アウトラインレンダラーより前に行われたため、実行中は視覚チャネルが不均一でした。

これは構築のみを測定しました。誰もがより難しいスキル、つまり誰かが壊したモデルを修理することは測定しませんでした。

ModelRiftにとっての意味

私たちはOpenSCADを使い続けます。このベンチマークは、答えを変えるのではなく、その理由を明確にしました。当初の理由は依然として有効です:LLMが直接書けるコンパクトなテキスト形式、安全なサンドボックス、高速なレンダリング。これらはすべてWhy we built ModelRift on OpenSCADでカバーされています。CadQueryの利点は現実ですが、主に検証にあり、検証はOpenSCADの周りに追加できるものです。その欠点は、私たちのケースでは構造的なものです:セッションごとにPythonランタイム(WASMサンドボックスの代わりに)、16ミリ秒ではなく2秒のリビルド、そしてmulticolor 3MFのために構築したようなクリーンなマルチオブジェクトカラーエクスポートの欠如です。

より有用な発見はフィードバックに関するものです。Pantheonベンチマークは、自律生成はまだ適切なワークフローではないという観察で終わりました。そして、レンダリングに描画してAIに返すアノテーションモードが、空間的なイテレーションを機能させるものです。この実行はそれに境界を追加します。視覚的なフィードバックは、マスキング、プロポーション、「列が間違った場所にある」といったことには適切なツールです。壁厚、クリアランス、ブーリアン演算がサイレントに部品の半分を削除したかどうかには不適切なツールです。それらには数値が必要であり、エージェントはそれらを見るようにする必要があります。

公開されているOpenSCADスキルには、すでに2つの変更が加えられています。上記のフィーチャーエッジレンダラー(エージェントが三角測量ではなく実際の部品アウトラインを持つプレビューを取得できるようにするため)。そして、エージェントがモデルを完了と呼ぶ前に実行しなければならない数値チェックパス(壁厚、クリアランス、干渉、およびツールにうまくやったかどうかを尋ねないメッシュ監査)。