text-to-cad:自然语言直出CAD模型的技术原理与工程实践
上周团队接了个急活,对方只给了一段文字描述:“一个带法兰的圆柱底座,法兰外径40、厚5,主体直径20、高50,中心一个直径8的通孔,表面要倒角。”搁以前,这种需求怎么也得建模软件里比划个十几分钟,先把草图画了,再拉伸、打孔、倒角,一步步来。但这次不一样,我把这段话直接扔进了text-to-cad的工具链里,几分钟后拿到一个可编辑的STEP文件,尺寸公差还是对的。这个事让我意识到,自然语言直出CAD模型已经不是PPT上的概念了,而是真能拿来干活的流程。
text-to-cad,说白了就是让AI理解你对零件的口语化描述,然后替你完成从“读需求”到“建模型”的整套动作。它解决的痛感非常明确:工程沟通过程中,80%的时间浪费在“把脑子里的形状转成软件里的参数”这件事上。理解这个技术能做什么、怎么落地、有哪些坑,是这篇文章想聊透的。不管你是机械工程师、产品结构设计,还是做自动化出图平台的开发者,下面这些内容都有点参考价值。
1. text-to-cad到底在解决什么问题
1.1 建模过程的“最后一公里”瓶颈
传统CAD建模有个很反直觉的特点:绝大多数时间不是花在“设计”上,而是花在“操作”上。设计师脑子里其实已经有了零件的拓扑结构、尺寸关系、配合要求,但把这些信息输入到软件里,得经过草图、约束、特征树、布尔运算这一长串流程。我见过不少熟手,建一个中等复杂度的支架,至少三分之一的时间耗在重复性操作上,比如反复画对称的孔位、反复设拉伸深度。
text-to-cad要干掉的就是这段“翻译成本”。它把建模过程从“手动操作指令序列”变成“描述意图”,再由模型自动映射成特征序列。这里的核心观点是:自然语言描述虽然信息密度低,但信息覆盖面广。一句话里的“法兰”“通孔”“倒角”这些词,背后都对应着CAD系统里的具体特征操作,AI要做的就是把这些词汇还原成完整的建模步骤。
1.2 三类主流技术路径
目前市面上做text-to-cad的方案很多,但归纳下来就是三条技术路线,各有取舍。
第一类是代码生成路径,也是我这次实测用的方案。它让大语言模型直接输出OpenSCAD、CadQuery、FreeCAD Python脚本这类程序化建模代码,再由脚本解析器生成实体模型。好处是结果完全参数化,改一个尺寸就等于改代码里的变量,适合需要反复迭代的场景。缺点是生成的代码质量高度依赖提示词设计,如果没给够约束条件,模型会把圆的直径和半径搞混。
第二类是端到端生成路径,比如学术界比较关注的Text2CAD框架,用Zoo这类大规模数据集训练深度网络,让模型直接输出B-Rep边界表示或CSG构造树。这个路子上限很高,因为不需要中间代码,直接从语义到几何,但对算力要求高,而且生成结果的局部精度不稳定。我见过不少demo展示时很惊艳,一拉到工程实际里就露馅。
第三类是信息抽取加参数化模板路径,更接近传统NLP的做法:先从文本里抽取出关键实体(法兰、孔、轴)和关系(直径、深度、同轴),再映射到预设的参数化模板库。这个方案工程稳定性最好,但泛化能力差,超出模板覆盖范围的描述就抓瞎。
三条路线不是互斥的,实际产品里经常混着用,比如先用LLM抽参数,再用模板生成,最后用代码补细节。理解这些路径,对你选型会有直接帮助。
2. 底层技术原理:为什么这件事能做成
2.1 语言模型和几何建模的“翻译层”
text-to-cad能落地,不是凭空冒出来的,底层其实踩在两个成熟技术肩上:一个是代码大模型,一个是程序化建模引擎。代码大模型本身就有很强的“意图到代码”能力,而OpenSCAD这类工具的脚本本身就是一种“可执行的建模语言”,这正好成了两者之间的翻译层。
我来打个比方。语言模型就像一个会读图的老钳工,你跟他说“做一个带法兰的圆柱”,他心里立刻浮现出那个零件的立体形态、相对位置和加工顺序,然后他拿起一把叫OpenSCAD的“工具”把心里想的雕刻出来。关键是,这个过程不是黑盒,每一步生成的代码都可以审查、修改、重放,所以容错率远高于端到端生成。而且代码本身就是设计历史,改一个参数整条特征链会跟着联动,这在工程里是刚需。
2.2 数据从哪儿来:Zoo数据集和合成数据
AI要理解“法兰”“通孔”这类专业名词,背后得有大量标注数据喂着。学术界公开的Zoo数据集(MIT等机构维护的Text2CAD数据集)是个很好的观察窗口:它从在线CAD模型库收集了十几万个零件模型,每个模型都配了对应的自然语言描述,描述里包含了形状、尺寸、特征和空间关系。这个数据集的思路特别朴素,但特别管用——与其让人去给老模型写标签,不如直接在用户分享模型的过程中自动提取描述,再结合程序化建模脚本逆向生成语言注释。
不过真实项目里光靠公开数据集远远不够,一个靠谱的做法是用合成数据补量。你可以自动生成一批模板模型,随机变化尺寸和特征,再用脚本把对应参数拼成文本描述,这样一天就能造出成千上万条训练样本。我在实测过程中也尝试过用这种方法配合微调一个开源模型,效果比直接拿通用LLM硬生成稳定不少,尤其在尺寸精度上。
2.3 关键瓶颈:从“形状对”到“参数对”
很多人用text-to-cad生成的第一个模型都会感叹“卧槽,形状出来了”,但一测尺寸就傻眼。这里的核心瓶颈在于:语言模型擅长理解“形状关系”,但不擅长精确计算“数值”。比如它知道“直径20的孔”应该是一个圆柱特征,但这个特征的直径值可能直接沿用了训练数据里的常见值,而不是严格等于20。
工程上缓解这个问题的思路有几个:一是在提示词里强制要求输出可参数化变量,把尺寸单独声明成变量而不是字面量;二是加一个后处理步骤,用一个解析器把生成代码里的尺寸参数全部抽出来核对约束;三是更彻底一些,将文本中的数值和几何特征直接绑定,生成代码时不是模型说了算,而是用外部参数直接代入。这里需要明白一个底层事实:text-to-cad的难点不在生成几何形状,而在维持几何和参数之间的强一致关系。任何一个尺寸错了,整个模型就是废品。
3. 实操:把一句话变成可编辑的CAD文件
3.1 环境准备与工具链选型
先说清楚我这套实测用的工具链,全部开源可复现。核心是OpenSCAD加一个支持代码生成的LLM,本地推理用Ollama跑开源模型,也可以直接调云端API。OpenSCAD是个轻量级程序化建模工具,用文本代码定义几何体,特别适合做text-to-cad的“落点”,因为它的语法足够简单,语言模型不容易产生语法错误。
如果你更习惯用传统CAD,可以考虑FreeCAD加它的Python API,同样可以通过代码驱动建模,好处是生成的是原生FreeCAD文档,后续能用图形界面编辑。再高级一点的用CadQuery,它的代码写起来更接近工程语义,比如box()、hole()这种直白的方法,对LLM来说反而更好生成。
我的建议是:初学者先用OpenSCAD跑通流程,等摸透了再做FreeCAD迁移。步骤是先把OpenSCAD装好,确认命令行能跑通一个最简单的立方体:
openscad -o test.stl -D 'size=10' test.scad然后准备一个本地大模型环境(我用的是qwen2.5-coder:7b这个量级的就能干活),或者直接申请一个云端API的key。剩下就是写提示词了。
3.2 提示词模板是成败的关键
实测下来,text-to-cad的成与败,一半以上取决于提示词怎么设计。直接扔一句“做一个带法兰的圆柱”给大模型,它大概率会给你一个徒有其表但尺寸混乱的东西。一段好用的提示词模板长这样:
你是一个资深的机械设计工程师。 请根据以下零件描述,生成OpenSCAD代码。 描述:{用户输入} 要求: 1. 将所有尺寸参数定义为变量,并添加注释; 2. 使用difference()布尔运算处理孔和槽; 3. 模型放置在原点,中心对称优先; 4. 单位统一为毫米; 5. 只输出代码,不需要解释。这个模板的核心思路是约束模型的行为边界。你会发现我特别强调了“变量化参数”和“单位毫米”,这两点能极大避免尺寸紊乱的问题。对大模型来说,一旦它把尺寸写成裸数字,你后续想调参就麻烦大了;而一旦它按变量输出,你拿到代码后可以直接改变量值重新渲染,这个体验跟传统CAD改特征尺寸一样丝滑。
3.3 核心案例:带法兰圆柱底座的完整实现
我就拿开头那个“带法兰的圆柱底座”作为例子,实际走一遍从文本到STEP文件的完整流程。
用户输入文本是这样的:
一个带法兰的圆柱底座,法兰外径40毫米,厚度5毫米, 主体直径20毫米,高度50毫米,中心有直径8毫米的通孔, 法兰上均布4个直径6毫米的安装孔,孔位在直径32毫米的圆周上。把这段提示词发出去,经过一点小修整,我拿到了一份能直接运行的OpenSCAD代码。核心部分是这个样子:
// 参数定义 flange_d = 40; // 法兰外径 flange_h = 5; // 法兰厚度 body_d = 20; // 主体直径 body_h = 50; // 主体高度 hole_d = 8; // 中心通孔直径 bolt_d = 6; // 安装孔直径 bolt_circle = 32; // 安装孔分布圆直径 module flange_base() { difference() { union() { cylinder(d=flange_d, h=flange_h); translate([0, 0, flange_h]) cylinder(d=body_d, h=body_h); } // 中心通孔 cylinder(d=hole_d, h=flange_h + body_h + 1, center=true); // 4个安装孔 for (i = [0:3]) { rotate([0, 0, i * 90]) translate([bolt_circle / 2, 0, -0.5]) cylinder(d=bolt_d, h=flange_h + 1); } } } flange_base();这里面有几个关键点值得展开说一下。首先是建模顺序,我用union()把法兰和主体合并成一个实体,再统一用difference()去减掉中心孔和安装孔,这是典型的“先加后减”思路,符合实际加工逻辑,也能避免布尔运算时出现自相交问题。
其次是安装孔的位置算法。四个孔均布在直径32的圆周上,我把分布圆半径当变量,然后拿循环加旋转角度逐一把孔位算出来,这就是程序化建模的威力。如果用手工建模,这四个孔的位置你得一个个算坐标手动点上去,而在代码里只是一行循环的事。
运行这段代码生成STL文件,命令非常简单:
openscad -o flange_base.stl flange_base.scadSTL拿来做3D打印没有问题,但工程上更需要可编辑的实体模型。OpenSCAD本身不直接导出STEP,我的办法是先把模型导入FreeCAD,再用它的Part.export()接口导出STEP。或者更直接一点,我在FreeCAD里用Python脚本复现了同样的建模逻辑,这样生成的直接就是FreeCAD原生文档。
下面是我实测过的FreeCAD Python脚本片段,逻辑和OpenSCAD版本完全对应:
import FreeCAD as App import Part doc = App.newDocument("flange_base") flange = Part.makeCylinder(20, 5) # 法兰,半径20高5 body = Part.makeCylinder(10, 50) # 主体,半径10高50 body.translate(App.Vector(0, 0, 5)) # 移动主体到法兰上方 merged = flange.fuse(body) # 合并 center_hole = Part.makeCylinder(4, 60) # 中心孔,半径4 center_hole.translate(App.Vector(0, 0, -5)) result = merged.cut(center_hole) # 布尔减去中心孔 for i in range(4): # 四个安装孔 import math ang = i * math.pi / 2 x = 16 * math.cos(ang) y = 16 * math.sin(ang) bolt_hole = Part.makeCylinder(3, 6) bolt_hole.translate(App.Vector(x, y, -1)) result = result.cut(bolt_hole) Part.export([result], "/path/to/flange_base.step")这里给新手的提醒是:半径和直径的换算特别容易错。LLM生成的代码里经常出现直径数值直接填进半径参数的情况,我这几次测试里至少遇到两回。拿到生成代码后要做的第一件事不是急着渲染,而是花三十秒扫一遍所有参数定义,看看有没有把直径当半径用,反过来也一样。这个习惯能帮你省下大量排查时间。
3.4 从零件描述到装配体的扩展思路
单零件跑通之后,很自然会想往更复杂的方向走,比如装配体。text-to-cad在装配体层面目前还比较吃力,因为多零件之间的配合关系(同轴、贴合、间距)很难从一句话里完整还原。我的尝试是分两步走:第一步让模型分别生成各个零件的代码,第二步再用一个装配脚本把零件按约束关系组装起来。比如刚才那个底座,如果要配一个压盖,压盖的描述是“直径40高10,中心孔8,均布4个安装孔”,两个零件共用中心孔轴线和安装孔位,装配关系其实就是“同轴加贴合”。
这个思路在OpenSCAD里可以很容易实现,把两个模块import到同一个文件里,用translate和rotate控制位置。但如果零件数是几十个起步,还是老老实实用专业CAD的装配功能吧。我的经验是,text-to-cad现阶段更适合做零件级快速出样和方案对比,装配体和运动仿真这些活还不能交给它。
4. 踩坑实录与常见问题速查
4.1 尺寸精确度失控
这是我遇到最多的问题,没有之一。语言模型对精确数字的“记忆力”远不如对形状关系那么强。举一个实际例子:描述里写“法兰外径40”,生成的代码里可能就变成了cylinder(d=45, h=5),数值悄悄偏移了5毫米。原因在于大模型在概率生成过程中,数字token的采样本身就存在不确定性,尤其是那些在训练数据里出现频率不高的奇数尺寸。
我的解决方案是分层校验:先读取提示词里的所有数值,形成一张“期望尺寸表”,再解析生成的OpenSCAD代码,提取出所有的变量赋值,逐一比对。这个过程我写了一个几十行的小脚本,跑一次只要十几秒,但能拦住一半以上的返工。如果你不想写脚本,至少在检查代码时留意一下那些非整数的圆角值和非对称的尺寸。
另外还有一个技巧,在提示词里明确要求“所有尺寸只能使用用户给定的数值,禁止推断或近似”,这能显著减少模型的擅自发挥。我测试了几次,加了这句话之后尺寸偏移发生率下降了一半还多。
4.2 语言歧义与特征遗漏
用户的一句话在工程上经常是不完备的。比如只说“中心有通孔”,没说孔贯穿多深、孔径多少,这时候模型只能猜。猜对了是运气,猜错了是常态。另一个典型问题就是特征遗漏,描述里说了“底座侧面开一个U形槽”,但模型生成的代码里压根没有这个槽。
应对思路是要在工程语言和自然语言之间做一个“结构化补充”。我通常会在提示词里要求模型在必要时用合理工程默认值补全信息,并在注释中标注哪些是用户给定的、哪些是推断的。比如孔深如果没有指定,可以默认贯穿整个零件,但需要在代码注释里写明“默认贯穿”。这种做法相当于把不确定因素显式暴露出来,而不是让模型闷头乱猜。
4.3 编辑能力与拓扑稳定性
text-to-cad生成的结果,形状可能对,但几何内核稳定性是另一回事。我遇到过不止一次的情况是:模型渲染出来看着正常,但一旦导入到Fusion 360或SolidWorks里,某些面就是缝合失败,或者布尔运算一执行就报错。这个问题在代码生成路径里往往出在曲面相交、零厚度面、退化几何这些细节上。
质量好的程序化建模代码,通常会把倒角和圆角放到布尔运算之后,并且在最后加一个intersection或hull来做几何清理。还有一种常见问题就是单位不一致,比如模型里混用了英寸和毫米,在3D打印切片时尺寸差一大截。所以每次拿到新生成的文件,第一步就是核验单位设置,这是基础的不能再基础的操作。
4.4 问题速查表
| 症状 | 可能原因 | 解决办法 |
|---|---|---|
| 渲染失败 | 生成代码存在语法错误 | 将错误信息反馈给模型,让它自我修复 |
| 尺寸偏移 | 模型自由推断或直径半径混淆 | 核对变量赋值,强制提示词约束 |
| 特征遗漏 | 描述歧义、信息不足 | 结构化描述模板,补充默认值 |
| 导入STEP报错 | 布尔运算产生退化几何 | 在代码中增加倒角/圆角清理步骤 |
| 单位错误 | 模型混用公制英制 | 代码中统一显式使用mm |
最后还想多说一个实用性很强的点:把text-to-cad的输出当草稿,而不是终稿。即便代码生成的模型看起来完全符合描述,也要拿到CAD软件里检查几何干涉、壁厚和拔模角这些加工要素。文字描述里很少会提“出模角度”和“最小壁厚”,而这两样对注塑件来说恰恰是致命的。把text-to-cad定位成“需求到草图的加速器”,是最合理的使用预期。
5. 工具生态与选型建议
5.1 开源方案横向对比
选工具这件事,我自己的体会是别迷信某一个,要根据你手里的任务类型来。如果只是快速验证“这个描述能不能建模”,OpenSCAD加LLM是最轻的组合,五分钟就能跑通全流程。如果你需要的是原生CAD文档、后续要在FreeCAD里继续精修,那就直接上FreeCAD Python API,配合一个代码生成模型,效果也是不错的。
CadQuery算是一个中间选项,它的代码风格介于OpenSCAD和传统CAD之间,既有程序化的灵活性,又有工程语义的直观性。比如用CadQuery做“带法兰圆柱底座”这个案例,代码可以直接写成:
import cadquery as cq result = ( cq.Workplane("XY") .circle(20).extrude(5) # 法兰 .faces(">Z").circle(10).extrude(50) # 主体 .faces(">Z").hole(8) # 中心通孔 ) cq.exporters.export(result, "flange_base.step")这个风格的代码对LLM来说特别友好,几乎一眼就能读懂每一步在干什么,而生成可用的概率也远高于手写复杂几何内核的脚本。
5.2 商业软件与云端服务趋势
开源的方案虽然灵活,但商业CAD厂商也确实在往text-to-cad方向发力。一些主流CAD软件已经在内部集成了AI辅助建模的功能,你输入一段描述,系统自动生成特征树,这种体验比开源路径更顺滑,因为生成的模型直接就是原生格式,不需要中转。
云端的SaaS工具也在做类似的事情,它们通常把“文本建模”封装成一个API接口,开发者可以把它嵌到自己的设计流程里。这种方式对非机械背景的产品经理尤其友好,他们不需要学CAD,只要把需求文档里的描述复制进去,就能拿到一个可以看的3D模型,方便评审和沟通。
但我个人对商业方案有个保留态度:生成结果的“可控性”依然不足。大多数商业工具都允许你调整生成的参数,但调整的自由度远不如直接改代码来得大。如果你是一个需要在细节上反复打磨的设计师,代码路径还是更有底气一点。
5.3 我的选型心得
说句掏心窝的话,我现在的日常工作流里,text-to-cad不是用来替代CAD的,而是用来替代“需求沟通会议”的。以前拿到一段文字需求,我得先心里建模,再跟需求方来回确认尺寸,一个上午就没了。现在我把文字需求丢给模型,生成第一版草样,再拿着三维模型去跟需求方对,沟通效率直接翻倍。
针对不同角色,我给的建议也完全不同:如果你是结构工程师,可以先把OpenSCAD路径吃透,成本最低,见效最快;如果你是独立开发者做设计自动化工具,那CadQuery加一个自训练的尺寸校正模块会更靠谱;如果你只是产品经理想快速要一个评审模型,那直接用商业软件里的AI辅助功能就够了,别折腾开源环境。
工具会变,模型会换,但“从意图到几何”这条链路是越来越通的。早一天把这条链路纳入自己的工作流,就早一天从重复劳动里解放出来。
最后再分享一个我踩了三次坑才总结出来的小技巧:所有text-to-cad的提示词里,最后一定要加一句“请你逐步解释你的建模思路”。加了这句话之后,模型会把生成代码的逻辑先拆解一遍,你会发现它能自己发现一些前后矛盾的地方,比如孔径和螺栓直径不匹配、孔位和法兰外径干涉,进而在生成代码时主动修正,这段解释比任何后处理脚本都管用。不信你试试,从此再也不必对着一个“形状正确但尺寸离谱”的模型干瞪眼了。