Skip to content

Repository files navigation

🛠️ MAC (Multi-Agent CAD): Generate printable 3D models with 1% the tokens

Tsinghua University · IEI Lab

4 agents collaborating · 116× fewer tokens · 99.3% feature pass rate — turn concise natural language directly into printable 3D models.

License: MIT Python 3.11 Powered by build123d 116× Fewer Tokens 13× Lower Cost 99.3% Pass Rate

Same CAD generation capability, 1/116 the tokens, 1/13 the inference cost.

CAD Skills MAC (ours) Advantage
Tokens 103.9M 896k 116× ↓
Cost ¥125.69 ¥9.67 13× ↓
Pass rate 97.9% (138/141) 99.3% (140/141)

🎬 Web UI walkthrough

Below is a screen recording of one full pipeline run through the Web UI.

Web UI walkthrough

📖 Table of Contents


1. 📸 Real-World Gallery

3D printed models overview

The 10 benchmark parts (P1–P10, sharing prompts with earthtojake/text-to-cad), the 10-piece show gallery (S1–S10, original prompts), and the articulable print-in-place demo below were each generated by MAC. The 3D rotation views and prompts for the physical printed models shown above are in qwen3.7_token.md.

🤖 Articulable Print-in-Place Models

Multi-body articulable models that print pre-assembled — multiple independent solid bodies coexist in one STEP with 0.4–1 mm clearance gaps so they move freely right off the build plate, no assembly required. This is a harder scenario than single-body generation: not only must the pipeline model each body separately, it must also precisely control clearances so the kinematic pairs actually function.

Description Real-shot
Ball-in-Cage Fidget Toy
A print-in-place classic: a solid ball is trapped inside a cube cage, printed as one piece — the ball rattles freely but cannot escape.
• 40 mm cube cage with a 16 mm radius spherical hollow inside, centered at origin
• 15 mm radius solid ball — 1 mm clearance from cage interior on all sides
• Six 12 mm radius through-holes (one on each face) make the ball visible & touchable

Articulable Gyroscope Toy
A print-in-place rotational pair: the inner ring spins inside the outer ring via two pivot pins.
• Outer ring: 30 mm outer / 23 mm inner radius, 10 mm tall, centered on XY plane
• Two 2.4 mm radius pivot holes through the outer ring along the X axis
• Inner spinner: 22 mm outer / 15 mm inner radius, 10 mm tall, 8 inner notches
• Two pivot pins (2.0 mm radius, 6 mm long) protrude outward into outer ring holes
• 0.4 mm radial clearance lets the inner ring spin freely 360° around the X axis
Articulable models real-shot

🎨 Show Gallery (S1–S10)

10 demo parts showcasing MAC on creative prints — ornaments, articulable toys, and mechanical mechanisms. Unlike P1–P10 (shared prompts), these are original to this project. Detailed prompts and 3D rotation views: qwen3.7_token.md.

S1 S2 S3 S4 S5
Honeycomb organizer Gyroscope ornament Lighthouse Smartphone stand Ball-in-cage
S1 S2 S3 S4 S5
S6 S7 S8 S9 S10
Articulable gyroscope Multi-link chain Geneva mechanism Plasma reactor Brake disc
S6 S7 S8 S9 S10

📐 Benchmark Parts (P1–P10)

10 mechanical parts covering arrayed features, boolean operations, rotational patterns, helical sweeps, and multi-body assemblies. The benchmark models shown below were all generated by this project using prompts from earthtojake/text-to-cad (CAD skill). Detailed prompts and per-feature pass rates are in qwen3.7_token.md.

Benchmark model views

P1 P2 P3 P4 P5
Rectangular block with 4 through-holes Circular flange L-bracket Stepped shaft Open-top enclosure
P1 P2 P3 P4 P5
¥5.53 → ¥0.31 (17.8×) ¥8.07 → ¥0.34 (23.7×) ¥13.07 → ¥1.08 (12.1×) ¥6.53 → ¥0.57 (11.5×) ¥2.88 → ¥0.36 (8.0×)
P6 P7 P8 P9 P10
Aerospace clevis bracket Radial-engine cylinder Centrifugal impeller Miniature spiral staircase Planetary gear assembly
P6 P7 P8 P9 P10
¥15.21 → ¥3.10 (4.9×) ¥17.42 → ¥0.53 (32.9×) ¥32.75 → ¥1.20 (27.3×) ¥12.80 → ¥1.45 (8.8×) ¥11.43 → ¥0.73 (15.7×)

