
1. 从一段文字到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个词很多人脑子里蹦出来的画面可能是对着电脑敲一句“给我画个法兰盘”然后屏幕上就自动出现一个带螺栓孔的 STEP 模型。这个想象不算离谱但也不完全准确。我实际折腾过几套方案之后更愿意把它理解成一种用自然语言描述来驱动 CAD 建模流程的思路——它不是要取代工程师而是把“脑子里想清楚的结构”快速变成“能看、能改、能导出”的三维实体。传统 CAD 建模的路径大家都熟打开软件选基准面画草图标注尺寸拉伸切除倒角阵列。一套流程下来简单零件十几分钟复杂装配体几个小时甚至几天。问题在于很多时候我们并不需要那么精细的交互只是想要一个能表达结构关系的初稿用来做方案沟通、装配验证或者 3D 打印预览。text-to-cad 瞄准的就是这个空档你描述需求系统生成几何你再拿回 CAD 里精修。它涉及的核心技术点其实横跨好几个领域。自然语言理解负责把你的“一个直径 80、厚 10 的圆盘中间开 30 的孔”解析成结构化参数几何内核负责把这些参数变成真实的 B-rep 实体或网格格式转换负责把结果输出成 STEP、GLB、STL 这些下游能用的文件。热搜词里频繁出现的 STEP、GLB、STL正好对应了三条主要出口STEP 给工程软件GLB 给可视化场景STL 给 3D 打印。适合看这篇内容的人我大致分三类。第一类是机械、建筑、工业设计方向的学生和初级工程师想快速把想法变成模型又不想被复杂命令劝退。第二类是做 3D 打印、手办、创客项目的玩家需要 STL 但不会建模。第三类是做工具链集成的开发者想把文字生成模型的能力嵌进自己的平台里。不管你是哪一类下面这些实操细节和踩坑记录应该都能用上。2. 整体方案怎么搭三条主流路线与选型逻辑2.1 路线一参数化模板匹配最稳但最不自由这条路线的思路很直接预先准备好一批参数化模型模板比如“法兰”“支架”“齿轮毛坯”“盒子”每个模板暴露若干可调参数。用户输入文字后系统做关键词和数值抽取匹配到对应模板填入参数生成模型。我最早试的就是这种方案。用 Python 写一个简单的解析器正则抓“直径”“厚度”“孔数”这些词然后调用 CadQuery 或 FreeCAD 的脚本接口生成 STEP。实测下来稳定性极高因为几何完全由确定性代码控制不会出现莫名其妙的破面。缺点是覆盖面窄用户说“一个带加强筋的 L 形支架”模板里没有就歇菜了。这种路线适合垂直场景比如只做钣金件、只做管接头、只做标准件。热搜里“金林钣金 CAD 版”“瑞丽服装 CAD”这类词其实暗示了行业专用 CAD 的需求模板匹配在专用领域反而比通用大模型更靠谱。2.2 路线二代码生成式让模型写建模脚本第二条路线是让语言模型直接生成建模代码比如 CadQuery 的 Python 脚本、OpenSCAD 的 DSL或者 FreeCAD 的宏命令。你输入“画一个 100x60x20 的盒子壁厚 3顶部开四个 M4 沉头孔”模型输出一段可执行的 CadQuery 代码运行后得到 STEP。这条路线的自由度明显更高因为代码能表达任意几何逻辑。我拿几个开源模型试过简单零件成功率不错但一旦涉及复杂曲面、放样、扫掠生成的代码经常跑不通或者几何自相交。排查起来也麻烦你得懂代码才能改。提示代码生成式方案一定要加沙箱执行和超时限制。我遇到过生成的脚本里写了死循环直接把进程卡死。另外生成的代码要先做语法检查再执行别直接 eval。2.3 路线三端到端模型生成直接出网格或隐式场第三条路线最“黑盒”训练一个模型输入文字直接输出三维表示。早期有直接生成体素或点云的现在比较多的是生成隐式场比如 occupancy network、SDF再用 marching cubes 提取网格最后转成 STL 或 GLB。这种方案的好处是能处理复杂形状不受模板和代码逻辑限制。坏处也明显生成的网格拓扑质量差面片多、有噪声、尺寸不精确基本不能直接用于工程制造。我拿它生成过一些装饰性摆件3D 打印出来还行但你要说“直径 80 正负 0.1”它给不了。所以这条路线更适合概念可视化、游戏资产、艺术造型输出 GLB 或 STL 做展示和打印而不是 STEP 做加工。2.4 选型对比一张表看清怎么选路线核心技术输出格式精度自由度适合场景模板匹配关键词抽取 参数化脚本STEP / STL高低标准件、垂直行业代码生成LLM CAD 脚本 APISTEP / STL高中高结构件、参数化零件端到端生成隐式场 / 扩散模型GLB / STL低高概念造型、展示、打印我个人的建议是如果你要的是能改、能加工、能出工程图的模型优先走前两条如果你要的是好看、能打印、能放进场景里的模型第三条可以玩。很多实际项目其实是混合的——先用端到端生成一个大概形状再转成参数化脚本精修。3. 核心细节拆解从文字到几何的关键环节3.1 文字解析怎么把“人话”变成“参数”自然语言描述三维结构最大的坑是歧义和缺省。用户说“一个圆盘”直径多少厚度多少中间有没有孔这些信息不补全几何就没法生成。我的做法是分三步走。第一步做实体和特征识别把句子拆成“基体 特征 尺寸”的结构。比如“一个 80 的圆盘厚 10中间 30 的孔”解析成基体圆柱直径80高度10特征通孔直径30位置中心。第二步做缺省值填充没有明确给出的尺寸按常见工程惯例给默认值比如圆盘厚度默认 5孔默认通孔。第三步做单位归一用户可能说“8 厘米”“80 毫米”“0.08 米”统一转成毫米再进几何内核。这里有个经验不要让模型直接输出最终尺寸而是输出带单位的参数字典由后端做校验和转换。我试过让模型直接生成 CadQuery 代码里的数字结果它把“80”理解成半径生成出来直径 160直接报废。3.2 几何内核B-rep 和网格的分水岭STEP 和 STL 的本质区别在于几何表示方式。STEP 用的是 B-rep边界表示记录的是精确的曲面方程和拓扑关系一个圆柱面就是一个数学曲面不是一堆三角形。STL 用的是三角网格把表面离散成小三角形精度取决于弦高公差。text-to-cad 如果要输出 STEP就必须走精确几何内核比如 OpenCASCADE、Parasolid、ACIS。这些内核能执行布尔运算、倒角、抽壳生成真正的实体。如果要输出 STL 或 GLB可以用网格生成路线也可以用 B-rep 再离散化。我实测下来OpenCASCADE 是开源方案里最靠谱的CadQuery、FreeCAD 都基于它。但它的布尔运算在复杂情况下会失败比如两个面几乎相切、或者有微小间隙。这时候需要调模糊容差把容差从默认的 1e-7 放宽到 1e-5 甚至 1e-4很多时候就能过。代价是精度下降但对概念模型来说可以接受。3.3 格式导出STEP、GLB、STL 各自的门道STEP导出要注意单位和坐标系。不同 CAD 软件对 STEP 的单位解释不一样有的默认毫米有的默认米。我遇到过导出的 STEP 在 SolidWorks 里打开变成 1000 倍大小就是因为单位没写清楚。AP214 和 AP203 是两个常见协议AP214 支持颜色和层AP203 更老但兼容性好。一般导出选 AP214。GLB是 glTF 的二进制版本适合网页和实时渲染。导出时要注意法线和材质。如果法线反了模型看起来会黑一块。材质如果用了 PBR要确保贴图路径正确否则 GLB 里只有颜色没有纹理。STL导出最关键的是弦高和角度公差。弦高越小网格越密文件越大。3D 打印一般弦高 0.01~0.05 毫米够用角度公差 15~30 度。如果导出后发现模型有破面多半是原始 B-rep 就有问题或者离散化时公差太松。注意STL 只有几何没有单位很多切片软件默认按毫米处理。如果你导出的 STL 是英寸单位打印出来会小 25.4 倍。导出前一定确认单位。4. 实操过程手把手搭一个最小可用的 text-to-cad 流程4.1 环境准备与依赖安装我用的技术栈是 Python CadQuery OpenCASCADE语言解析部分用了一个本地部署的小模型做意图识别。先装依赖pip install cadquery ocp pip install numpy trimesh pip install transformers torchCadQuery 自带 OCPOpenCASCADE 的 Python 绑定装完就能做布尔运算和导出。trimesh 用来处理 STL 和 GLB 的读写和检查。transformers 用来跑本地模型做文字解析如果你用 API 方案可以跳过。装完之后先跑一个冒烟测试import cadquery as cq result cq.Workplane(XY).circle(40).extrude(10) cq.exporters.export(result, test.step) cq.exporters.export(result, test.stl)如果 STEP 和 STL 都能正常导出说明内核没问题。我在这步踩过坑Windows 上 OCP 的某些版本和 CadQuery 不兼容报 DLL 加载失败。解决办法是用 conda 装或者锁定 CadQuery 2.4 以上版本。4.2 文字解析模块的实现解析模块我写了一个简单的 pipeline。先做分词和实体标注用正则抓尺寸和特征词再用模型做意图分类。核心代码如下import re def parse_description(text): params {} # 抓直径 dia re.search(r直径\s*(\d(?:\.\d)?), text) if dia: params[diameter] float(dia.group(1)) # 抓厚度 thick re.search(r厚\s*(\d(?:\.\d)?), text) if thick: params[thickness] float(thick.group(1)) # 抓孔 hole re.search(r(\d(?:\.\d)?)\s*的孔, text) if hole: params[hole_diameter] float(hole.group(1)) return params这只是一个兜底实际用的时候我会先让模型输出 JSON再用正则做校验。关键是要有默认值比如没抓到直径就默认 50没抓到厚度就默认 5。这样即使解析不全也能生成一个合理的模型而不是直接报错。4.3 几何生成与参数校验拿到参数字典后先做合理性校验。孔直径不能大于基体直径厚度不能为负尺寸不能超过某个上限比如 1000 毫米。校验通过后调用 CadQuery 生成几何def build_disk(params): d params.get(diameter, 50) t params.get(thickness, 5) hd params.get(hole_diameter, 0) result cq.Workplane(XY).circle(d/2).extrude(t) if hd 0: result result.faces(Z).workplane().hole(hd) return result这里有个细节hole 的方向。CadQuery 的 hole 默认向下打如果你在顶面工作平面上打孔它会穿透整个实体。如果只想打一半要用 cutBlind。我一开始没注意打出来的孔直接穿透了后来改成 cutBlind 才控制住深度。4.4 导出与下游验证生成实体后导出 STEP 和 STLcq.exporters.export(result, output.step) cq.exporters.export(result, output.stl, tolerance0.01, angularTolerance0.1)导出 STL 时tolerance 是弦高angularTolerance 是角度公差。0.01 毫米弦高对大多数 3D 打印够用文件也不会太大。导出后我用 trimesh 做一次检查import trimesh mesh trimesh.load(output.stl) print(mesh.is_watertight) print(mesh.volume)is_watertight 为 True 说明网格封闭可以打印。volume 可以用来估算材料用量。如果 is_watertight 为 False说明有破面需要回退检查 B-rep 或者调整离散化公差。5. 常见问题与排查技巧实录5.1 布尔运算失败怎么办这是最高频的问题。两个实体做差集结果报错或者生成空实体。原因通常是面重合或间隙过小。比如你在圆柱顶面打一个和顶面同直径的孔布尔运算就会因为面完全重合而失败。解决办法有三个。第一调整孔的位置或直径避免和边界重合。第二放宽模糊容差在 CadQuery 里可以设置cq.OCCT_MAKE_BOX # 不直接暴露但可以通过 OCP 设置更实际的做法是用clean()清理几何或者在布尔运算前先做一次fuse再cut。第三换运算顺序先做所有加法再做减法减少中间状态的复杂度。5.2 导出的 STEP 在别的软件里打不开我遇到过 STEP 在 FreeCAD 里正常在 SolidWorks 里报错。排查下来是单位协议问题。CadQuery 默认导出 AP214单位是毫米。但有些软件对 AP214 的支持不完整换成 AP203 就好了cq.exporters.export(result, output.step, exportTypeAP203)另外坐标系原点也很关键。如果模型离原点很远有些软件会显示异常。生成时尽量让模型中心或底面中心在原点。5.3 STL 打印出来尺寸不对前面提过单位问题这里再强调一次。STL 文件本身不记录单位切片软件默认按毫米。如果你的模型是按英寸建的导出 STL 后数值没变打印出来就是 25.4 倍。解决办法是在导出前统一转成毫米或者在切片软件里手动缩放。还有一个坑是法线方向。如果 STL 的法线朝内切片软件可能识别成负体积打印出来是空的。用 trimesh 检查mesh.fix_normals()这行代码能自动修复法线方向。5.4 文字解析把尺寸理解错了模型把“80”理解成半径而不是直径或者把“厚 10”理解成壁厚而不是总厚。这种问题很难完全避免我的做法是在生成前让用户确认参数。界面上把解析出的参数列出来用户点确认再生成。多一步交互少一堆返工。另外单位词要特别小心。“8 厘米”和“8 毫米”差 10 倍。我在解析模块里加了一个单位映射表厘米乘 10米乘 1000英寸乘 25.4统一转毫米。5.5 常见问题速查表问题现象可能原因排查方法解决手段布尔运算失败面重合或间隙过小检查实体是否相交调整尺寸、放宽容差、换运算顺序STEP 打不开协议或单位不兼容换软件打开测试改用 AP203、统一单位STL 尺寸不对单位未转换检查导出数值导出前转毫米STL 有破面离散化公差太松trimesh 检查 watertight减小弦高、修复法线文字解析错误歧义或缺省人工核对参数加确认步骤、补默认值6. 工具链与格式选择的经验之谈6.1 开源方案和商业方案的取舍开源方案里CadQuery OpenCASCADE是我用得最顺的。CadQuery 的 API 设计接近自然语言写起来快社区也活跃。FreeCAD 的脚本接口更底层适合做深度定制但学习曲线陡。OpenSCAD 适合纯参数化但不支持 STEP 导出只能出 STL 和 CSG。商业方案里Onshape 的 FeatureScript和Fusion 360 的 API都能做类似的事但需要联网和账号不适合本地部署。如果你要做产品开源方案省成本但维护量大商业方案稳定但受制于人。我个人的选择是核心用开源关键环节用商业库做补充。6.2 STEP、GLB、STL 的适用边界再梳理一遍这三个格式的适用场景。STEP是工程交换格式适合在 SolidWorks、UG、CATIA、FreeCAD 之间传递精确几何。GLB是渲染格式适合网页展示、AR/VR、游戏引擎。STL是打印格式适合切片软件和 3D 打印。如果你要做的是可编辑的工程模型STEP 是唯一选择。如果你要做的是展示和交互GLB 更合适因为它带材质和动画。如果你要做的是快速原型STL 最直接。我见过有人把 STL 转成 STEP用 FreeCAD 的“从网格创建形状”功能。转出来的 STEP 是一堆平面片体不是真正的曲面没法做圆角抽壳。所以格式转换不是万能的源头是什么下游就只能是什么。6.3 性能优化的几个实用技巧生成复杂模型时性能是个问题。我的经验是先做粗模再做精修。文字解析后先生成一个低精度的包围盒或简化体快速给用户看确认后再生成精确模型。这样交互体验好很多。另外缓存中间结果。同一个描述如果重复生成直接返回缓存。布尔运算的结果也可以缓存避免重复计算。对于批量生成用多进程并行每个进程独立跑 OpenCASCADE避免线程安全问题。提示OpenCASCADE 不是线程安全的多线程调用同一个内核实例会崩溃。用多进程别用多线程。7. 这个方向后续还能怎么玩我最近在试的一个方向是把 text-to-cad 和参数化库结合。比如用户说“一个 40 系列铝型材的直角支架”系统先匹配到标准件库再根据文字调整长度和孔位。这样既有模板的稳定性又有文字输入的灵活性。另一个方向是多轮对话式建模。用户第一句说“画个盒子”系统生成一个默认盒子用户接着说“高度改成 50加个盖子”系统在原有模型上修改。这需要维护一个建模状态树每次修改只更新受影响的部分而不是从头生成。还有一个实用场景是批量生成变体。比如你有一批零件只是尺寸不同可以用文字描述模板批量生成 STEP 和 STL。热搜里“python 批量对 cad 修改”这个词其实就是在说这个需求。用 CadQuery 写循环几分钟就能生成几百个变体。我在实际项目里最大的体会是text-to-cad 的价值不在于全自动而在于把重复劳动压缩掉。工程师的时间应该花在判断和优化上而不是画标准结构。把那些“每次都要画一遍”的东西交给文字生成省下来的时间用来思考真正的设计问题这才是它最实在的用处。