☰
text-to-cad 实战:从自然语言到 STEP/GLB/STL 的 CadQuery 参数化建模
2026/10/26 7:28:22 网站建设 项目流程

1. 从一句话到三维模型:text-to-cad 到底在解决什么问题

第一次听到 text-to-cad 这个词,我脑子里蹦出来的画面是:对着电脑敲一句“给我画一个 80×60×20 的法兰盘,中心开直径 30 的通孔,四角各一个 M6 沉头孔”,然后屏幕上直接出现一个可以旋转、可以导出、可以拿去加工的实体模型。这个画面在几年前还属于科幻范畴,现在已经有了一批能跑通的原型工具和开源方案。text-to-cad 的核心,就是把自然语言描述转成 CAD 能识别的几何数据,最终落地成 STEP、GLB、STL 这类通用格式。

它解决的问题很具体。传统 CAD 建模,不管是 SolidWorks、中望 CAD 还是 FreeCAD,你都得先学草图约束、拉伸、旋转、布尔运算这一套。一个简单的支架,熟手也要十几分钟,新手可能折腾一两个小时还画不出来。而 text-to-cad 想干的事,是让“描述需求”和“生成几何”之间不再隔着软件操作这道墙。你描述得越清楚,模型越接近你要的东西。

适合关注这个方向的人其实比想象中多。做机械设计的工程师,可以用它快速出概念模型,省掉重复劳动;做 3D 打印的玩家,可以直接把想法变成 STL 去切片;做前端或者游戏开发的,需要 GLB 资产时也能用得上;甚至做钣金、做建筑构件的人,只要涉及参数化几何,都能从中找到价值。关键词里出现的 STEP、GLB、STL 正好对应了三条主流落地路径:STEP 走工程制造,GLB 走可视化与渲染,STL 走 3D 打印。

我自己的判断是,text-to-cad 现在还没到“一句话出成品”的程度,但它已经能承担“从想法到初稿”这一段。把它当成一个不知疲倦的建模助手,而不是替代设计师的黑盒,心态就对了。下面我会把整个链路拆开,从整体设计思路讲到具体实现,再到踩过的坑,尽量让你看完能自己动手跑一遍。

2. 整体设计与技术路线拆解

2.1 为什么不能直接让大模型“画图”

很多人第一反应是:现在多模态模型这么强,直接让它输出一个三维模型不就行了?实测下来这条路走不通。图像生成模型输出的是像素,它不理解“这个孔必须和那个轴同心”这种几何约束。你让它画一个齿轮,它可能画得很像,但齿数、模数、压力角全是错的,导出的 STL 拿去打印根本装不上。

所以 text-to-cad 的主流思路不是“生成模型”,而是“生成建模代码”。也就是说,大模型负责把自然语言翻译成一段可执行的建模脚本,再由几何内核去执行这段脚本,算出真正的 B-rep 实体或网格。这个分工很关键:语言模型擅长处理语义和意图,几何内核擅长处理精确计算,各干各的。

这个思路下,最终产出的模型精度取决于几何内核,而不是模型本身。只要脚本写对了,出来的 STEP 就是工程级精度,可以进 CAM 加工。这也是为什么 text-to-cad 能同时输出 STEP、GLB、STL——它们只是同一个几何体的不同导出格式。

2.2 三条主流技术路线对比

目前能跑通的方案大致分三类,我整理成表格方便对照:

路线核心工具输出格式精度上手难度适合场景
代码驱动型CadQuery / build123dSTEP、STL工程级中机械零件、参数化构件
网格生成型OpenSCAD / 网格脚本STL、GLB中等低3D 打印、概念模型
云端 API 型各类在线生成服务STEP、GLB、STL视服务而定低快速验证、非核心资产

代码驱动型的代表是 CadQuery,它基于 OpenCASCADE 内核,用 Python 描述几何。你写cq.Workplane("XY").box(80, 60, 20)就能得到一个长方体,再链式调用.faces()、.hole()就能开孔。这种方式的优势是参数化程度极高,改一个数字整个模型跟着变,特别适合做系列化零件。

网格生成型的代表是 OpenSCAD,它用类似编程的方式做 CSG(构造实体几何),本质上是布尔运算堆出来的网格。它的好处是语法简单,坏处是精度受限于网格分辨率,做曲面和精细特征比较吃力。