Per-prompt cost (CNY): CAD Skills → MAC (cost-reduction ratio). Totals: ¥125.69 → ¥9.67 (13.0×). Raw data: docs/qwen3.7_token.md.

Design your own prints! See §2 Quick Start for how to generate a model.


2. 🚀 Quick Start

Installation

git clone https://github.com/Pan-Chera/Multi-Agent-CAD
cd Multi-Agent-CAD
conda env create -f environment.yml
conda activate multi_agent_cad

pip users (no conda): aider-chat pins numpy==1.26.4, but build123d>=0.8 requires numpy>=2,<3 — these conflict in pure pip. Use this workaround (verified on macOS arm64 + Python 3.11):

python3.11 -m venv .venv
source .venv/bin/activate          # Windows PowerShell: .venv\Scripts\activate
pip install --upgrade pip
# Install aider first (pulls numpy 1.26.4 + transitive deps), then force-upgrade numpy.
# Verified: aider 0.82.3 imports cleanly on numpy 2.x — the pin is over-cautious upstream.
pip install "aider-chat==0.82.3"
pip install --no-deps --force-reinstall "numpy>=2,<3"
pip install "build123d>=0.8" "langgraph>=0.2,<0.3" "langgraph-checkpoint>=2.0,<3.0" \
            "pydantic>=2.5" "openai>=1.20.0" "anthropic>=0.30" \
            "trimesh>=4.0" "rtree>=1.1" "scipy>=1.10" "scikit-learn>=1.3" \
            "fastapi>=0.110" "uvicorn[standard]>=0.27" "ipython>=8.15" "pytest>=7.4"
# --no-deps skips re-checking the numpy pin in pyproject.toml; fastapi+uvicorn
# are already installed by the previous step, so the [web] extras resolve.
pip install --no-deps -e .

The last step registers the mac-config-reset console script and lets you run python -m multi_agent_cad.graph from any directory. See requirements.txt / pyproject.toml for the canonical dependency list.

Windows: conda env create -f environment.yml works out of the box — trimesh and rtree come from conda-forge prebuilt; OCP is pulled in transitively by build123d (via its PyPI dep cadquery-ocp-novtk). Don't use the pure-pip workaround above on Windows — native wheels for trimesh/rtree can be unreliable. Set the API key in PowerShell as $env:DASHSCOPE_API_KEY = "sk-..." (or set DASHSCOPE_API_KEY=sk-... in cmd.exe). For the Web UI under conda, pip install -e ".[web]" inside the activated env works — uvloop auto-skips on Windows. Windows isn't in CI, but the code avoids Unix-only APIs and uses UTF-8 throughout; issues welcome.

Configuration

Edit multi_agent_cad/config.py:

Field Purpose
DS_API_KEY API key (or set DASHSCOPE_API_KEY env var — takes priority over the in-file value)
USER_REQUEST Default CAD generation request
DS_BASE_URL + 4 stages' MODEL / TEMPERATURE / MAX_TOKENS / KWARGS Provider and per-stage model params (see §4 Hybrid Routing)

To restore defaults after editing config:

python -m multi_agent_cad._config_defaults --reset

🔌 Use any LLM provider (not locked to Alibaba Cloud)

MAC calls models through an OpenAI-compatible endpoint. The repo defaults to Alibaba Cloud DashScope (qwen3.7-max). Point two config fields at any provider and the whole pipeline follows:

The model names and endpoints below are illustrative only. Verify the exact model ID with your provider's docs (DashScope console / OpenAI models API / etc.) before use — names like qwen3.7-max may not match what's currently served.

Provider DS_BASE_URL Example *_MODEL Notes
OpenAI https://api.openai.com/v1 gpt-5.6 DASHSCOPE_API_KEY = your OpenAI key; set *_KWARGS = {}
DeepSeek https://api.deepseek.com/v1 deepseek-v4-pro OpenAI-compatible
Google Gemini https://generativelanguage.googleapis.com/v1beta/openai/ gemini-3.6-flash OpenAI-compatible endpoint
Local (Ollama) http://localhost:11434/v1 qwen3-coder:32b no API key needed
Anthropic Claude via an OpenAI-compatible gateway (OpenRouter / LiteLLM proxy) claude-sonnet-4-6 the Aider repair stage supports Claude natively via litellm

