Tsinghua University · IEI Lab
4 agents collaborating · 116× fewer tokens · 99.3% feature pass rate — turn concise natural language directly into printable 3D models.
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.
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.
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.
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 |
![]() |
![]() |
![]() |
![]() |
![]() |
| S6 | S7 | S8 | S9 | S10 |
|---|---|---|---|---|
| Articulable gyroscope | Multi-link chain | Geneva mechanism | Plasma reactor | Brake disc |
![]() |
![]() |
![]() |
![]() |
![]() |
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.
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.
git clone https://github.com/Pan-Chera/Multi-Agent-CAD
cd Multi-Agent-CAD
conda env create -f environment.yml
conda activate multi_agent_cadpip users (no conda):
aider-chatpinsnumpy==1.26.4, butbuild123d>=0.8requiresnumpy>=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-resetconsole script and lets you runpython -m multi_agent_cad.graphfrom any directory. See requirements.txt / pyproject.toml for the canonical dependency list.
Windows:
conda env create -f environment.ymlworks out of the box —trimeshandrtreecome from conda-forge prebuilt;OCPis pulled in transitively bybuild123d(via its PyPI depcadquery-ocp-novtk). Don't use the pure-pip workaround above on Windows — native wheels fortrimesh/rtreecan be unreliable. Set the API key in PowerShell as$env:DASHSCOPE_API_KEY = "sk-..."(orset DASHSCOPE_API_KEY=sk-...in cmd.exe). For the Web UI under conda,pip install -e ".[web]"inside the activated env works —uvloopauto-skips on Windows. Windows isn't in CI, but the code avoids Unix-only APIs and uses UTF-8 throughout; issues welcome.
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 --resetMAC 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-maxmay 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*_MODELfield accepts whatever model ID your provider exposes; nothing in the code is Qwen-specific. The only Qwen-specific piece is theenable_thinkingtoggle inside*_KWARGS— set*_KWARGS = {}for other providers (more per-provider examples live in config.py).
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.
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*.pyBoth 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.
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:8000Open 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.
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.jsonOr bypass via code: set force_refresh: True in get_default_initial_state in multi_agent_cad/graph.py.
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.
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.
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.
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%.
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.
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.
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.
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.
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}}
}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.
- 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 skillbaseline used in the quantitative evaluation; the 10 benchmark prompts (P1–P10) are taken from the project's benchmarks/ directory. The vendoredpackages/cadpyruntime 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






















