做了一年多的“用自然语言直接生成CAD模型”这件事,我最大的感受是:text-to-cad这玩意儿,终于从论文里的demo变得能落地了。以前你跟CAD说“帮我画一个带四个安装孔的支架”,它只会弹个语法错误;现在你对着一条提示词,能直接拿到一个可编辑、可制造、能导出STEP的实体模型。这个变化不是某个单点技术的突破,而是大语言模型、几何内核、参数化建模几股力量凑到一起的结果。
这篇文章不打算写那种“教你三分钟用AI取代工程师”的鸡汤,我想从一个实际做过很多次生成、踩过无数坑的人的角度,把text-to-cad的完整链路拆开给你看:它背后是什么原理、有哪些实现方式、怎么搭一套能用的流程、以及那些真正要命的问题怎么避开。适合正在搞AI辅助设计、想接生成式建模的开发者,也适合想用工具提升效率的产品和结构工程师。不管你是用开源方案自己撸,还是调用现成工具,这篇文章应该能帮你省掉不少试错成本。
1. 先搞清楚:text-to-cad到底在生成什么
很多人一听“text-to-cad”,第一反应是“这不就是用AI画图吗”。这是最大的误解。文生图生成的是像素矩阵,而CAD模型需要的是精确的几何信息:哪条边是圆弧、哪两个面平行、哪个孔是通孔还是盲孔、直径公差是多少。像素错了无所谓,几何错了,零件就装不上,更没法加工。
1.1 从描述到模型的两种技术路线
我梳理了一下目前主流方案,基本可以分成两条路线:脚本生成路线和端到端生成路线。
脚本生成路线的思路是:让大语言模型理解自然语言,然后把设计意图翻译成一段参数化建模脚本,再交给CAD内核执行。常用载体包括CadQuery、OpenSCAD、FreeCAD的Python API。这条路线的最大优点是:生成的模型完全可编辑、可参数化,因为脚本本身就是特征历史的另一种表达形式。你后来想改某个孔的直径,改脚本里的参数重新跑一遍就行。
端到端生成路线则是训练一个深度学习模型,输入文本,直接输出点云、体素或者BREP边界表示。这条路线的优点是一步到位,短平快。但问题是:输出结果往往是“不可编辑的实体”,像是一块捏好的泥巴,没有特征树、没有参数、没有历史记录。在制造业的工作流里,这种模型基本只能当参考,没法直接进PDM系统做变更管理。
我自己在实际项目里几乎只走脚本生成路线,原因后面会展开说,但核心就一句话:CAD的核心价值在于“可复用”和“可修改”,而不是“一次性画出来”。
| 对比维度 | 脚本生成路线 | 端到端生成路线 |
|---|---|---|
| 代表实现 | LLM + CadQuery/OpenSCAD | 专用生成网络输出BREP/体素 |
| 可编辑性 | 高,参数任意改 | 低,生成即固定 |
| 可制造性 | 高,遵守建模规则 | 一般,可能产生破面 |
| 对算力要求 | 普通推理即可 | 训练和推理成本高 |
| 上手门槛 | 需要懂一点代码 | 需要炼丹,门槛更高 |
1.2 一个核心认知:你要生成的是“特征”,不是“网格”
我刚入坑时犯过一个错误:拿到一个text-to-cad生成的模型,兴奋地点开一看,发现它导出的是STL网格。网格对3D打印够用,但对真正的机械设计是完全不够的。真正的CAD模型,内核里记的是“先拉伸一个矩形,再在顶面上打两个直径5mm的通孔,再倒一个R2的圆角”这种特征历史,而不是“一堆三角形拼成的形状”。
所以,在评估任何text-to-cad工具时,我第一个问题永远是:“你输出的是B-rep实体,还是Mesh网格?”如果答案是后者,基本可以排除在工程场景之外。现代的CadQuery和OpenSCAD都属于前者,它们底层的几何内核(分别是OCCT和CGAL)能生成真正带拓扑信息的实体模型。这个差别,到了下游做有限元分析、开模具、做装配干涉检查的时候,会被放大成一个天一个地。
2. 我把text-to-cad拆成了四个关键环节
如果你要自己搭一套text-to-cad流程,或者要评估市面上某个工具靠不靠谱,我建议把它拆成四个环节来看:自然语言理解、设计意图到CAD指令、几何内核执行、可制造性校验。这四个环节每一环都会掉链子,而且掉链子的方式完全不同。
2.1 自然语言到设计意图:缺的不是理解,是约束提取
大语言模型理解自然语言这件事,现阶段已经不是瓶颈了。真正麻烦的是:用户说的一句话里,往往参数不全、几何关系不明确、术语混乱。比如你说“给我一个带孔的板子”,模型得自己决定板子多厚、多大、孔开在哪、开多大、是通孔还是沉头孔。
我试过几种处理方法,最有效的是让模型输出结构化的JSON中间表示,而不是直接输出代码。也就是说,让LLM先把自然语言翻译成一套明确的“设计意图描述”,然后再用一个确定性规则把它映射成CAD脚本。这样做的优势是:出错了你能知道是理解错还是生成错,不用对着堆栈瞎猜。
举个我实际用的例子。对于“一个80毫米宽、60毫米高的L型支架,厚度3毫米,底部有两个直径6毫米的安装孔”,我让模型先输出这样的JSON:
{ "part_type": "l_bracket", "parameters": { "width": 80, "height": 60, "thickness": 3, "base_depth": 40, "mounting_holes": [ {"diameter": 6, "x_offset": -15, "y_offset": -20}, {"diameter": 6, "x_offset": 15, "y_offset": -20} ] } }这一步非常关键,它等于把模糊的中文描述格式化成CAD软件能接受的数据结构。
2.2 设计意图到CAD指令:模板和自由生成的博弈
有了结构化JSON之后,接下来就是把参数填进模板脚本里。这个环节我踩过的坑最多。一开始我让LLM直接从零生成CadQuery代码,结果经常出现:用了一个不存在的API、坐标系搞反、单位搞错、甚至逻辑上先布尔减再布尔加导致把特征削没了。
后来我改成预置一套经过验证的建模模板,LLM只需要负责从模板库里选择并填参数。这套做法稳定性提升非常明显。模板的作用相当于把LLM的搜索空间缩小到一个能保证正确的范围内,剩下的只是一些简单的参数映射。只有当用户需求超出模板范围时,才让LLM尝试扩展,但扩展的代码必须经过自动校验。
典型的校验手段包括:语法检查、引用检查、用样本参数试运行看是否会抛异常、检查几何结果是否满足预设约束(比如体积大于零、面数合理、最小壁厚大于某阈值)。
2.3 几何内核执行:一步错,步步错
这个环节普通用户感觉不到它的存在,但它恰恰是text-to-cad稳定性的命门。几何内核负责完成拉伸、旋转、布尔并集差集、倒角圆角这些操作。拿CadQuery来说,它底层是Open CASCADE,这是一个有几十年历史的C++几何库,功能强大,但API设计也比较“古典”,很多行为需要经验才能预测。
举例:两个实体做布尔差集,用来减去的那个工具实体如果刚好和主体共面,某些内核会判定为无法执行,报错“No shape found”。这个情况在用户对壁厚没概念时很常见——他说“掏个槽”,槽深刚好等于板厚,工具体就跟主体底面完全重合了。
我的经验是:在生成脚本里加一层隐性约束——所有操作参数都要留安全余量,或者在后处理里做“几何合理性检查”。比如布尔运算前先查一下两个实体是否只共享边界而不共享体积,是的话就自动给偏移一个微小距离,避免共面的数值问题。这类问题不踩几次真的不知道坑有多深。
2.4 可制造性校验:AI负责生成,社会负责现实
最后一个环节是制造相关,很多人忽略,我建议任何人都别省。要知道“能画出来”和“能加工出来”之间,还隔着好几座大山。你让LLM生成一个带悬伸结构的零件,在3D打印上可能还行,但如果你要用数控铣削加工,这个设计就是废铁。
我的做法是在生成流程末尾接一个自动校验层,检查项目包括:
- 最小壁厚是否满足材料和工艺要求(注塑至少0.8mm,CNC至少1.5mm,具体看材料)
- 是否存在封闭内腔,导致无法排屑或模具无法脱模
- 锐角内角是否过小,导致应力集中或刀具无法进入
- 孔径是否小于推荐的最小加工孔径限制
这套校验其实不需要写在CAD脚本里,它可以是独立的一段Python脚本,在模型导出前跑一遍,不合格就直接拦截返工。这也避免了“生成100个,拿到工厂80个不能用”的窘境。
3. 实操:从零搭一套能用的text-to-cad流程
前面聊了不少原理,这块我给你一套我能跑通的实现方案。没有依赖某个特定付费平台,你只需要一个能调用大语言模型的环境,以及Python库就够了。
3.1 环境准备与工具选型
我目前的推荐组合是:
- 大语言模型:可以选用商业API或者本地开源模型。项目里如果涉及保密设计,建议本地部署开源模型;如果追求理解能力,商业API效果更好。我只把脱敏的通用需求发给外部API,涉密任务走本地。
- 参数化CAD库:CadQuery(或者更现代的build123d)
- 结构化输出:用Pydantic定义JSON格式,强制模型输出符合Schema的数据。
- 校验层:自定义Python脚本,跑完几何后检查体积、干涉、壁厚等指标。
环境安装没什么特别的,Python 3.10以上,pip install cadquery即可。如果你要用build123d,它是CadQuery的进化版,API更友好,但社区资源少一些,二选一即可。
3.2 提示词与输入规范化
我一开始直接让用户把需求敲进去,然后丢给LLM。结果惨不忍睹。用户描述里经常带语气词、默认值、口语化的模糊单位:“差不多这么大的”“厚一点的”“孔别太大啊”。这些表述在工程师之间是靠默契理解的,LLM瞎猜的准确率达不到工程要求。
后来我加了一个需求澄清前置环节。系统先根据用户输入,提取参数,如果发现关键参数缺失,会反问用户。比如“如果只告诉我‘带孔的板子’,我会默认厚度2mm,长度80mm,宽度50mm,孔径5mm,请确认,或者提供修正参数”。这一步交互看着简单,但对于提升生成成功率是质的改变。
如果场景不允许交互(比如批量任务),我就用默认值策略,但必须在生成结果里明确标注哪些参数是采用默认值的。这样做的好处是,工程师拿到的模型自带参数假设说明,不用自己去猜AI干了什么。
3.3 核心生成代码示例:一个L型支架的实战
下面这段代码是简化后的流程核心,我用它跑了无数次。它做的是:接收用户自然语言,调用模型提取JSON,然后填充CadQuery模板,生成STEP文件。
import cadquery as cq import json from pydantic import BaseModel # 定义结构化输出Schema class BracketParams(BaseModel): width: float = 80.0 height: float = 60.0 thickness: float = 3.0 base_depth: float = 40.0 hole_diameter: float = 6.0 hole_x_spacing: float = 30.0 # 假设这已经由LLM从用户输入提取出来 params = BracketParams() # 生成L型支架 vertical = cq.Workplane("XY").box( params.width, params.thickness, params.height, centered=(True, True, False) ) base = cq.Workplane("XY").box( params.width, params.base_depth, params.thickness, centered=(True, True, False) ).translate((0, 0, params.thickness / 2)) result = vertical.union(base) # 在底板上开安装孔 result = ( result.faces(">Z") .workplane() .pushPoints([ (-params.hole_x_spacing / 2, -15), (params.hole_x_spacing / 2, -15) ]) .hole(params.hole_diameter) ) # 导出STEP和STL cq.exporters.export(result, "output/bracket.step") cq.exporters.export(result, "output/bracket.stl")有几个细节值得展开说。第一,box的centered参数我特意设成了(True, True, False),意思是让x、y方向居中,z方向放在原点平面以上。这是为了后续用faces(">Z")选择顶面时有个明确的坐标参考,否则容易选到意想不到的面。第二,pushPoints传的是打孔点的坐标列表,这里用了相对位置的写法,便于以后改成任意布局。第三,translate((0, 0, params.thickness / 2))是为了把底板抬起来,使它的顶面恰好和竖板的底面贴平。
这段代码不是我拍脑袋写的,它是迭代了很多次之后稳定下来的模板。之前我犯过一个低级错误:把竖板和底板都用centered=(True, True, True),然后靠坐标偏移拼到一起。结果是两块板在z方向的中心对齐,L型的轮廓变得很别扭。这些几何细节,LLM自己是很难一次生成的,必须靠模板固化下来。
3.4 让输出更可控:规则注入与多轮修正
用模板+结构化输出的方式,能把成功率拉高,但依然会有用户不按套路出牌。比如他说“在竖板上加一个长圆孔”,而我的模板里只有圆孔。这时候LLM如果硬填参数就会出错。
我应对的办法是:检测到用户需求超出模板能力时,切换到自由代码生成模式,同时把几何校验层调到最严。让LLM生成一段全新的CadQuery代码,然后我在沙箱里运行,看它的输出是否满足基本约束。如果失败,把错误信息回到LLM,让它自己修。这个“生成-运行-报错-修复”的循环,通常跑两三轮就能得到可用的结果。
这个过程有点像和一个有经验但偶尔粗心的实习生合作:你得给他清晰的任务边界、规则清单,并在他做完之后检查结果,而不是甩一句“你去把它搞定”就完事了。
4. 在实际业务里怎么用text-to-cad,而不是玩票
讲了这么多技术细节,如果这玩意儿只能拿来生成几个玩具模型,那没什么意思。我这里说几个我实际验证过有长期价值的使用场景。
4.1 三个高价值场景:概念造型、标准件库批量生成、非专业人员定制
第一个场景是前期的概念造型阶段。产品经理或者工业设计师在头脑风暴时往往会提很多模糊的想法:“能不能做一个底座,能放两个电池仓和一个充电模块?”过去工程师得手动搭个糙模型来验证空间布局,现在可以直接用text-to-cad生成几个方案版,快速比对尺寸和布局。虽然最终的详细设计工程师还得重做,但早期沟通成本省了一大截。
第二个场景是标准件库批量生成。很多公司的外购件、标准件库里,同一类零件有不同的尺寸规格,以前得靠人工建一堆类似模型。现在可以写一批参数化模板,然后用一个简单的LLM脚本,让用户输入自然语言“生成M6×20的内六角螺栓,头部直径10mm”,直接得到对应的STEP文件。批量生成几十个变体也就是几分钟的事。
第三个场景更野,是让非设计人员也能做定制。我认识的一个做非标设备的老板,给终端客户提供了一套内部系统,客户只需要输入自己的安装尺寸和负载要求,系统内部调用text-to-cad流程,自动生成定制支架模型和报价。这种玩法在过去至少需要一个CAD二次开发工程师,现在一个人能做一条线。
4.2 对接3D打印和加工的关键一步
生成模型之后,下一步往往是做原型。3D打印这条路最顺,因为STL格式直接切片就行。但这里有个我踩过的坑:CadQuery默认的STL导出三角化精度比较粗,如果你的模型是小尺寸精细件,会出现明显的棱边,打印出来表面粗糙得像狗啃。
解法是在导出前设置弦高公差。CadQuery里可以这样控制:把cq.exporters.export时的tolerance参数调小,或者先通过val().tessellate(tolerance)做高精度三角化,再保存为STL。弦高公差我一般设置在0.01mm级别,文件会变大,但打印质量能接受。
如果是CNC加工,STEP才是标准交付格式。CNC编程人员拿到STEP可以直接在CAM软件里生成刀路,不需要重新建模。
4.3 和传统CAD工作流的协作方式
很多人担心“AI生成的模型会不会打乱我们现有的设计流程”。我的经验是:把它当成一个“设计前置工具”而不是“替代工具”。生成的STEP文件进入PDM系统时,我会强制在流程里建立审核节点,要求设计负责人确认关键尺寸和制造约束,并附上生成时的提示词和参数假设。这样即使后面出了问题,也可以回溯。这个思路跟人类工程师设计的图要经历校对、审核是一个道理,只是把“快速出初稿”这个环节交了出去。
说到底,CAD从来不是“画图”这么简单,它是工程决策的记录工具。text-to-cad的价值在于加速这个记录过程的“起步阶段”,而审核和决策永远是人的工作。
5. 常见问题与避坑指南
最后这块我整理了几个高频问题,都是我自己或者团队小伙伴实际遇到过的。
5.1 生成的脚本经常编译报错怎么办?
我的回答是:别让它绕开你的模板。如果你发现模型在自由代码生成模式下频繁报错,最好的做法不是换更大的模型,而是回到模板策略。把所有能预定义的特征都做成插槽,让模型只在插槽里填数字。自由代码生成留到最后兜底,并且一定配合自动试运行校验。
还有一个容易被忽略的点:CadQuery的版本差异会带来API兼容问题。你本地跑的版本跟模型训练时见过的代码版本很可能不同。所以一旦锁定CadQuery版本后,提示词里最好带上版本信息,降低模型生成不兼容API的概率。
5.2 能生成形状,但改不了尺寸,不满足要求
这种情况多半是走的端到端生成路线,或者模型生成的是网格。解法只能是回到参数化脚本路线。如果你用的工具不提供参数暴露,那这个工具在你的工作流里就是死路。购买或者选型的时候,一定问清楚:“生成的模型有没有特征树?能不能改参数?”
5.3 结果“看起来像”,但不可制造
这是最迷惑人的坑。一个零件在屏幕上看着很完美,壁厚0.2mm,内腔封闭,锐角一堆,但它实际没法注塑、没法铣削。我的避坑方法前面讲过,就是自动校验层。这里补充一个细节:校验不能只看几何,还要把工艺约束一起检查。比如对CNC来说,铣刀半径决定了内圆角的最小半径,如果你设计了一个R1的内角而加工刀具是R3的,那这个角就清不到根。这类规则完全可以在校验脚本里写成硬约束。
5.4 提示词模糊导致结果不稳定,同一句话两次生成不一样
LLM天然有随机性,所以如果你的流程是“自然语言直接生成代码”,每次结果不同是必然的。想要稳定,只有一条路:把随机性从关键路径上搬走。具体就是我前面说的三步:先提取结构化JSON,再查表选模板,最后用确定性逻辑生成代码。这样LLM的随机性只影响JSON字段的取值,不影响代码结构和几何操作顺序。同样一句话,两次生成的模型在尺寸上有细微差异,但整体结构、特征位置、可编辑性都是确定的。
5.5 生成太慢,或者API调用太贵
如果你的场景要批量生成,逐条调用大语言模型API的延迟和成本都很可观。我的优化办法是:拆分任务,对于参数完全相同、只是数值不同的批量需求,不需要每次都调LLM,一次提取参数、批量跑CAD模板即可。只有真正的新结构才需要走完整流程。另外,对高频的“标准件变体”,可以直接做成查表,连LLM不用,环境也不会抱怨。
最后再分享两个我个人的习惯
第一,我始终把可追溯性放在第一位。每生成一个模型,我会在同一目录下保存一份JSON参数文件,里面完整记录了用户原始描述、解析出的结构化参数、哪些用了默认值、用的是什么版本的模型和模板。这个习惯在我后来追查一个问题时救过我很多次。
第二,别迷信“一键生成”。即使现阶段text-to-cad已经能跑通比较复杂的零件,我仍然会在生成结果后手动旋转查看一遍,有时候还要切成线框模式看内部结构。AI能干活,但最后签字的是你。带着这个心态用text-to-cad,它能成为你手里最顺手的工具,而不是定时炸弹。