For OpenAI, edit config.py:

DS_BASE_URL = "https://api.openai.com/v1"
SPEC_PLANNER_MODEL = ARCHITECT_MODEL = CODER_MODEL = REPAIR_MODEL = "gpt-5.6"
# disable the Qwen-only thinking toggle:
SPEC_PLANNER_KWARGS = ARCHITECT_KWARGS = CODER_KWARGS = REPAIR_KWARGS = {}
# Aider stage (litellm-prefixed model name):
AIDER_MODEL = "openai/gpt-5.6"

then export your key (the env-var name is historical — it accepts any OpenAI-compatible key):

export DASHSCOPE_API_KEY="sk-..."              # bash / zsh
# PowerShell:  $env:DASHSCOPE_API_KEY = "sk-..."

About the model name qwen3.7-max — it is simply the model ID served on the configured endpoint, here the flagship reasoning model of Alibaba DashScope. Every *_MODEL field accepts whatever model ID your provider exposes; nothing in the code is Qwen-specific. The only Qwen-specific piece is the enable_thinking toggle inside *_KWARGS — set *_KWARGS = {} for other providers (more per-provider examples live in config.py).

Two ways to run

MAC runs the same pipeline from the terminal or from a browser UI. Same outputs, different ergonomics — pick by what you need:

Terminal Web UI
Best for Mid-run steering Visual feedback, easier to grasp
Mid-run inject change / halt ✅ 10s checkpoint per QA (1 auto / 2 inject / 3 halt) ❌ auto-iterates only
3D preview of result ❌ open STEP/STL in an external viewer ✅ in-browser <model-viewer> + one-click downloads
Config editing edit config.py fill a form
Output location repo root (temp_*) per-job tempdir (optional copy to a path you specify)

See Terminal and Web UI below.

Terminal

python -m multi_agent_cad.graph          # original workflow: deterministic coder first, Aider fallback
python -m multi_agent_cad.graph_aider    # modify-existing-file workflow: apply USER_REQUEST as modification requirements to an existing temp_design*.py

Both entry points stream LangGraph events to the terminal. Each QA pass opens a 10-second checkpoint (auto-iterates on timeout): press 1 auto-iterate, 2 inject change requirements, 3 halt and keep current artifacts.

Output files (written to the repo root):

File Contents
temp_output_0.step / .stl Final model
temp_design_0.py Generated build123d source
temp_measurements_0.json White-box feature measurements
temp_missed_0.json Runtime diagnostics

For more complex example prompts see §1 Gallery.

🖥️ Web UI

A browser UI for the pipeline — fill the config form, run, preview the GLB in 3D, and download the artifacts. The UI runs in your browser; the pipeline runs on the server (single-user, trusted-network only — generated .py is executed server-side).

pip install -e ".[web]"                       # adds fastapi + uvicorn
python -m multi_agent_cad.web                 # serves on http://0.0.0.0:8000

Open http://<server>:8000 from your laptop. For remote access over an untrusted network, tunnel via SSH: ssh -L 8000:localhost:8000 user@server, then open http://localhost:8000 locally.

Cache mechanism

pipeline_cache/ stores the output of the first two stages, saving time and money on re-runs:

File Source Purpose
cad_brief.json Spec Planner (stage 1) Parsed requirement as structured data
architect_plan.json Geometric Architect (stage 2) Geometric plan (sketches, steps, selectors)

Re-run the same prompt: just python -m multi_agent_cad.graph — the cache is hit, the first two LLM stages are skipped, and the pipeline restarts at the Python Coder stage with a fresh repair loop. Useful when the previous run's QA failed or Aider's repair drifted — same plan, new attempt, seconds not minutes.

Generate a different model: the cache checks file existence only, not whether USER_REQUEST matches. So if you change the prompt but leave the cache in place, you'll get the old model again. Clear it before generating something new:

rm pipeline_cache/cad_brief.json pipeline_cache/architect_plan.json

Or bypass via code: set force_refresh: True in get_default_initial_state in multi_agent_cad/graph.py.

Customizing the prompt

Edit USER_REQUEST in multi_agent_cad/config.py, e.g.:

USER_REQUEST = "Create a single solid circular flange as a STEP model in millimeters. The flange is a cylinder with an outside diameter of 80 mm and a thickness of 10 mm. Add a central vertical through-bore with diameter 30 mm."