云端 API 型就是直接调服务,把文字发过去拿回模型文件。这种方式最省事,但可控性差,复杂零件经常生成得似是而非,而且涉及数据外传,做正经工程项目要谨慎。

2.3 我为什么最终选了 CadQuery 这条线

试过几轮之后,我把主力方案定在了 CadQuery 加本地大模型的组合上。原因有三点。第一,CadQuery 的输出是真正的 B-rep 实体,导出的 STEP 能被主流 CAD 软件打开并继续编辑,这是工程落地的前提。第二,它的 Python 接口对大模型很友好,模型见过的 Python 代码多,生成 CadQuery 脚本的准确率明显高于生成其他 DSL。第三,整条链路可以完全本地跑,不依赖外部服务,数据不出机器。

这里要说明一点,CadQuery 和 build123d 是同一批人做的,build123d 语法更现代,但生态和资料还不如 CadQuery 丰富。新手我建议从 CadQuery 入手,遇到瓶颈再考虑迁移。下面所有实操都以 CadQuery 为准。

3. 核心细节解析与实操要点

3.1 环境搭建:把地基打牢

环境这一步看着简单,实际上坑最多。CadQuery 依赖 OpenCASCADE,在 Windows 上装不好就是各种 DLL 报错。我的建议是直接用 conda 装,别用 pip 硬扛。

conda create -n text2cad python=3.11 conda activate text2cad conda install -c conda-forge cadquery

装完之后验证一下:

import cadquery as cq result = cq.Workplane("XY").box(10, 10, 10) cq.exporters.export(result, "test.step")

能生成 test.step 就说明环境没问题。如果报OCP相关的错,八成是 OpenCASCADE 版本冲突,重装 conda 环境基本能解决。

大模型这块,本地跑的话推荐用支持代码生成的模型,参数量 7B 到 14B 之间比较平衡。太小了代码写不对,太大了消费级显卡扛不住。量化版本能进一步降低显存占用,实测 4bit 量化后 14B 模型在 12G 显存上能跑。

注意:环境变量里如果有多个 Python 路径,conda 激活后一定要确认which python指向的是新环境,否则会出现“装了却 import 不到”的诡异情况。

3.2 提示词工程:让模型听懂人话

text-to-cad 的效果,七成取决于提示词。你不能直接甩一句“画个零件”就指望它出好东西。我的做法是给模型一个固定的系统提示,把 CadQuery 的常用 API 和输出规范写进去。

系统提示大概长这样:

你是一个 CAD 建模助手,使用 CadQuery 生成 Python 脚本。 要求: 1. 只输出可执行的 Python 代码,不要解释。 2. 所有尺寸用毫米。 3. 使用 cq.Workplane 链式调用。 4. 最后用 cq.exporters.export 导出 STEP 和 STL。 5. 变量命名清晰,关键尺寸用变量存储。

用户输入则尽量结构化。比如“画一个法兰盘”太模糊,改成“画一个外径 100、内径 40、厚度 10 的法兰盘,沿圆周均匀分布 6 个直径 8 的螺栓孔,分布圆直径 80”,模型生成的脚本就靠谱得多。

我总结了一个描述模板,按这个顺序说,命中率最高:

  1. 整体形状(长方体、圆柱、法兰、支架)
  2. 主要尺寸(长宽高、直径、厚度)
  3. 特征(孔、槽、倒角、圆角)
  4. 特征位置和数量
  5. 特殊要求(对称、阵列、公差)

3.3 几何内核:精度是怎么保证的

CadQuery 底层是 OpenCASCADE,这是一个工业级的几何内核,和很多商业 CAD 用的是同一套底层技术。它处理的是 B-rep(边界表示),也就是用精确的数学曲面来描述几何体,而不是用三角形网格去逼近。

这个区别很关键。STL 是网格格式,一个圆柱面会被切成很多小三角形,切得越细越接近圆,但永远不是真正的圆。而 STEP 保存的是“这是一个圆柱面,半径 20,轴线在这里”这样的精确描述。所以同一个模型,STEP 文件可能只有几十 KB,STL 却有几 MB,而且 STEP 放大后边缘依然光滑。

导出的时候要注意,STL 的精度由弦高和角度容差控制。默认值有时候太粗,打印出来能看到明显的多边形棱角。可以在导出时调小容差:

cq.exporters.export( result, "part.stl", tolerance=0.01, angularTolerance=0.1 )

tolerance 是弦高,单位毫米,越小越精细;angularTolerance 是角度容差,单位弧度。这两个值调太小文件会爆炸,一般 0.01 和 0.1 够用了。

