1. 从一句话到三维模型:text-to-cad 到底在解决什么问题
把一句自然语言描述直接变成可用的 CAD 模型,这件事在几年前还只存在于论文里。现在你打开任何一个 AI 编程工具,输入“生成一个长宽高 100x60x40mm、壁厚 3mm、四角带 M4 沉头孔安装位的钣金外壳”,几秒钟后就能拿到一段可渲染的几何代码——这就是text-to-cad正在做的事。
它的核心链路其实不复杂:自然语言 → 结构化参数 → 几何内核脚本 → 标准格式文件。但真正落地时会发现,每一步都有大量工程细节需要处理。比如“四角带 M4 沉头孔”这句话,模型需要理解沉头孔的标准尺寸(M4 沉头孔通常头部直径 8mm、沉头角度 90°),还要知道孔位应该距离边缘多少(一般取板厚的 2 倍或至少 6mm),这些隐含知识如果不在提示词或后处理里补全,生成的模型就是废的。
这篇文章面向三类人:一是想用 AI 加速原型设计的硬件工程师,二是需要批量生成参数化模型的工艺人员,三是想把 CAD 能力集成到自己工具链里的开发者。我会把 text-to-cad 的完整实现路径拆开讲清楚,包括几何内核选型、提示词工程、格式导出(STEP、URDF、G-code)、以及实际踩过的坑。读完你至少能自己搭一条可用的生成流水线,而不是停留在“让 AI 画个方块”的玩具阶段。
提示:text-to-cad 不是要替代 CAD 工程师,它替代的是“重复性建模劳动”。理解这一点,你才不会在工具选型上走弯路。
2. 核心架构拆解:为什么是“代码生成”而不是“直接建模”
2.1 两条技术路线的本质区别
目前 text-to-cad 的实现大致分两派。一派是直接生成网格,用扩散模型或点云生成网络直接输出 STL 或 OBJ 网格;另一派是生成几何脚本,让大模型输出 CadQuery、OpenSCAD 或 build123d 的代码,再由几何内核执行得到 B-rep 实体。
我实测下来,直接生成网格的路线在“看起来像”这件事上表现不错,但一旦你要修改尺寸、加个孔、导出 STEP,基本就废了。因为网格没有参数化信息,也没有拓扑关系,后续根本没法做特征编辑。而代码生成路线虽然对提示词要求更高,但生成的模型是真正的参数化实体,可以导出 STEP、可以改参数重新执行、可以导入 URDF 做仿真。
所以如果你做的是工程用途,代码生成路线是唯一选择。直接生成网格那套更适合游戏资产或视觉展示,不在本文讨论范围内。
2.2 几何内核选型:CadQuery vs OpenSCAD vs build123d
选哪个内核直接决定了你后续的能力边界。我列一个实际对比表:
| 内核 | 底层 | 输出格式 | 参数化能力 | 学习曲线 | 适合场景 |
|---|---|---|---|---|---|
| OpenSCAD | CSG | STL、OFF、DXF | 强 | 低 | 简单结构、快速验证 |
| CadQuery | OCCT | STEP、STL、DXF | 极强 | 中 | 工程零件、装配体 |
| build123d | OCCT | STEP、STL | 极强 | 中高 | 复杂特征、Python 原生 |
| FreeCAD 脚本 | OCCT | STEP、IGES | 强 | 高 | 已有 FreeCAD 工作流 |
OpenSCAD 的优势是语法简单,大模型生成准确率高,但它只有 CSG(构造实体几何),做圆角、倒角、复杂曲面很吃力。CadQuery 基于 OCCT(Open CASCADE Technology),能输出真正的 STEP 文件,支持完整的 B-rep 操作,是目前 text-to-cad 项目里用得最多的内核。
我个人的选择是CadQuery 为主,OpenSCAD 为辅。简单零件用 OpenSCAD 快速出结果,需要 STEP 导出或复杂特征的用 CadQuery。build123d 虽然更现代,但大模型对它的训练数据相对少,生成准确率还不如 CadQuery 稳定。
2.3 大模型输出代码的可靠性问题
这里有个很多人忽略的点:大模型生成的 CadQuery 代码经常有 API 幻觉。比如它会写出cq.Workplane("XY").box(100, 60, 40).fillet(3)这种代码,但fillet在 CadQuery 里需要先选中边,直接调用会报错。再比如它会混用 CadQuery 2.x 和 1.x 的 API,导致运行失败。
解决办法不是换更大的模型,而是建立代码校验和自动修复层。我的做法是:生成代码后先在沙箱里执行,捕获异常,把错误信息回传给模型让它自我修复,最多重试 3 次。实测这个策略能把首次生成的成功率从 40% 左右提升到 85% 以上。
注意:不要让模型直接生成最终代码就完事,一定要有执行验证环节。没有验证的 text-to-cad 流水线,产出全是“看起来对但跑不通”的废代码。
3. 提示词工程:怎么把一句话变成可执行的几何参数
3.1 提示词的结构化模板
直接丢一句“帮我画个盒子”给模型,出来的东西基本不能用。我总结了一个结构化模板,把提示词分成五个部分:
- 几何类型:明确是拉伸体、旋转体、扫掠体还是装配体
- 关键尺寸:长宽高、直径、壁厚、孔径,全部带单位和数值
- 特征列表:孔、槽、圆角、倒角、螺纹,逐项列出
- 坐标系约定:原点在哪、Z 轴朝哪、基准面是哪个
- 输出要求:目标格式(STEP/STL/URDF)、单位制(mm/inch)、精度
举个例子,同样是“一个带孔的板”,好的提示词是这样的:
生成一个矩形板: - 尺寸:120mm x 80mm x 6mm - 原点位于板底面中心,Z轴向上 - 四角各有一个 M5 通孔,孔中心距边缘 10mm - 所有外边缘倒角 R2 - 输出 STEP 格式,单位 mm这样模型生成的代码基本一次就能跑通。而“画个带孔的板”这种提示词,你得到的可能是任意尺寸、任意孔位、任意格式的东西。
3.2 隐含工程知识的补全策略
自然语言里大量信息是省略的。用户说“M4 沉头孔”,他不会告诉你沉头孔的标准尺寸。这时候有两种补全方式:一是在提示词模板里预置标准件库,二是让模型自己查表。
我推荐预置标准件库的方式。具体做法是维护一个 JSON 文件,里面存常用标准件的参数:
{ "M4_flat_head": { "hole_diameter": 4.5, "head_diameter": 8.0, "head_angle": 90, "head_height": 2.5 }, "M5_socket_head": { "hole_diameter": 5.5, "head_diameter": 9.5, "head_height": 5.0 } }生成代码前,先用规则引擎把“M4 沉头孔”替换成具体参数,再交给模型生成几何代码。这样既保证了准确性,又减少了对模型“记忆力”的依赖。
3.3 多轮对话中的参数继承
实际使用中,用户不会一次把需求说全。常见的情况是:“先画个底板” → “厚度改成 8mm” → “再加四个安装孔”。如果每轮都重新生成完整代码,很容易丢失之前的上下文。
我的处理方式是维护一个参数状态机。每轮对话只更新变化的参数,几何代码基于最新参数集重新生成。这样即使用户改了十次尺寸,最终模型始终是一致的。实现上可以用一个字典存所有参数,每次生成前把字典序列化成提示词的一部分。
实操心得:参数状态机要记录每个参数的来源(用户指定还是默认值),这样当用户说“恢复默认”时你知道该恢复什么。我一开始没做这个,结果用户改了几轮之后想回退,只能全部重来。
4. 从代码到文件:STEP、URDF、G-code 导出实操
4.1 STEP 导出与常见坑
CadQuery 导出 STEP 就一行代码:
cq.exporters.export(result, "output.step")但实际用的时候有几个坑。第一,单位问题。CadQuery 默认单位是 mm,但有些下游软件(比如某些老版本 SolidWorks)读 STEP 时会按 inch 解析,导致模型放大 25.4 倍。解决办法是在导出时显式设置单位,或者在文件头里写清楚。
第二,装配体导出。如果你生成的是多个零件的装配体,直接 export 只会导出第一个实体。需要先用cq.Assembly把零件组装起来,再导出。装配约束(同心、贴合、距离)也要在代码里定义好,否则导出的 STEP 里零件位置全是乱的。
第三,精度设置。STEP 导出有线性精度和角度精度两个参数,默认值对大多数零件够用,但如果你做的是光学件或精密配合件,需要调高精度。代价是文件体积会变大。
4.2 URDF 导出:从 CAD 到仿真
URDF(Unified Robot Description Format)是机器人仿真的标准格式。把 text-to-cad 生成的模型导出成 URDF,可以直接导入 CoppeliaSim、Gazebo 等仿真环境。
这里的关键是关节定义。CAD 模型本身只有几何信息,没有运动学关系。你需要在生成代码时额外定义每个关节的类型(旋转、平移、固定)、轴向、限位。我的做法是在提示词里加一段关节描述:
关节定义: - joint1: 旋转关节,绕Z轴,范围 -180° 到 180° - joint2: 平移关节,沿X轴,范围 0 到 50mm - 其余连接为固定关节然后生成代码时同时输出几何和 URDF 的 XML 片段。注意 URDF 里的惯性矩阵需要根据几何形状和材料密度计算,不能随便填。我一般用 CadQuery 算出体积,乘以密度得到质量,再用简化公式估算转动惯量。
4.3 G-code 生成:从模型到加工路径
如果你生成模型的目的是 3D 打印或 CNC 加工,就需要导出 G-code。这一步通常不在 text-to-cad 的直接链路里,而是把生成的 STL 丢给切片软件(Cura、PrusaSlicer)或 CAM 软件处理。
但有些场景下,你希望直接生成 G-code,比如简单的 2D 轮廓切割或钻孔路径。这时候可以用 Python 的pygcode库或者直接写 G-code 生成器。关键参数包括:进给速度、主轴转速、刀具直径、安全高度、切削深度。这些参数如果让大模型直接生成,出错率很高,建议用模板加参数替换的方式。
注意:G-code 生成涉及实际加工安全,参数错误可能导致断刀或撞机。我的做法是生成的 G-code 先在仿真软件里跑一遍,确认路径无误再上机。
5. 常见问题与排查技巧实录
5.1 模型生成失败的高频原因
我把实际遇到过的失败案例整理成了一张速查表:
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 代码执行报 API 错误 | 模型用了不存在的 API | 看报错行号,查 CadQuery 文档 | 回传错误让模型修复 |
| 生成的实体为空 | 布尔运算顺序错误 | 打印中间结果体积 | 调整 union/cut 顺序 |
| 圆角失败 | 圆角半径大于相邻边 | 检查圆角处几何尺寸 | 减小半径或改倒角 |
| STEP 导入后尺寸不对 | 单位不一致 | 测量导入后模型尺寸 | 导出时显式设单位 |
| 装配体零件重叠 | 约束定义错误 | 逐个检查零件位置 | 重新定义装配约束 |
| URDF 导入仿真后抖动 | 惯性矩阵不合理 | 检查质量和惯量值 | 按实际材料重算 |
5.2 大模型代码幻觉的应对
前面提过 API 幻觉的问题,这里展开说。最常见的幻觉有三种:一是调用不存在的方法,比如Workplane.circle()在 CadQuery 里其实是Workplane.circle()没错,但Workplane.cylinder()就不存在,应该用Workplane.cylinder()或者Workplane.extrude()。二是参数顺序搞错,比如box(length, width, height)和box(width, length, height)在某些版本里含义不同。三是混用不同版本的 API。
应对策略是建立 API 白名单。把 CadQuery 常用 API 整理成一个列表,生成代码后检查所有调用的方法是否在白名单里。不在的就标记出来,让模型重新生成。这个白名单不需要覆盖全部 API,覆盖 80% 常用操作就够了。
5.3 性能优化:批量生成时的资源管理
如果你要批量生成几百个模型,性能会成为问题。OCCT 内核是单线程的,每个模型生成都要几秒到几十秒。我的优化经验是:
- 用多进程而不是多线程,因为 OCCT 不释放 GIL
- 把模型生成和文件导出分开,先生成所有模型对象,再统一导出
- 对于相似模型,复用几何内核的上下文,减少初始化开销
- 设置超时机制,单个模型超过 60 秒直接跳过,避免卡死整个队列
实测下来,8 核机器上批量生成 100 个中等复杂度零件,优化前要 15 分钟,优化后能压到 4 分钟左右。
实操心得:批量生成时一定要加日志,记录每个模型的生成时间、成功失败、错误信息。不然出了问题你根本不知道是哪个环节卡的。我用的是 Python 的 logging 模块,输出到文件加控制台双通道。
6. 工具链集成:把 text-to-cad 接入现有工作流
6.1 与 FreeCAD 的集成
FreeCAD 本身支持 Python 脚本,可以把 text-to-cad 生成的代码直接在里面执行。具体做法是写一个 FreeCAD 宏,接收自然语言输入,调用大模型生成 CadQuery 代码,执行后把结果添加到当前文档。这样你既享受了 AI 生成的便利,又能在 FreeCAD 里继续手动编辑。
需要注意的是 FreeCAD 内置的 Python 环境可能缺少 CadQuery 依赖,需要手动安装。我一般用 FreeCAD 的插件管理器装 CadQuery 插件,或者直接在系统 Python 里装好 CadQuery,然后让 FreeCAD 用系统 Python。
6.2 与 CoppeliaSim 的联动
CoppeliaSim(原 V-REP)支持导入 URDF,所以 text-to-cad 生成的 URDF 可以直接拖进去。但导入后经常发现模型比例不对或者关节方向反了。这时候需要检查 URDF 里的<origin>标签,确认每个 link 和 joint 的坐标系定义是否正确。
我的经验是:在生成 URDF 时,把所有 link 的坐标系都定义在几何中心,joint 的坐标系定义在旋转轴上。这样导入 CoppeliaSim 后基本不需要调整。如果关节方向反了,改<axis>标签的符号就行。
6.3 版本管理与可复现性
text-to-cad 的产出物包括:提示词、生成的代码、参数集、最终文件。这四样东西必须一起版本管理,否则你永远复现不出三个月前生成的那个模型。
我的做法是用 Git 管理整个项目目录,每次生成创建一个新分支,提交信息里写清楚提示词和参数。生成的代码和文件都提交进去。这样任何时候都能 checkout 到历史版本,重新执行代码得到相同结果。
提示:几何内核的版本也要记录。CadQuery 2.2 和 2.3 生成的同一个模型可能有细微差异,不记录版本号的话,复现时会对不上。
7. 实际项目中的经验与建议
7.1 从简单零件开始,逐步增加复杂度
我见过很多人一上来就想让 AI 生成复杂的装配体,结果挫败感很强。正确的做法是先从最简单的拉伸体开始,确认整条链路跑通,再逐步加特征。比如:
第一阶段:生成一个指定尺寸的方块,导出 STEP 第二阶段:加圆角、倒角 第三阶段:加孔、槽 第四阶段:多零件装配 第五阶段:导出 URDF 做仿真
每个阶段都验证通过后再进入下一阶段。这样出问题时容易定位,也不会因为一次引入太多变量而崩溃。
7.2 建立自己的提示词库和代码模板
用得多了你会发现,很多提示词和代码片段是重复的。比如“四角安装孔”这个特征,几乎每个板类零件都会用到。把这些常用特征做成模板,生成时直接引用,既提高速度又保证一致性。
我的模板库分三层:最底层是标准特征(孔、圆角、倒角),中间层是常用零件(板、轴、法兰),最上层是完整产品(外壳、支架、夹具)。每层都可以被上层继承和覆盖参数。
7.3 人工审核不可省略
不管 AI 生成得多么流畅,最终模型一定要人工审核。我审核的重点是:关键尺寸是否正确、特征位置是否合理、有没有干涉、能不能加工出来。特别是涉及配合的尺寸,差 0.1mm 可能就装不上。
审核通过后再导出最终文件。如果直接拿 AI 生成的模型去加工,出问题的概率很高。我自己的流程是:AI 生成 → 人工审核 → 修改参数 → 重新生成 → 再次审核 → 导出。
7.4 关于精度和公差的处理
自然语言里很少会提到公差。用户说“直径 10mm 的孔”,他不会说“直径 10mm H7 公差”。但实际加工时,公差决定了配合性质。我的处理方式是在提示词模板里加一个公差选项,默认用中等精度(比如孔 H8、轴 h7),用户有特殊要求时再指定。
导出 STEP 时,公差信息不会体现在几何里,但可以在文件名或伴随的 JSON 文件里记录。这样下游拿到文件时知道该按什么精度加工。
8. 后续扩展方向
text-to-cad 这条链路跑通之后,可以往几个方向扩展。一是反向工程,给一张手绘草图或照片,识别出几何特征再生成模型。二是参数优化,给定目标和约束,让 AI 自动调整参数找到最优解。三是多模态输入,结合语音、手势、草图等多种输入方式。
我现在正在做的是把 text-to-cad 和 3D 打印切片流程打通,生成模型后自动切片、生成 G-code、发送到打印机。整个流程从一句话到开始打印,目前能压到 5 分钟以内。当然中间还有人工审核环节,完全无人值守还不现实,但效率提升已经非常明显了。
最后分享一个小技巧:如果你用的是 CadQuery,在生成代码时让模型加上cq.exporters.export(result, "debug.stl")这行,每次生成后先导出 STL 快速预览,确认形状对了再导出 STEP。STL 导出比 STEP 快很多,能节省不少等待时间。