Administrator
Administrator
发布于 2026-07-02 / 14 阅读
0
0

用 LLM 写代码搞机械建模:CadQuery + Claude Code/Codex 实战,把需求直接变成可打印的 3D 实体

一、痛点:机械设计为什么难被 LLM 接管

做硬件、做机器人的同学大概都有过这种体验:脑子里一个工装方案已经想清楚了,但要落地,得打开 SolidWorks / Fusion 360,鼠标点几百下——画草图、拉伸、打孔、倒角、阵列、装配……一套下来半天没了。改个尺寸?重新点一遍。

这种GUI 驱动、操作密集的工作流,LLM 根本插不上手。它能写代码,但点不了鼠标。

所以问题变成了:有没有一种方式,让机械建模本身变成"写代码"? 只要建模是代码,LLM 就有了着力的支点。

答案是 CadQuery——一个纯 Python 的脚本化 CAD 库。

二、为什么选 CadQuery

CadQuery 不是又一个画图玩具,它的定位很明确:用 Python 代码做参数化实体建模,底层是工业级内核 OpenCASCADE(OCP)

和同类方案比:

  • vs FreeCAD:FreeCAD 是 GUI 应用,CadQuery 是纯代码库,天然适合 LLM 生成。
  • vs OpenSCAD:OpenSCAD 用自己的 DSL,靠 CSG 布尔拼凑;CadQuery 用 Python,能用循环/函数/数学库,表达能力高一个量级,且底层是 B-Rep 实体(精度远高于多边形网格)。
  • vs 直接调 OpenCASCADE:OCP 原生 API 极其繁琐,CadQuery 在上面封了一层 fluent API(Workplane().box().cut()),可读性接近自然描述。

最关键的是产出:CadQuery 能直接导出 STEP(工程级,可进任何 CAD/CMC)和 STL(打印用)。这意味着 LLM 生成的代码,端到端能落地到一个真实的、可制造的结果——不是停在屏幕上的渲染图。

我们这边的版本是 CadQuery 2.7,跑在独立 venv 里。

三、核心思路:把 LLM 变成"机械建模工程师"

很多人用 LLM 做技术活失败,不是因为模型不行,而是没给它一份像样的"岗位说明书"

做机械建模尤其如此——LLM 默认会写出"能跑但不可打印"的东西:零厚度面、自交、悬垂 80°、薄壁 0.5mm、孔没留公差……每一个都是打印翻车现场。

所以这个项目的核心不是调 prompt 技巧,而是写两份严格的工程规范文件,把一个资深机械工程师脑子里的"纪律"固化下来:

  • CLAUDE.md —— 给 Claude Code 的岗位说明
  • AGENTS.md —— 给 Codex 的岗位说明(OpenAI 的 agent 用 AGENTS.md 约定)

两份文件都把 LLM 的角色定义为同一句话:精通 CadQuery 的机械建模工程师,产出可直接运行、可 3D 打印、参数可调的模型脚本。

规范里钉死的几条硬约束(节选):

  • 目标打印机 Bambu Lab P1S,可用体积 250×250×250mm——任何单件包围盒三方向都必须 ≤250mm,超出必须主动拆件
  • 参数化纪律:所有尺寸在文件顶部定义为大写参数变量 + 中文注释,几何代码里禁止魔法数字;
  • 可打印性:水密实体、布尔运算后 .val().isValid() 自检、薄壁 ≥2mm、孔位预留 0.2~0.4mm 公差、悬垂 >45° 必须标注"需要支撑";
  • CadQuery 编码习惯:显式基准面、选择器要注释(.faces(">Z") # 选择顶面)、布尔运算前对齐坐标系;
  • 每个项目强制三件套:源码 .py + preview.py(双模式预览)+ README.md,外加 stl/step/ 产物目录;
  • 文首信息块:每个 .py 顶部必须有项目名/开发者/版本/时间/说明。

这不是"建议",是"必须"。LLM 一旦接受这套规范,它的产出就从"看起来像 CAD 的代码"变成了"真的能上打印机的工程件"。

四、工具链搭建

一份干净的 venv 是基础:

python3 -m venv .venv
.venv/bin/pip install --upgrade pip wheel setuptools
.venv/bin/pip install cadquery        # 核心建模 + STL/STEP 导出 + 自带 VTK 预览器
.venv/bin/pip install cq-editor       # GUI 预览器(PyQt5)

验证安装:

.venv/bin/python -c "import cadquery as cq; print(cq.__version__)"
# 2.7

之后所有运行/导出都走这个 venv 的解释器,不用系统 python3,避免环境污染。

五、实战案例:食材体积扫描的烤箱工装

需求很具体:验证一个**"深度相机 + 转台"**的食材体积估计方案,需要一个小型扫描腔体工装——前开放矩形腔体,底部带 NEMA17 步进电机驱动的转台,顶部后角装倾斜俯视的深度相机,顶部前方装环形光源。

腔体内部默认 200×200×220mm,总装高度逼近 250mm 上限,必须拆件打印

参数化:改一个数,整件联动

源码顶部把所有尺寸定义清楚(节选):

# --- 腔体 ---
CHAMBER_W = 200        # 腔体内部宽度 (X)
CHAMBER_D = 200        # 腔体内部深度 (Y)
CHAMBER_H = 220        # 腔体内部高度 (Z)
WALL_T = 3             # 壁厚

# --- 转台 ---
TURNTABLE_DIA = 100    # 转台盘直径
SHAFT_DIA = 8          # 转台中心轴孔直径(配电机轴)
MOTOR_MOUNT_W = 42     # NEMA17 电机安装方孔边长

# --- 相机支架 ---
CAM_TILT_DEG = 45      # 相机俯视倾角(相对水平)
CAM_LENS_HOLE_DIA = 15 # 镜头避让开孔直径

派生尺寸由参数计算,不写死:

OUT_W = CHAMBER_W + 2 * WALL_T   # 外形宽 = 206
# 相机楔形支架高度,由倾角三角推出,保证光学轴 = CAM_TILT_DEG
WEDGE_H = FLANGE_D * math.tan(math.radians(90 - CAM_TILT_DEG))

想把腔体加大、相机倾角改成 40°?动两个数,所有部件重新生成。这是 GUI 建模给不了的迭代速度。

部件函数:每个零件一个 make_xxx()

每个独立部件封装成函数,返回 cq.Workplane 对象。以底座为例(节选,已去掉部分细节):

def make_base():
    """底座+转台座:含墙板榫卯槽、电机方孔、4 螺丝孔、中心轴孔、转台凸台。
    打印朝向:底面朝下。"""
    b = cq.Workplane("XY").box(OUT_W, OUT_D, BASE_THICK,
                               centered=(True, True, False))
    # 前/后墙板榫卯槽(顶面下切)
    for sy in (1, -1):
        groove = (cq.Workplane("XY")
                  .box(OUT_W, GW, GROOVE_D, centered=(True, True, False))
                  .translate((0, sy * (CHAMBER_D/2 + GW/2), BASE_THICK - GROOVE_D)))
        b = b.cut(groove)
    # 电机安装方孔(贯穿)
    b = b.cut(cq.Workplane("XY").box(MOTOR_MOUNT_W, MOTOR_MOUNT_W, BASE_THICK+4)
              .translate((0, 0, -2)))
    # 中心轴孔 + 转台凸台 ...
    return b

看到没?这段代码读起来几乎就是一句自然语言:"取一块板,在顶面四边切出墙板槽,中间开个电机方孔,再立个转台凸台。" 这正是 CadQuery 配合 LLM 的杀手锏——代码即设计意图,可读、可改、可 diff。

运行、导出、验证

一条命令导出全部 STL/STEP:

.venv/bin/python 2026-07-01-体积扫描烤箱工装/oven_tooling.py

交付前必须过两道自检——包围盒 ≤ 250mm + 水密性 isValid

.venv/bin/python -c "import cadquery as cq; \
  r=cq.importers.importStep('2026-07-01-体积扫描烤箱工装/step/base.step'); \
  bb=r.val().BoundingBox(); \
  print('bbox', round(bb.xlen,1), round(bb.ylen,1), round(bb.zlen,1), \
        'valid', r.val().isValid())"
# bbox 206.0 206.0 16.0 valid True

最终产出的部件包围盒(证明全部 ≤ 250mm):

部件 X×Y×Z (mm)
base 底座 206 × 206 × 16
wall 墙板 206 × 3 × 226
top 顶板 206 × 206 × 6
camera_bracket 相机支架 52 × 45 × 45
turntable 转台盘 100 × 100 × 5

最大单件 226mm < 250mm ✓,全部 isValid=True ✓。这套件可以直接切片上机。

双模式预览:同一份 preview.py 兼容两种看法

这里有个很实用的工程技巧:一个 preview.py 同时兼容命令行预览和 GUI 预览,靠环境探测自动分支,用户不用改代码:

from cadquery.vis import show
# 探测是否在 CQ-editor 中运行(它会向命名空间注入 show_object)
try:
    show_object            # noqa
    _IN_CQ_EDITOR = True
except NameError:
    _IN_CQ_EDITOR = False

if _IN_CQ_EDITOR:          # 方式2:CQ-editor,各部件命名显示
    for name, obj, color in DISPLAY:
        show_object(obj, name=name, options={"color": color, "alpha": 0.9})
else:                      # 方式1:命令行,弹 VTK 窗口
    show(*[o for _, o, _ in DISPLAY])

两种用法:

# 方式1:命令行直接弹 VTK 窗口(先导出总装 preview STEP)
.venv/bin/python 2026-07-01-体积扫描烤箱工装/preview.py
.venv/bin/python 2026-07-01-体积扫描烤箱工装/preview.py --png out.png   # 无桌面离屏出图

# 方式2:CQ-editor 打开,右侧 Objects 面板逐件显隐/改色
.venv/bin/CQ-editor 2026-07-01-体积扫描烤箱工装/preview.py

这种“一份脚本双模式”的设计,是规范里强制要求的——交付物不能只给个 .py 让人自己琢磨怎么看。

📸 【实拍截图位置 · Claude Code】 下图是 Claude Code(国产 GLM 模型代理)实际生成的 3D 模型渲染——烤箱扫描工装总装预览,来自 2026-07-01-体积扫描烤箱工装/preview.py 的运行结果。

六、双 Agent 同题对照:这条路可复现

这个项目最有意思的地方,是用 Claude Code 和 Codex 两个不同的 agent,独立做同一个题

  • Claude Code 产出 → 2026-07-01-体积扫描烤箱工装/oven_tooling.py,7 个部件函数,榫卯 + M3 螺纹杆组装)
  • Codex 产出 → CX-2026-07-01-烤箱扫描工装/oven_scan_fixture.py,9 个部件,榫槽 + M3 通孔,版本 v1.1)

📸 【实拍截图位置 · Codex】 下图是 Codex(GPT-4)实际生成的 3D 模型项目截图——同一个烤箱扫描工装需求的另一套实现,来自 CX-2026-07-01-烤箱扫描工装/

两套方案细节不同(拆件粒度、连接方式各有取舍),但都满足同一份规范:参数化、可打印、双模式预览、包围盒全部 ≤250mm、isValid=True、都带完整 README。

这说明了一件重要的事:让 LLM 做参数化机械建模,不是某个模型的偶然 lucky shot,而是一套可复现的方法论。 只要规范写到位,不同 agent、不同模型都能稳定产出合格的工程件。这才是"能用"和"玩具"的分水岭。

当然,两个 agent 的产出也有差异——这正是双跑的价值:同题双答,工程师做选型/合并,比单跑一次盲信结果靠谱得多。

七、踩出来的几条经验

跑通这个项目,有几点值得记下来:

  1. 规范比模型更重要。同一份 CLAUDE.md/AGENTS.md,换了 agent 也能跑通;反过来,没有规范约束的强模型,照样写出不可打印的废件。纪律 > 模型能力。

  2. 可打印性约束必须显式写进规范。水密、薄壁、公差、悬垂——这些是机械工程师的肌肉记忆,但 LLM 没有。你得替它写进"岗位说明书",否则它根本意识不到 0.5mm 薄壁打印不出来。

  3. isValid() 是底线。布尔运算(union/cut)很容易产生非流形、零厚度面。每件导出后必须过 .val().isValid(),不过就返工。这是自动验证闭环的关键一环。

  4. 参数化让 LLM 的迭代优势真正发挥。GUI 建模改尺寸成本极高,LLM 改一个参数重跑一次,几秒钟。参数化 + 代码 + LLM,三者叠加才叫降维打击。

  5. 交付物要"自解释"。源码 + preview.py + README 三件套,让任何接手的人(或下一个 agent)能立刻运行、预览、验证。这是把一次性脚本变成可持续工程资产的前提。

  6. 文首信息块不是形式主义。项目名/版本/时间/说明,让每件产出可追溯、可版本管理。机械设计终于能像软件一样 git diff 了。