3.4 格式选择:STEP、GLB、STL 各管一摊

这三个格式经常被混用,其实各有各的地盘。

STEP 是工程交换格式,几乎所有 CAD 软件都认。它的优势是精确、可编辑、能保留特征树(部分情况)。你要把模型发给加工厂,或者后续还要在 SolidWorks 里改,就导 STEP。

STL 是 3D 打印的事实标准,切片软件只认它。它只有三角面片,没有单位、没有颜色、没有装配关系。导出前一定要确认单位是毫米,否则打印出来尺寸差 25.4 倍。

GLB 是 glTF 的二进制版本,主打可视化和渲染。它支持材质、颜色、动画,网页端加载特别方便。做产品展示、游戏资产、AR 预览就用它。CadQuery 本身不直接导 GLB,一般先导 STL 或 OBJ,再用 trimesh 或 Blender 转一道。

import trimesh mesh = trimesh.load("part.stl") mesh.export("part.glb")

这一步转换会丢失精确几何,但对可视化来说无所谓。

4. 完整实操流程:从一句话到三个格式

4.1 需求描述与脚本生成

假设我要做一个简单的安装支架:底板 100×60×8,上面立一块 100×50×8 的竖板,竖板中心开一个直径 20 的孔,底板四角各一个直径 6 的通孔。

我把这段描述发给本地模型,附上系统提示。模型返回的脚本大概是这样:

import cadquery as cq # 参数 base_l = 100.0 base_w = 60.0 base_t = 8.0 wall_h = 50.0 wall_t = 8.0 hole_d = 20.0 mount_d = 6.0 mount_offset = 10.0 # 底板 base = cq.Workplane("XY").box(base_l, base_w, base_t) # 竖板,立在底板后侧 wall = ( cq.Workplane("XY") .box(base_l, wall_t, wall_h) .translate((0, base_w/2 - wall_t/2, base_t/2 + wall_h/2)) ) # 合并 part = base.union(wall) # 竖板中心孔 part = ( part.faces(">Y") .workplane() .hole(hole_d) ) # 底板四角安装孔 part = ( part.faces("<Z") .workplane() .rect(base_l - 2*mount_offset, base_w - 2*mount_offset, forConstruction=True) .vertices() .hole(mount_d) ) cq.exporters.export(part, "bracket.step") cq.exporters.export(part, "bracket.stl", tolerance=0.01, angularTolerance=0.1)

这段脚本能跑,但有几个地方需要人工检查。第一,竖板的位置对不对,translate 的 Z 值是不是让底面刚好贴合底板顶面。第二,faces(">Y")选的是不是竖板朝前的那个面,如果选错了孔会开在别的地方。第三,四角孔的定位是不是真的在四角。

4.2 脚本校验与修正

模型生成的脚本不能盲信,必须跑一遍看结果。我一般会加一段可视化代码,直接在 Jupyter 里看:

from cadquery.vis import show show(part)

如果环境不支持可视化,就导出 STL 用系统自带的 3D 查看器打开。重点看三个东西:整体比例对不对、特征位置对不对、有没有多余的实体。

我遇到过最常见的问题是坐标系搞混。CadQuery 默认 Z 轴向上,但很多人描述“竖板”时脑子里想的是 Y 轴向上。模型有时候会跟着错,把竖板放倒。这时候不用重写,改一下 translate 的参数就行。

还有一个高频问题是布尔运算失败。两个实体如果只是面贴面,没有真正相交,union 可能报错或者产生非流形几何。解决办法是让它们稍微重叠一点,比如竖板往下多伸 0.1mm 插进底板,合并完再把多余部分切掉。这个技巧在网格建模里也常用,叫“过盈合并”。

4.3 导出与后处理

脚本跑通之后,导出三个格式。STEP 直接给 CAD 软件,STL 给切片软件,GLB 给展示用。

导出 STL 的时候,我习惯用 trimesh 再过一道,检查网格是否封闭:

import trimesh mesh = trimesh.load("bracket.stl") print("是否水密:", mesh.is_watertight) print("体积:", mesh.volume) print("包围盒:", mesh.bounds)

is_watertight为 True 说明网格封闭,3D 打印不会出问题。如果为 False,多半是布尔运算留下了缝隙,需要回 CadQuery 里修。

转 GLB 的时候可以顺便加个材质:

mesh.visual.face_colors = [180, 180, 180, 255] mesh.export("bracket.glb")

这样在网页里加载出来就是灰色的金属感,比默认的白色好看。

4.4 参数化迭代

text-to-cad 最大的价值不是一次生成,而是快速迭代。支架做出来之后,客户说“底板加宽到 120”,你只需要改一个变量base_l = 120,重新跑脚本,三个格式全部更新。这个过程几秒钟,比在 CAD 软件里改草图快得多。

我一般会把所有关键尺寸抽成变量放在脚本开头,形成一个小型的参数表。更进一步,可以用 JSON 或 YAML 存参数,脚本读配置生成模型,这样非技术人员也能改尺寸。

import json with open("params.json") as f: p = json.load(f) base_l = p["base_l"] base_w = p["base_w"] # ...

这套做法在批量出图、系列化零件上特别香。关键词里提到的“python批量对cad修改”,本质上就是这个思路的延伸。

5. 常见问题与排查技巧实录

5.1 模型生成失败的高频原因

跑了几十次之后,我把失败原因归了类,做成速查表:

现象可能原因解决办法
脚本报语法错模型输出了伪代码或中文标点在提示词里强调只输出纯 Python
import 报错环境没装 cadquery回到 3.1 检查 conda 环境
布尔运算失败实体没有真正相交让实体过盈重叠 0.1mm
孔开错位置面选择器选错用faces(">Z")等明确指定方向
导出 STEP 为空没有实体,只有草图确认最后一步是实体操作
STL 打印有破面网格不水密用 trimesh 检查并修复
尺寸差 25.4 倍单位是英寸导出前统一转毫米

5.2 面选择器:最容易翻车的地方

CadQuery 的面选择器是新手最大的坎。faces(">Z")选的是 Z 方向最靠上的面,faces("<Z")是最靠下的,faces(">Y")是 Y 方向最靠前的。但“最靠前”是相对于当前工作平面说的,如果你之前做过旋转或平移,方向可能和你想象的不一样。

我的经验是,每做一步操作就打印一下当前实体的面数和包围盒,确认状态:

print("面数:", part.faces().size()) print("包围盒:", part.val().BoundingBox())

包围盒能告诉你实体在空间中的实际范围,比凭感觉猜靠谱得多。如果发现实体跑到别的地方去了,多半是某一步 translate 的参数写反了。

还有一个技巧是用faces(cq.selectors.BoxSelector(...))按空间范围选面,比方向选择器更精确。比如要选 Z 在 8 到 16 之间的所有面:

from cadquery import selectors part = part.faces(selectors.BoxSelector((-100, -100, 8), (100, 100, 16)))

5.3 大模型幻觉的应对

大模型生成 CadQuery 代码时,最常见的幻觉是编造不存在的 API。比如它会写cq.Workplane("XY").cylinder(10, 20),但 CadQuery 里圆柱的正确写法是.circle(10).extrude(20)或者.cylinder(height, radius),参数顺序还不一样。

应对办法有两个。一是在系统提示里附上常用 API 的正确签名,让模型照着抄。二是生成后先做静态检查,用ast模块解析一下,看有没有明显不存在的函数调用。更彻底的办法是维护一个 API 白名单,生成后逐个比对。

import ast allowed = {"Workplane", "box", "circle", "extrude", "hole", "union", "cut"} tree = ast.parse(code) for node in ast.walk(tree): if isinstance(node, ast.Attribute): if node.attr not in allowed: print("可疑调用:", node.attr)

这个检查不能保证 100% 正确,但能拦下大部分低级错误。

5.4 性能优化:别让脚本跑太久

简单的零件脚本几秒就跑完,但复杂模型——比如几百个孔的阵列、复杂的曲面——可能跑几分钟甚至卡死。我踩过的坑里,最常见的是阵列数量写太大。模型看到“均匀分布”就给你来个 360 个孔,几何内核直接跪。

解决办法是在提示词里限制阵列数量,或者生成后人工检查循环次数。另外,CadQuery 的布尔运算很吃性能,能一次 union 就不要分多次。把多个实体收集到列表里,用union(*solids)一次性合并,比循环 union 快好几倍。

solids = [make_pin(i) for i in range(20)] part = solids[0].union(*solids[1:])

还有一点,导出 STL 时容差别调太小。0.001 的容差能让文件从几 MB 涨到几百 MB,切片软件打开都费劲。0.01 对绝大多数 3D 打印场景足够了。

