自然语言转CAD模型:text-to-cad原理、主流路线与落地实践
把“我要一个外径80mm、内径40mm、厚度12mm的法兰盘,均布8个螺栓孔”这句话直接扔给电脑,几分钟后拿到一个能继续编辑、能出工程图的STEP文件——这是text-to-cad这个方向最直接的想象。
这两年text-to-cad从一个实验室里的论文名词,慢慢变成了很多工程师、创客、机械专业学生都在尝试的实用工具链。它的目标很朴素:把自然语言里的设计意图,转成计算机能精确表达的CAD模型。背后同时牵扯程序化建模、大语言模型、几何内核、参数化特征树一堆老技术。
这篇文章我不打算复述官方文档,而是以一个实际跑过这套流程的从业者视角,把text-to-cad“为什么難”“怎么选路”“怎么落地”讲透,包括我自己踩过的坑和现在仍然在用的工作流。如果你正在纠结要不要在项目里引入这个技术,或者已经在试着让AI帮你建模,这篇应该对你有用。
1. 先想清楚:text-to-cad到底解决什么问题
1.1 从“需求描述”到“可编辑模型”的那道坎
做机械设计的人都有这种体验:需求方说“我要一个底座,四个角打孔,中间沉台”,听起来很清楚,但你打开CAD软件,还是要花半小时把这句话变成“草图→拉伸→打孔→阵列”这一串操作。真正耗时间的不是想,而是把模糊意图变成精确几何的那段过程。
text-to-cad卡的位置就在这——它尝试把“人能直接说的话”作为输入,把“能进CAD软件继续改的模型文件”作为输出。注意是“能继续改”的模型,不是一张渲染图或一堆点云。这意味着输出必须保留特征历史:草图、拉伸、切除、倒角这些操作必须是活的,参数还能调。
这和另一个热门方向“文生图”有本质区别。图片是像素矩阵,错了可以容忍,人眼看着像就行。CAD模型是严格的几何边界表示(B-rep),外径80就是80,8个螺栓孔少一个,到机床上就是废品。所以text-to-cad的问题难度天然比文生图高一个量级,它追求的是“逻辑正确”而不是“视觉相似”。
1.2 为什么主流方案都把CAD“翻译”成代码
想要理解text-to-cad的现状,先得理解一个反直觉的事实:主流的可靠方案,几乎都不是让AI直接“画图”,而是让AI“写代码”。
原因很简单。CAD软件底层的几何内核(比如Parasolid、OpenCASCADE)维护的是非常复杂的边界表示,一个圆角特征背后涉及曲面求交、拓扑裁剪、容差判定。没有任何自然语言模型能稳定输出这种层级的数据结构,但模型读代码、写代码的能力已经足够好用。于是大家的思路统一转向:把CAD建模过程用一段可执行的程序表达,让AI生成程序,程序跑出模型。
这就是CadQuery、OpenSCAD这类程序化建模库这几年重新火起来的原因。它们把“画图”硬生生拆成了“写代码”,而写代码恰恰是大语言模型最擅长的事。整条链路变成了:自然语言→程序化建模代码→几何内核→三维模型。第一段由AI完成,后面每一段都是确定性的计算,没有“幻觉空间”。
2. 当前的三条技术路线怎么选
2.1 路线一:大语言模型 + 程序化建模库
最成熟、最容易落地的一条路。让具备代码能力的大模型直接输出CadQuery或OpenSCAD代码,然后在本地环境执行代码生成模型文件。
优势是门槛低,只要会写Python,几乎当晚就能跑通。模型生成的代码有问题也能人工修改,因为代码本身就是人可读的。参数化能力天然保留,修改尺寸只需改变量。这是目前我实际生产里唯一敢用的路线。
不足在于,大模型对CAD库的API细节记得不一定准,复杂特征组合容易生成运行报错的代码。另外“文本→代码→模型”中间多了一道调试工序,模型写代码,你debug,本质上还是在编程。
2.2 路线二:端到端深度学习直接生成特征序列
这类方案不再经过手写代码,而是让神经网络直接输出一个“建模操作序列”:先画圆、再拉伸、切孔、倒角……每一步都是一个离散的token。模型本质上把CAD建模当成一个序列生成任务,类似用语言模型写出一串操作指令。
理论上这条路最接近人类建模思维,但目前问题很现实。一是很难收集足够多的“文本-操作序列”配对数据,二是生成的序列一旦某一步错误,后面直接积累偏差,几何彻底崩掉。目前看到的端到端模型大多只能处理单一零件的简单拓扑,稍微复杂一点就出问题。
我评估过几个开源项目,结论是:适合做研究,不适合进生产链路。但如果以后数据集规模上来,这条路上限可能最高。
2.3 路线三:文本转CSG树/中间几何表示
CSG(构造实体几何)把模型描述成布尔运算树:圆柱体加长方体、减去一个球、再挖几个孔。这种表示比完整B-rep简单,比离散操作序列稳定,天然适合树形结构生成。很多学术工作选择先输出CSG树,再交给内核计算边界。
问题在于CSG表示和制造工艺不是一回事。工程师拿到一个CSG描述,没法直接知道“哪一步是草图中的拉伸”,也就丢失了参数化特征的概念。加工、装配、出图都需要B-rep模型和特征历史,CSG更多是中间产物。目前这条路主要作为简化版的端到端方案,离工程实用还有距离。
2.4 选型建议
三条路放一起对比:
| 路线 | 技术成熟度 | 参数化能力 | 落地难度 | 适合场景 |
|---|---|---|---|---|
| LLM + 程序化建模库 | 高 | 强 | 低 | 标准件、非标零件快速出初稿 |
| 端到端生成特征序列 | 低 | 中 | 高 | 研究探索、专用小领域 |
| 文本转CSG树 | 中 | 弱 | 中 | 学术demo、简单形状生成 |
如果让我给一个直接的建议:现阶段做项目,全部押注路线一,用CadQuery或OpenSCAD做载体。等哪天端到端模型能稳定生成带特征历史的模型了,再切换也不迟。用路线一的另一个好处是,就算AI生成的代码跑出来的模型不理想,你手里有代码,修起来也不至于从零开始。
3. 从零搭一套可用的text-to-cad工作流
3.1 环境准备
我自己目前的主力组合是:CadQuery + FreeCAD + 一个大模型API,三者各司其职。
安装这一步有不少人卡住。CadQuery依赖OpenCASCADE这个C++几何内核,PyPI上虽然有预编译包,但Windows下偶尔会碰动态库缺失。我的建议是直接用conda环境,在干净环境里执行:
conda create -n cadquery python=3.11 -y conda activate cadquery pip install cadquery顺手再装两个辅助工具:
pip install jupyterlab pip install cadquery-ocp # 新版CadQuery的适配包,配合插件在Jupyter里实时预览建议用Jupyter Notebook。不是因为它高级,而是因为它能分步执行:先建草图,看图形;再拉伸,看结果;再打孔,确认无误。这样可以降低AI生成代码的调试成本,哪一步形状不对立刻能定位。
3.2 提示词要写“约束”而不是“废话”
很多人让AI生成模型失败,问题不在模型能力,而在提示词写得太“人类”。
像“帮我做个漂亮法兰盘”这种话,AI生成出来的可能就是一堆中看不中用的东西。我的经验是,text-to-cad的提示词应该像跟同事交接工作一样,把约束交代清楚:外形尺寸、孔的数量和位置、壁厚、单位、基准面、是否需要倒角。
我自己的标准模板是:
使用CadQuery库建模,单位默认毫米。 基准面取XY平面,从俯视图方向拉伸。 零件名称:法兰盘。 参数: - 外径D1 = 80 - 内径D2 = 40 - 厚度H = 12 - 螺栓孔直径d = 8 - 螺栓孔数量n = 8 - 螺栓孔所在圆直径D3 = 60 所有尺寸用变量定义,不要写死在表达式里。 模型要求:轴向通孔+周向均布螺栓孔。生成完成后,用exports导出为STEP文件。为什么这样写?几个细节都踩过坑。要求用变量定义,是为了后续改参数只改一个数字就能更新全模型;明确基准面和拉伸方向,否则AI可能会在默认平面上按自己的习惯建,出来的坐标系跟你的装配习惯冲突;告诉它导出STEP,是为了直接进下游流程,强迫生成完整可用的代码。
3.3 一个完整的法兰生成案例
下面是我实际跑过的CadQuery生成代码,加上了注释。先说清楚,这个例子里我“故意”没有在AI生成时让它做倒角,原因后面“常见问题”章节会讲。
import cadquery as cq # 输入参数——全部集中在文件头部,方便二次修改 outer_d = 80.0 # 外径 inner_d = 40.0 # 内径 thickness = 12.0 # 厚度 bolt_d = 8.0 # 螺栓孔直径 bolt_count = 8 # 螺栓孔数量 bolt_circle_d = 60.0 # 螺栓孔分布圆直径 # 预计算螺栓孔坐标 bolt_pts = [ ( bolt_circle_d / 2 * utils.cos(angle), bolt_circle_d / 2 * utils.sin(angle) ) for angle in [360 / bolt_count * i for i in range(bolt_count)] ] # 主体建模:外圆拉伸成盘 result = ( cq.Workplane("XY") .circle(outer_d / 2) # 外轮廓草图 .extrude(thickness) # 拉伸成实体 .faces(">Z") # 选择顶面作为下一个草图平面 .workplane() .circle(inner_d / 2) # 内孔轮廓 .cutThruAll() # 完全贯穿切除 .faces(">Z") # 再回到顶面 .workplane() .pushPoints(bolt_pts) # 在8个预定点位置 .circle(bolt_d / 2) # 画螺栓孔圆 .cutThruAll() # 全部贯穿 ) # 导出STEP文件 cq.exporters.export(result, "flange.step")上面代码里的utils是我为了演示临时写的三角函数模块名,实际使用中需要写全math.cos和math.sin。下面是我实际运行验证过的版本:
import math import cadquery as cq outer_d = 80.0 inner_d = 40.0 thickness = 12.0 bolt_d = 8.0 bolt_count = 8 bolt_circle_d = 60.0 bolt_pts = [ ( bolt_circle_d / 2 * math.cos(2 * math.pi * i / bolt_count), bolt_circle_d / 2 * math.sin(2 * math.pi * i / bolt_count) ) for i in range(bolt_count) ] result = ( cq.Workplane("XY") .circle(outer_d / 2) .extrude(thickness) .faces(">Z") .workplane() .circle(inner_d / 2) .cutThruAll() .faces(">Z") .workplane() .pushPoints(bolt_pts) .circle(bolt_d / 2) .cutThruAll() ) cq.exporters.export(result, "flange.step")这段代码跑完,你会得到一个外径80、内径40、厚度12、8个螺栓孔均布的法兰盘STEP文件。整个过程从发起请求到拿到文件,我实测在十几秒到一分钟左右,主要取决于大模型接口的响应速度。
3.4 在FreeCAD里验证模型
拿到STEP文件不代表万事大吉,必须做一次“进CAD体检”。
打开FreeCAD,导入这个STEP文件。第一件事旋转看各方向的形状对不对;第二件事测量几个关键尺寸,验证外径、内径、孔距;第三件事检查输出单位,STEP文件默认毫米,但有些AI生成的代码可能自带英寸,进软件一看尺寸差25.4倍,那就全错了。
一个真实的坑:CadQuery导出STEP时,法兰的“草图特征”历史并不会保留到STEP里。STEP格式本质是B-rep,它只保存最终几何形状,不带特征树。所以你在FreeCAD里打开它,看到的是一个“死模型”,改不了参数,想改外径只能重新生成。这就是为什么我坚持在CadQuery代码里把参数集中在文件头,改参数就重新跑一遍代码,效果上等于参数化。
4. 常见问题与排查技巧实录
4.1 生成的CadQuery代码动不动报错
这是遇到频率最高的问题。大模型生成的CadQuery代码,语法看起来没问题,一跑就报错,而且报错信息经常很抽象。我总结了一套三步定位法:
第一步,把AI生成的代码逐行拆到Jupyter单独的cell里,从创建Workplane开始,每一步都执行并查看中间结果,定位是第几步崩的。第二步,把报错信息原样贴回给大模型,让它自己解释报错原因并修改。第三步,如果反复修改还报错,直接删掉报错那一段,换一个更基础的API自己写。比如AI总用错fillet的参数,我就干脆不用它自动生成圆角,留到CAD软件里手动补。
还有一个策略:在提示词里要求AI“不要使用CadQuery中不常见的API”。模型知道CadQuery的API,但有些方法它记混了,比如把OpenSCAD的语法套到CadQuery上。让它只用最核心的circle、extrude、cutThruAll、faces、workplane、pushPoints,出错率会下降一大截。
4.2 模型“长出来了”,但跟想象不一样
代码能跑、模型也有了,但形状和描述不一致。这种情况我遇到过好多次,总结起来主要是三个来源。
一个是坐标系问题。你的“正面”和AI理解的“正面”不是一回事。提示词里要求“从XY平面、沿Z轴正方向拉伸”能解决大部分此类问题。一个是加减法搞反,把“打孔”写成了“加圆柱”。这需要在提示词里明确说“内孔用cutThruAll切除”,而不是留给AI自由发挥。另一个是单位不一致,CadQuery默认毫米,但如果AI在生成时参考了某些英制项目代码,会把尺寸当成英寸处理,模型整体放大25.4倍。解决办法:开头就是一句“单位:毫米”。
4.3 圆角和倒角操作的处理时机问题
有一类“卷土重来”的错误,就是让AI在CadQuery代码里直接做fillet或chamfer。表面看是CAD很基础的操作,放到程序化建模里却很容易翻车。
原因在于,圆角作用于的是拓扑边(edge),模型经过多次布尔运算后,边的拓扑顺序会变化。AI生成代码时无法准确判断倒角应该作用在哪条边、哪个面上,生成的代码经常把整圈边选错,或者因为算法本身对微小面片的容差处理导致运行失败。
我的建议是:倒角、圆角这类“修饰性特征”先不放代码里,等模型主体生成完毕,再进FreeCAD手工补上。这不是偷懒,而是在当前技术条件下最稳的路径。真要让AI做,就得把提示词写成“只给外圈顶部边缘做1mm倒角,代码中先用tag标注目标边缘”,但即便这样,成功率和手工补的效率差距也不大。
4.4 从需求语言到建模参数的对齐
这个坑比较隐性:你提出“法兰盘”,AI可能生成一个标准GB法兰,而下料时你需要的只是一个圆形板加几个孔,两回事。“标准法兰”和“自定义法兰底座”是不同的东西。
我现在会在提示词里加一句“不要试图生成国标或ISO标准件,按我给的尺寸直接构造”。这样AI就不会自作主张去参考标准件库,导致出来一个和需求尺寸对不上的模型。反过来,如果你真的需要标准件,应该去专门的零件库下载,而不是让AI画。
5. 从demo到能用:text-to-cad的现实边界
5.1 现在能拿来干活的场景
text-to-cad目前的甜区,集中在中低复杂度的“机加工件”和“3D打印件”上。法兰盘、轴承座、盖板、支架、卡扣、传感器安装座这类零件,结构规则、特征清晰、参数明确,正是AI最擅长处理的类型。
我常用的一个流程:用text-to-cad生成初版模型,导出STEP,进FreeCAD检查,然后交给机加工厂打样。对比传统方式,省掉的是“从一张手绘草图到第一版三维模型”的那段时间。尤其是接到需求方随手发的“照着这个画一个”的活,直接把描述扔给AI,出来的第一版经常比我自己凭印象画的还要快。
3D打印场景更合适,因为打印件对特征历史要求低,Cura、PrusaSlicer直接吃STL,而CadQuery可以方便地导出STL:
cq.exporters.export(result, "flange.stl", tolerance=0.1, angularTolerance=0.1)5.2 不能指望的场景
有几个方向,AI目前完全顶不上。一类是复杂曲面设计,比如汽车覆盖件、手柄的人体工学曲面,这类设计需要的是美学判断和连续曲率控制,文本描述起来都困难,就别提生成了。一类是多零件装配体,几十个零件互相配合、公差分析、运动仿真,text-to-cad单模型都搞不定,更别说整机。还有一类是带有大量工程约束的任务,比如同时满足冲压工艺要求、成本控制、结构强度,这些约束很难在自然语言里表达完整。
5.3 给团队的落地建议
如果你打算在团队里引入text-to-cad,我建议从最不起眼的小零件开始验证,先跑通“文本→代码→模型→审图”这条链路,再逐步扩大应用范围。
建立一套内部的提示词模板库,把常用零件的描述模板沉淀下来。同一个模板在不同项目里复用,准确率会越来越高,因为你可以把每次出问题的修正经验反馈到模板里。另外模型生成的代码一定要纳入版本管理,不要只存最终STEP文件,代码才是参数化资产。哪天需求方说“孔从8个改成10个”,你改一行代码重新运行,比在CAD软件里点半天要快得多。
写在最后的小经验
跑了这套流程小半年,我最大的感受是:text-to-cad不是来取代设计师的,它更像一个随叫随到、从来不发脾气的画图学徒。你告诉它尺寸、告诉它约束、告诉它哪些地方要倒角,它把重复劳动干完,你把关和兜底。
我个人现在的工作习惯是:凡是要一天内出第一版方案的活,先让text-to-cad跑一遍;凡是涉及到外观评审、复杂配合、工艺验证的模型,老老实实自己上手。两边配合着来,效率提升是实打实的。如果你也想上手试,我的建议就是开头那句——从法兰盘开始,规格写成“外径80、内径40、厚12、8孔均布”,跑通一遍,你就能摸清这套东西的脾气了。