text-to-cad 原理与工程落地:从自然语言到可编辑参数化模型
1. text-to-cad到底解决什么问题
1.1 先把“能生成3D模型”和“能生成零件”分清楚
先说个结论:text-to-cad 不是让 AI 随手吐一个三维模型出来,而是要输出能进加工、装配、仿真流程的“正经 CAD 模型”。很多第一次接触这个概念的人,以为只要对着电脑说一句“帮我画一个圆角矩形盒子”,就能得到和 SolidWorks 里一模一样可编辑的零件——这个期待是对的,但离技术现状还有一段距离。
我见过不少项目在这个点上栽跟头。团队拿一个文本生成点云或网格的开源模型,跑通了 demo,兴奋地拿去给机械工程师看,结果对方打开模型第一句话就是:“这个孔是贯通的吗?圆角能不能改 R3?壁厚均匀吗?”工程师关心的不是渲染效果,而是这个模型能不能放进加工环境、能不能改尺寸、能不能做有限元。text-to-cad 的核心价值,恰恰就藏在这些“能不能”里。
这里要区分两个概念:一个是“生成 3D 形状”,另一个是“生成 CAD 模型”。前者可以是一团点云、一个 mesh、一张深度图,只要视觉上像就行;后者必须包含参数、特征、约束、历史树。CAD 模型的本质不是形状,而是一串“制造意图”的连续记录。比如一个法兰盘,在 CAD 系统里不是一个圆柱加六个孔,而是由“拉伸基体、切除材料、阵列孔”这些特征组成的操作序列。text-to-cad 要解决的就是这个问题:把自然语言描述,转换成工程师能继续编辑的特征序列。
我常用一个类比来解释:传统建模就像口述做菜给一个厨师,厨师会按你的步骤切菜、配菜、下锅,但你要是只给“我要一道好吃的菜”,厨师只能自由发挥;而 text-to-cad 的目标,是让 AI 变成那个能听懂“少盐、多醋、不要香菜”的帮厨,而不是直接把外卖端上桌。
1.2 直接生成网格为什么难落地
市面上很多“文本转 3D”项目,比如文本生成点云、文本生成神经辐射场,其实走的是另一条路线。它们擅长生成视觉上惊艳的有机体:一只猫、一把椅子、一个角色概念。但这类结果到了 CAD 场景里几乎不可用,原因很现实。
网格模型没有工程语义。一个由几十万三角面片组成的 mesh,里面根本没有“圆柱”“通孔”“圆角”这些概念。你想把孔直径从 8mm 改成 9mm,网格模型只能整体重生成或手动雕刻,没法像参数化模型那样改一个数字。同时,网格模型的拓扑质量很难保证:经常出现破面、重叠三角形、法线翻转、非流形边。拿去切片打印,切片软件可能会直接报错;拿去 CAM 编程,刀路更是没法算。
还有精度问题。工业 CAD 的尺寸精度通常是微米级,一个机械零件如果台阶厚度差了 0.1mm,装配就可能出问题。而生成式网格模型天然是近似表示,它的顶点坐标、面片密度都服务于“看起来像”,而不是“量起来准”。这就像用像素画去指导数控机床加工,本质上不是同一个信息载体。
所以 text-to-cad 的技术路线,从一开始就注定不能走“生成网格”这条捷径,而是要让模型学会输出参数化操作。哪怕最终也要导出成 mesh 用于渲染或打印,但在中间环节必须有可编辑、可约束、可重算的 CAD 数据结构。谁能在这一层做得稳,谁才能真正落地。
1.3 谁适合用text-to-cad
先说最直接的用户:非专业建模者。很多 3D 打印玩家有明确需求:我要一个能卡住摄像头的小支架、一个路由器挂架、一个补缺的塑料垫片。他们不想学一整套 CAD 软件,只想用自然语言描述尺寸和功能。text-to-cad 可以成为“设计助手”,帮他们生成第一版模型,再进软件微调。
另一类是设计师和结构工程师的草图阶段。工程师经常开会时口头描述一个零件:宽度大概 60,长度 100,厚度 3,四周开四个沉头孔。过去要回工位慢慢画,如果有一个 text-to-cad 工具能先画出基础特征,再到 CadQuery 或 SolidWorks 里补细节,效率会高不少。注意这里说的是“辅助”,不是“替代”,目前替代还不现实。
还有自动化批量生成场景。比如电商平台要按不同参数生成成千上万款定制铭牌、外壳、齿轮。用传统模板参数化当然也能做,但如果有自然语言入口,业务人员就能直接描述需求,不需要开发改代码。教学场景也很有意思:让学生用自然语言描述设计意图,再对照生成的 CAD 特征树学建模逻辑,比从零学命令快得多。
我个人的判断是,text-to-cad 短期不是要取代 CAD 软件,而是把人和三维建模之间的“输入门槛”降低一大截。它能做的事,是让“画一个东西”变得更像“说一个东西”。
2. 主流技术路径:从文本到参数化模型
2.1 核心是把语言翻译成构造步骤
目前比较靠谱的 text-to-cad 实现,几乎都是同一个思路:让大型语言模型把文本翻译成一份 CAD 构造脚本。所谓 CAD 构造脚本,就是一系列可执行的建模操作,例如“创建一个平面草图,画一个矩形,拉伸到 10mm,在中心打一个直径 5mm 的孔”。这类脚本语言包括 OpenSCAD、CadQuery、SolidPython、FreeCAD 的 Python API 等。
为什么要用代码作为中间表示?因为文本是离散的,代码也是离散的,语言模型处理连续的点云反而不擅长。文本描述“凸台边长 20,高 5”,可以直接映射到代码里的cube([20, 20, 5]),这种 token 级别的映射关系,是语言模型天然可以学习的。反过来,如果让模型直接回归三维坐标,误差控制非常难,而且很难引入“约束”信息。
这里有个关键点:CAD 脚本不是简单的一句代码,而是一棵树。OpenSCAD 的布尔运算本身就是一个 CSG 树,CadQuery 则是面向对象的特征序列。我们要让 AI 学会的,是如何从自然语言中提取实体、属性、空间关系,并组织成合法的操作树。比如“在圆盘中央打一个通孔”,模型不仅要识别出“圆盘”和“孔”两个实体,还要知道“中央”是位置约束、“通孔”是贯穿特征。
所以在实际项目里,我不建议直接用大模型输出纯 OpenSCAD 代码。更稳的方案是设计一个受限的中间 DSL(领域专用语言),比如 JSON 格式的特征列表:
{ "features": [ {"type": "cylinder", "radius": 20, "height": 10, "origin": [0, 0, 0]}, {"type": "hole", "radius": 4, "origin": [0, 0, 0], "through": true} ], "units": "mm" }然后写一个解释器,把这个 JSON 转成 OpenSCAD 或 CadQuery 脚本。这样做的原因是:让大模型直接生成自由代码,语法错误率太高;但如果让它生成结构化 JSON,再交给固定解释器渲染,就把“语义理解”和“语法生成”分离了。前者是大模型擅长的,后者是传统代码可以兜底的。
2.2 三种常见表示空间怎么选
text-to-cad 的技术路径中,中间表示的选择决定了整个系统的上限。我总结下来,主流方案有三类。
第一类是程序化代码表示,代表工具是 OpenSCAD、CadQuery。它生成的模型自带参数和特征,可编辑性最强,也最容易验证。缺点是表达能力受限于脚本语言,复杂的自由曲面很难表达,需要依赖放样、扫掠、曲面建模等高级操作。
第二类是隐式场表示,比如 SDF(符号距离场)、占用场。这类表示适合生成有机形状,比如阀体、外壳、人体工程学手柄。模型输出一个函数,空间中每个点返回“到表面的距离”或“是否在体内”,再从函数里提取等值面生成网格。优点是表达能力强,能生成任意拓扑;缺点是提取网格后仍然是 mesh,无法直接进入 CAD 特征树,需要再做逆向。AutoSDF、Point-E 这类方法都在这个方向上。
第三类是点云或体素表示,通常作为中间输出,再配合后续的曲面重建进入 CAD。点云本身不带任何工程语义,需要额外步骤,因此目前更多用于“文本生成形状”的研究,不太适合直接做机械零件。
我给一个不太严谨但很实用的选择建议:如果目标是加工件、标准件、装配体,优先选代码生成,因为特征、尺寸、约束都在;如果目标是概念外形、外观件,可以考虑隐式场;如果只是做设计灵感预览,那就无所谓了,点云、网格都行。也就是说,越接近制造环节,越要偏向可编辑的程序化表示。
2.3 端到端生成与传统两步走的取舍
有些研究论文追求一个模型从文本直接输出 CAD 操作序列,也就是端到端。这种方案听起来很爽,实际训练起来却非常吃数据和算力。CAD 操作序列本身是一种带层级结构的程序,语言模型要同时学会语义理解、几何推理、语法约束和参数回归,任何一个环节出错都会崩盘。我见过的端到端 demo,大多是训练数据里见过的类似句式能跑通,换一个说法就完全失灵。
相比而言,两步走方案在工程上更稳妥。第一步,先用语言模型做信息抽取:识别文本中的实体、数量、单位、位置关系。第二步,再用规则或模板规划生成 CAD 操作。比如“一个 40mm × 30mm × 5mm 的底座,四角带 M3 沉头孔”,第一步先抽取出“底座、四个孔、M3、矩形阵列”,第二步查标准件库得到 M3 沉头孔的尺寸,然后生成 CadQuery 代码。
两步走的好处是可以引入外部知识库和规则约束。沉头孔的标准尺寸不该靠模型“想象”,而是查表。倒角该倒多大、螺纹底孔该钻多大,都应由工艺规范决定。这些信息用外部规则注入,比让模型硬记可靠得多。所以我的判断是:当前阶段,工程应用应优先做可控的分步系统,而不是迷信一个“黑盒”端到端模型。
3. 落地实操:从一句描述到可打印的STL文件
3.1 先搭一个最小可用的环境
拿一个最简单的场景举例:从自然语言生成 OpenSCAD 模型,再导出 STL 用于 3D 打印。这个流程足够小,却覆盖了 text-to-cad 的几个关键节点:语义解析、代码生成、渲染校验、导出制造格式。
环境准备只需要三样东西:Python 环境,用于调用大模型和编写解析逻辑;OpenSCAD 命令行工具,用于把脚本渲染成 PNG 或导出 STL;以及一个文本编辑器或 Jupyter Notebook。如果你希望生成更现代的脚本式模型,也可以装 CadQuery,它的 Python API 比 OpenSCAD 更接近传统 CAD 的特征思维,但最小示例用 OpenSCAD 就够了。
安装 OpenSCAD 之后,记得确认命令openscad在 PATH 里。在 Linux 下可以用apt install openscad,macOS 下用 Homebrew 安装,Windows 下安装后手动把可执行文件路径加进 PATH。这个步骤看起来简单,但很多人卡在脚本调用时找不到可执行文件,后面所有自动化都会报错。
3.2 一个从文本到OpenSCAD脚本的完整示例
假设用户输入这样一句话:“一个直径 40mm、高 10mm 的圆柱,中心打一个直径 8mm 的通孔。”这是一个非常典型的入门级描述。
先让大模型做结构化抽取,输出 JSON:
{ "base": {"type": "cylinder", "radius": 20, "height": 10}, "hole": {"type": "hole", "radius": 4, "through": true} }然后由一个解释器生成 OpenSCAD 脚本:
$fn = 64; difference() { cylinder(r = 20, h = 10); cylinder(r = 4, h = 10); }这里有两个细节常被新手忽略。第一,文本说“直径 40mm”,半径是 20mm;文本说“直径 8mm”,半径是 4mm。模型如果不理解“直径”和“半径”的转换,生成结果会大错特错。所以在结构化表达中,我建议直接统一使用半径,并把“直径/半径”的转换放在语义解析阶段完成,不要让解释器再去猜。
第二,OpenSCAD 的$fn参数控制圆的逼近精度。实际打印时如果$fn设置成 64,圆柱侧面看起来已经足够光滑;但如果用于精密零件,建议用更高的$fn或改用$fa、$fs控制角度和尺寸误差。还有一点,通孔的建模用cylinder加上difference布尔减法是常规做法,但如果你希望孔在工程上更真实,考虑锥角、沉头等特征时,就不能只用一个简单的圆柱了,那属于后处理阶段需要补充的工艺细节。
生成脚本后立刻进行渲染预览,在命令行执行:
openscad -o preview.png -D '$fn=64' part.scad如果命令没有报错,并生成了一张正常图片,说明基本语法没问题。但别高兴太早,这只是第一步。
3.3 不能只看渲染图:自动校验的四个环节
文本生成代码最大的风险,是“看起来对,实际不能用”。很多 AI 生成的 OpenSCAD 模型,渲染预览能通过,切片时却出问题。我自定义了一套四步校验流程,每次批量生成都跑一遍。
第一步是语法校验。用 OpenSCAD 的--check-parameters这类参数检查,或直接用 Python 的 AST 解析脚本,看看有没有未定义变量、括号不匹配、函数名拼错。代码层面的错误要最先干掉。
第二步是几何校验。导出 STL 之后,用admesh、MeshLab或 Python 的trimesh库检查 STL 是不是闭合的流形,有没有朝向错误的面、破洞、自相交。对于打印来说,非流形模型等于废件。
第三步是尺寸校验。把脚本里的关键参数抽出来,和用户输入的要求做比对:直径对不对、高度对不对、孔位间距对不对。这一步不是看渲染图,而是做数值断言。比如用户要求“中心孔距底面 30mm”,生成的代码里translate([0, 0, 30])就必须真有一个30。
第四步是工程校验。是否有拔模角度?壁厚是否小于打印机能承受的极限?孔是否有过盈配合需要?这类规则没法靠单一模型解决,需要一套规则库。我的做法是把校验规则写成 Python 检查器,在生成流水线里逐个执行,检查不通过就触发“重新生成”或“标记人工审核”。
3.4 批量生成时的工程化提示
当你开始批量处理几十条描述时,就不能一条条手动跑命令了。我会把所有流程包装成一个函数:
def text_to_stl(description: str, out_path: str): spec = llm_extract(description) script = build_openscad(spec) if not validate_syntax(script): raise ValueError("syntax check failed") tmp_scad = write_temp(script) preview = render_preview(tmp_scad) stl_path = export_stl(tmp_scad, out_path) if not validate_mesh(stl_path): raise RuntimeError("mesh not manifold") return stl_path这个函数里我刻意把每一步拆开,原因是方便定位问题。如果生成的 STL 流形不通,错误信息可以直接告诉你是语法、几何还是尺寸阶段失败,而不是让你面对一团乱麻的报错日志。
还有一个工程化细节:大模型的 temperature 参数要调低。text-to-cad 和聊天不同,这里要的是稳定输出,不是创意发挥。temperature 设置在 0.1 到 0.2 之间,能显著减少随机生成的“胡话参数”。另外,system prompt 里必须写明“只输出 JSON,不要解释”,否则模型把思考过程也输出出来,解释器直接崩溃。
4. 常见问题与排查技巧实录
4.1 文本歧义:AI把“薄壁”理解成模型的一个薄片
自然语言天生有歧义,这在 text-to-cad 里会被放大。比如“两孔之间的薄壁厚度是 2mm”,AI 可能把这个“薄壁”理解成单独一个薄片实体,而不是两个孔之间的距离约束。我遇到最典型的例子是用户说“做一个小外壳,壁厚 1.5mm”,结果生成的模型是“一个壁厚 1.5mm 的实体板”,而不是一个空心的薄壁容器。
解法有两种。第一种是在提示词工程里做约束:要求模型把“壁厚”识别为“壳操作”或“布尔减去的内部偏移”,并且在中间表示里明确字段wall_thickness。第二种是后规则校验:如果检测到文本里出现“外壳”“盒体”“壁厚”等词汇,而生成的模型没有布尔挖空操作,就判定为语义解析失败,触发重新生成。
遇到歧义时,我倾向于让模型输出多个候选解释,再让用户选择。比如“做一个长 50 的盒子”到底是内长还是外长?先让模型生成两个版本,标注“内尺寸版本”和“外尺寸版本”,这种交互比强行让 AI 猜一个要可靠得多。
4.2 尺寸单位与半径直径混淆
单位问题是 text-to-cad 的隐形杀手。CAD 领域默认用毫米,但普通用户可能说“4 厘米”“3 英寸”。如果系统没有单位换算,后面所有尺寸都会对不上。我的建议是:在语义解析阶段直接统一到毫米,并在 JSON 里记录原始单位和原始数值,方便追溯。
另一个高频错误是“直径/半径”不分的幻觉。用户说“直径 10 的孔”,模型却生成r = 10。这个问题看起来很蠢,但语言模型非常容易混淆,因为“10”出现在描述里,模型就倾向于直接作为参数。补救方法是建立关键词归一化表:与“直径”对应的 key 是diameter,然后在解释器里做radius = diameter / 2,而不是让模型自己换算。
4.3 布尔运算与拓扑错误
OpenSCAD 的difference、union、intersection是 CSG 布尔运算,对输入几何体的要求很严格。当两个圆柱共面、一个立方体正好贴住另一个立方体的面时,OpenSCAD 可能产生退化面、零厚度边,最后导出的 STL 流形不闭合。
最典型的场景是“在方形底板的中心挖一个刚好与板厚度相等的贯通槽”。由于槽高度和板厚度完全相等,布尔求差时两个体在 Z 方向“恰好相切”,软件无法稳定判断边界,渲染图上可能显示正确,导出 STL 后却出现裂缝。
排查策略是:对每个布尔操作“留一点点余量”。比如挖槽的高度比底板厚度多 0.001mm,或者把分割平面做一次微小偏移,让布尔操作“穿过”而不是“擦过”。经验规则是:参与布尔运算的体,尽量让它们有明确的相交区域,避免共面接触。
4.4 LLM幻觉代码与参数失控
大模型生成代码时,会一本正经地编造不存在的函数或参数。比如 OpenSCAD 里根本没有chamfer圆角命令,它却可能生成chamfer(...)。这种问题特别的隐蔽,因为脚本报错后,初学者第一反应是去查 OpenSCAD 文档,没想到是模型在“一本正经地胡说八道”。
解决办法是不要让它直接输出“自由文本代码”,而是让它生成受限的 JSON 特征指令,再由本地的“可执行函数库”映射到 OpenSCAD 或 CadQuery。如果某个特性(比如倒角)当前还不支持,JSON 解释器就直接报“不支持该特征”,而不是让模型临场发挥。
另一个幻觉点是参数范围。模型可能生成半径 1e8 的巨大圆柱,或者负高度的立方体。所以每个参数都要做范围检查:radius 必须大于 0 且小于 1000,height 必须大于 0 且小于 1000。数值校验是成本最低、收益最高的防线。
4.5 数据依赖与泛化边界
text-to-cad 模型的泛化能力,目前受限于训练数据。开源社区在做 Text2CAD 这类数据集,把 CAD 模型的操作序列和文本描述配对。这类数据合成思路是对的,但覆盖范围还比较窄,大多是机械零件、规则几何体。一旦遇到汽车曲面、复杂装配体、需要自由曲面建模的造型,模型的表现就会断崖式下跌。
所以我的建议是:把它当“规则零件的辅助设计器”用,别拿它当“万能建模师”。在业务落地时,先盘点自己的需求是否落在训练数据覆盖范围内。如果都是板件、轴、套、孔系结构,那 text-to-cad 能发挥很大价值;如果涉及外观创意设计,建议找另一个技术路线。
5. 工具选型与学习建议
5.1 不同需求对应不同技术栈
| 需求场景 | 推荐中间表示 | 推荐工具 | 理由 |
|---|---|---|---|
| 机械零件、标准件 | 特征序列 | CadQuery / SolidPython | 贴近 CAD 特征思维,参数改动方便 |
| 3D 打印外壳、支架 | CSG 树 | OpenSCAD | 语法简单,AI 容易生成,验证快 |
| 概念外观、自由曲面 | 隐式场 | SDF / 神经隐式模型 | 表达能力更强,适合有机形态 |
| 装配体、多零件设计 | 参数约束网络 | FreeCAD Python API | 支持装配关系,但技术门槛更高 |
| 纯设计灵感预览 | 点云或网格 | 现成文本生成 3D 模型 | 快,但不适合工程化 |
这段表格不是绝对标准,但可以作为技术选型的第一层过滤器。机械场景里,我强烈建议优先掌握 CadQuery。它的思想是“先建平面草图、再拉伸旋转、再打孔”,和主流 CAD 软件的操作逻辑一致,所以模型生成的代码也更接近真实设计步骤。
5.2 开源项目怎么读才不走弯路
很多人读 text-to-cad 相关的论文或开源仓库,一上来就盯模型架构、loss 函数,结果越看越晕。我建议先看数据,再看中间表示,最后看模型结构。因为这类任务最大的难点往往不是模型,而是数据如何构造。
先看训练数据长什么样:一条文本描述对应几个操作步骤?操作步骤是用序列化的 JSON 表示,还是一段 CadQuery 代码?如果数据本身质量不高,模型再先进也白搭。
再看中间表示是否支持“可逆执行”。也就是从表示能不能直接重建出模型,并且能不能方便地做局部修改。如果中间表示是固定长度的向量,那基本不具备工程价值,顶多发论文。
最后才是模型。我个人的经验是,当前阶段与其去训练一个新模型,不如先在大模型预训练基础上做少量微调或直接做 in-context learning。LSTM 时代那种从零训练序列模型的方式,已经被大模型取代了,别走回头路。
5.3 几条写在最后的大实话
如果让我总结 text-to-cad 真正重要的东西,我会说:不是模型从文本生成能力,而是“约束系统”。一个能让 AI 自由发挥的文本生成器,和一个能把结果约束在制造规则之内的生成器,是完全不同的产品。普通用户只看到渲染图,工程师却会检查尺寸、公差、螺纹孔、壁厚、材料收缩率。这些约束越早进入系统,落地的概率越大。
在实际操作中,我把大模型当“翻译官”而不是“设计师”。它负责把用户的话翻译成结构化诉求,剩下的几何生成和校验交给规则系统。这样可以充分发挥大模型的语义理解能力,同时避免它的幻觉和不确定性。你可以在提示词里加上一句话:“如果你的描述有歧义,请输出你能想到的默认假设,并单独列出假设条件。”这比让模型闷头生成更可控。
还有一个小技巧:每个生成的模型,都保留当时的“输入文本、中间 JSON、最终脚本”三件套,存成一个可追溯的 case。下次模型表现不对时,翻出历史 case 对比,能更快定位是语义抽取问题还是解释器问题。我就靠这个办法,把模型的单次成功率从八成提到了九成以上。
最后再分享一个我常用的验证思路:拿到一个 text-to-cad 生成结果,别先急着看正面渲染图,先剖开看内部。把模型切一半,看壁厚是否均匀、孔道是否贯通、倒角是否如预期。文本生成模型的很多错误,藏在内部比藏在表面多得多。做设计工具的人,一定要有“切开模型”的习惯。