Then clear the cache per Cache mechanism above and re-run python -m multi_agent_cad.graph.


3. 💡 Introduction

Recent LLM-based text-to-CAD agents can already generate complex models, but their reasoning process is expensive: long-context interaction repeatedly consumes tokens on documentation, conversation history, and debugging traces.

The bottleneck is not CAD capability, but inefficient reasoning organization. A single agent on a 10-prompt benchmark burns 103M tokens and 1,307 API calls.

MAC splits the generation process into 4 agents wired together by a LangGraph state machine. Agents pass only compact structured states (CADBrief, ArchitectPlan, QA reports) instead of raw conversation, compressing token usage to 1/116:

Stage Agent Input Output
1 Spec Planner natural-language request CADBrief JSON (only 3 verification targets)
2 Geometric Architect CADBrief ArchitectPlan JSON (sketches, steps, selectors)
3 Python Coder ArchitectPlan temp_design.py (deterministic translator first, Aider fallback)
4 Autonomous Skill Loop code + STEP/STL final STEP + Dual-Engine QA report (Aider repair loop)

Each agent only sees the small, structured snapshot its role requires — there is no shared bloated context. Hallucination propagation is cut off at the stage boundary: even if one agent makes a mistake, the next stage continues from the structured output, not from the previous agent's narrative.

10-prompt / 141-feature benchmark results (Qwen 3.7-max, CNY):

Metric single-agent baseline MAC ratio
Total cost 125.69 9.67 13× cheaper
Total tokens 103,950,189 896,340 116× fewer
API calls 1,307 50 26× fewer
Feature pass rate 97.9% (138/141) 99.3% (140/141)

MAC is also a white-box system: every intermediate artifact (CADBrief, ArchitectPlan, temp_design.py, temp_measurements_*.json, temp_missed_*.json, QA report) is serialized to disk and human-auditable. You can intervene at any iteration checkpoint, override a passing result, and feed additional change requirements directly into the Aider repair prompt.

For full benchmark methodology, per-prompt token/cost breakdowns, fairness analysis, and failure-mode details, see quantified_quality.md / quantified_quality_cn.md.


4. ✨ Core Features

Why token efficiency is the core metric?

CAD generation is inherently a multi-round process: code generation → execution → error analysis → repair → regenerate. A naive agent stuffs the full conversation (prompt + build123d docs + error stack) into context on every round, so tokens grow exponentially with iterations — per-run cost can climb from a few cents to a few dollars. MAC passes structured state instead of raw conversation, turning exponential growth linear: same multi-round iteration, 13× lower total cost, 116× fewer total tokens, and a higher 99.3% feature pass rate.

🚀 Structured state passing, not context replay — 13× token efficiency

Each agent's input is the previous stage's structured JSON output (CADBrief, ArchitectPlan), not a re-stuffed transcript. The Spec Planner reads only the user request; the Architect reads only CADBrief; the Coder reads only ArchitectPlan; Aider reads only the QA error report + build123d_reference.md. No agent ever re-reads the full conversation history. On the 10-prompt benchmark this cuts total tokens from 103.9M → 0.90M (116×) and total cost from ¥125.69 → ¥9.67 (13×), while raising the feature pass rate from 97.9% to 99.3%.

🔍 White-box transparency — audit or override any stage

Every intermediate artifact is on disk: pipeline_cache/cad_brief.json, pipeline_cache/architect_plan.json, temp_design_*.py, temp_measurements_*.json (white-box feature dimensions), temp_missed_*.json (runtime diagnostics classified as MISSED_CUT / FILLET_FAILED / CHAMFER_FAILED), QA report. The Autonomous Skill Loop also exposes an iteration checkpoint — after each QA pass it prints STEP/STL paths, QA status, and a 10-second window to pick auto-iterate / user-intervention / stop. Intervene mid-loop and your change requirements are prepended verbatim to the Aider repair prompt.

🧠 Hybrid routing — per-stage model freedom, more room for customization