八、观点:机械设计正在被"代码化"

做完这个案例,我对一个趋势更确信了:机械设计正在从"操作密集的手艺"变成"代码驱动的工程"

这件事的连锁反应很深远:

  • 可版本化:实体模型能进 Git,每一次修改有 diff、有 commit、有 blame。传统 CAD 文件几乎做不到。
  • 可自动化:参数一改,整件重生;CI 里跑 isValid 和包围盒检查,把"能不能打印"变成自动化测试。
  • 可被 LLM 接管:当代码是建模的唯一入口,LLM 就成了最自然的"建模工"——它读规范、写代码、跑验证、改参数,闭环。

但这不意味着机械工程师要失业。恰恰相反——当"怎么画"被代码和 LLM 接管,工程师的价值上移到了"画什么、为什么这么约束、怎么验收"

  • 需求拆解(这个工装要解决什么扫描问题、转台要多大、相机俯角几度);
  • 约束定义(打印机体积、壁厚、公差、配合方式);
  • 结果验收(包围盒、水密、装配干涉、实际打印)。

这些是 LLM 替不了的判断力。和之前聊量化部署、MLOps 选型一样——AI 接管执行层,工程师退到决策层。 工具变了,工程师的护城河没变:对问题的理解、对边界的把握、对结果的负责。

九、结语

这个项目验证了一件具体的事:今天,你完全可以把"我需要一个工装件"这句话,丢给一个被工程规范约束好的 LLM,几分钟后拿到一份参数化、可打印、带预览和文档的完整工程包。

而且不止一个 agent 能做到——Claude Code 行,Codex 也行。方法可复现。

机械设计的代码化不是未来时,是现在进行时。对做硬件、机器人、嵌入式工装的同学来说,早点把你的建模纪律写成规范、交给 LLM,比纠结"哪个 CAD 软件更好用"值得得多。

下次你需要打个工装件,试试先写代码。


参考链接: [1] CadQuery 官方文档(Python 脚本化 CAD) https://cadquery.readthedocs.io/

[2] CadQuery 源码仓库(GitHub) https://github.com/CadQuery/cadquery

[3] CQ-editor GUI 预览器(GitHub) https://github.com/CadQuery/CQ-editor

[4] OpenCASCADE / OCP 内核官网 https://dev.opencascade.org/

[5] Claude Code 官方介绍 https://www.anthropic.com/claude-code

[6] OpenAI Codex 介绍 https://openai.com/index/openai-codex/

[7] Bambu Lab P1S 3D 打印机 https://bambulab.com/


评论