5.5 与现有 CAD 工作流的衔接

text-to-cad 生成的 STEP 能不能直接进 SolidWorks 或中望 CAD?能,但要注意版本。STEP 有 AP203、AP214、AP242 几个版本,AP242 保留的信息最全,支持颜色和装配。CadQuery 默认导 AP214,一般够用。如果对方软件打不开,试试指定版本:

cq.exporters.export(part, "part.step", opt={"write_pcurves": False})

导入之后,模型通常是一个“哑实体”,没有特征树,不能直接改尺寸。想改还得回脚本改参数重新生成。所以我的工作流是:text-to-cad 出初稿和参数化版本,需要精细调整的再进 CAD 软件做后期。两者不是替代关系,是接力关系。

关键词里有人问“sw 中 stl 转 stp”,这其实是逆向工程的路子。STL 转 STEP 需要曲面重建,精度损失很大,能不做就不做。正确的做法是一开始就用 text-to-cad 直接生成 STEP,跳过网格这一环。

6. 进阶玩法与扩展方向

6.1 批量生成与系列化零件

把参数抽出来之后,批量生成就是循环的事。比如做一整套不同长度的支架:

import cadquery as cq def make_bracket(length): base = cq.Workplane("XY").box(length, 60, 8) # ... 其余建模逻辑 return base for L in [80, 100, 120, 150]: part = make_bracket(L) cq.exporters.export(part, f"bracket_{L}.step")

这套逻辑配合配置文件,能实现“改表出图”。做钣金、做型材、做标准件的人应该对这个场景很熟悉。关键词里的“金林钣金 cad 版”这类工具,核心能力之一就是参数化批量出图,text-to-cad 相当于用自然语言驱动了同样的流程。

6.2 结合 3D 打印的闭环

生成 STL 之后直接调切片软件的命令行接口,能实现全自动。比如用 PrusaSlicer 的命令行:

prusa-slicer --export-gcode --load config.ini part.stl

生成的 G-code 直接丢给打印机。整个链路从一句话到可打印文件,中间不需要人工打开任何软件。当然,实际打印前还是要人工检查一下模型,但至少省掉了建模和切片两步。

6.3 网页端预览

GLB 格式在网页端加载特别方便,用 three.js 几行代码就能转起来:

import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; const loader = new GLTFLoader(); loader.load('bracket.glb', (gltf) => { scene.add(gltf.scene); });

这样客户在浏览器里就能 360 度看模型,不用装任何软件。做定制化产品的,这个体验提升很明显。

6.4 局限性与边界

说了这么多好处,也得说说 text-to-cad 现在做不到什么。复杂曲面、自由造型、有机形态,它基本无能为力。你让它画一个汽车外壳或者一个人像,出来的东西没法看。这些场景还是得靠传统建模或者雕刻软件。

装配体也是弱项。多个零件的配合关系、运动约束,自然语言很难描述清楚,模型也理解不了。目前 text-to-cad 最适合的是单体的、规则的、参数化的零件。

还有就是精度要求极高的场景,比如航空件、精密模具,生成的模型只能当参考,最终还是要工程师在专业软件里重新做。把它当成草稿工具,而不是生产工具,预期就对了。

7. 我踩过的坑和几条实在建议

折腾 text-to-cad 这段时间,最大的体会是:别指望它一步到位,把它当成一个需要调教的助手。第一版脚本能跑通就谢天谢地,剩下的靠迭代。我现在的习惯是,先生成一个最简版本,确认环境、导出、查看这条链路通了,再逐步加特征。一次性描述太复杂,模型容易顾此失彼。

第二个体会是,参数化思维比建模技巧更重要。写脚本的时候,凡是可能变的尺寸都抽成变量,哪怕现在用不上。等到客户要改的时候,你会感谢自己当初多写的那几行。

第三个是版本管理。生成的脚本和模型文件一定要用 git 管起来,每次改参数都提交一次。text-to-cad 的迭代速度很快,没有版本管理,改着改着就不知道哪版是对的了。

最后分享一个小技巧:如果模型生成的脚本总是差一点,别急着重新生成,先手动改两行试试。很多时候问题很小,比如少了一个.clean()或者面选择器方向反了。手动改比重新生成快得多,而且改的过程能帮你理解 CadQuery 的工作方式。等你能一眼看出脚本哪里不对,text-to-cad 对你来说就不再是黑盒,而是一个真正顺手的工具了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询