A traditional single agent stuffs every task (requirement parsing, geometric design, code generation, error repair) into one model — you're forced to pick one "all-rounder" expensive model. MAC decouples these 4 stages so each stage can pick its own model (see the SPEC_PLANNER_* / ARCHITECT_* / CODER_* / AIDER_* / REPAIR_* blocks in config.py, each with independent MODEL / TEMPERATURE / MAX_TOKENS / KWARGS, e.g. the thinking-chain toggle):

  • Spec Planner (requirement parsing) — "read a paragraph, output structured JSON" is simple work; you can hang a cheap lightweight model or a local small model here
  • Geometric Architect and Python Coder — tasks that need spatial imagination and algorithmic reasoning should use a strong model like qwen3.7-max
  • Aider Repair — swap in Claude/GPT (better at code) or even train a local model specialized in build123d repair

Going further — since stages hand off only via structured JSON (CADBrief, ArchitectPlan), any one stage can be replaced with a specialized local model you trained without touching the others. For example, train a small model that only reads CADBrief and outputs ArchitectPlan, replacing the Architect stage's qwen call and dropping per-run cost from ~¥0.5 to near zero. This is impossible in a single-agent architecture — the single agent's prompt and context are deeply coupled, you can't swap just one piece.

🛡️ Deterministic translator — zero tokens for common CAD ops

LLM-only CAD agents burn tokens every time they generate code. MAC flips this: the deterministic translator _plan_to_code takes the Coder stage's "read JSON, write code" work entirely off the LLM — it translates ArchitectPlan directly into build123d code at zero token cost. It supports extrude, revolve, hole, boolean_union/cut, pattern_linear/circular, mirror, fillet, chamfer, shell, and other common CAD operations; only unsupported step types (draft, rib, custom polygons without control_points) emit # TODO_AIDER placeholders for Aider to fill.

This is one of the keys to the 1/116 token reduction: common geometric operations go through the translator, and the LLM is only invoked on edge cases. It's also the extreme of §4.4's hybrid routing — the Coder stage's model call drops to zero.

Default config: Qwen 3.7-max with thinking enabled on Planner/Coder/Repair, disabled on Architect for JSON determinism.

⏱️ Wall-clock speed — roughly 10× faster

Token efficiency (116×) and API-call reduction (26×) translate directly into wall-clock speed: less to generate, fewer round-trips to the LLM. No formal benchmark was run, but across the 10-prompt suite MAC consistently finished in roughly a tenth the wall-clock time of the single-agent baseline. Treat the 10× as an order-of-magnitude estimate, not a measured figure.

For the complete pipeline diagrams (Mermaid), GraphState definition, per-stage design rationale, and key implementation features, see multi_agent_cad/WORKFLOW.md.


5. 📝 Citation

If you find this project useful for your research, please consider citing:

@misc{mac2026,
  author = {Guanxing Qu and Xueyan Zou},
  title  = {MAC (Multi-Agent CAD): A Decoupled Multi-Agent Framework for Text-to-CAD Generation},
  year   = {2026},
  publisher = {GitHub},
  journal   = {GitHub repository},
  howpublished = {\url{https://github.com/Pan-Chera/Multi-Agent-CAD}}
}

The quantitative evaluation in this README uses earthtojake/text-to-cad (CAD Skills) as the comparison baseline. If your paper cites MAC, please also cite that project:

@misc{texttocad2026,
  author = {earthtojake},
  title  = {CAD Skills: A skills library for CAD, robotics, and hardware design agents},
  year   = {2026},
  publisher = {GitHub},
  journal   = {GitHub repository},
  howpublished = {\url{https://github.com/earthtojake/text-to-cad}}
}

📄 License

MIT — see LICENSE.

The vendored packages/cadpy STEP/GLB runtime is derived from earthtojake/text-to-cad (CAD Skills) and is redistributed under its original MIT license — see packages/cadpy/LICENSE.

🙏 Acknowledgements

  • Tsinghua University, IEI Lab — the lab where this project was developed; provided the research environment and advisor guidance
  • earthtojake/text-to-cad (CAD Skills) — source of the cad skill baseline used in the quantitative evaluation; the 10 benchmark prompts (P1–P10) are taken from the project's benchmarks/ directory. The vendored packages/cadpy runtime is also derived from this project and retains its original MIT copyright
  • build123d — algebraic B-rep CAD kernel
  • LangGraph — stateful agent orchestration
  • Aider — LLM-driven code repair
  • Qwen 3.7-max — DashScope LLM

About

MAC (Multi-Agent CAD): A decoupled multi-agent framework for text-to-CAD generation via constrained test-time compute

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

281 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages