
1. 从一段文字到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词很多做机械设计或者工业建模的朋友第一反应是噱头。毕竟在大多数人的认知里CAD 建模是一件高度依赖空间想象力和软件操作熟练度的手艺活怎么可能靠打几个字就生成出来我一开始也是这么想的直到自己真正动手把这条链路跑通才发现它解决的其实是一个非常具体的痛点从想法到可用的几何文件之间那段最枯燥、最重复的建模劳动。举个最典型的场景。假设你要做一个法兰盘参数是外径 120mm、内径 60mm、厚度 15mm、均匀分布 6 个直径 10mm 的螺栓孔。在传统流程里你得打开 CAD 软件画圆、拉伸、再画孔、阵列、布尔运算一套操作下来熟练工也要几分钟而且一旦某个参数要改整条特征树都得跟着调整。而 text-to-cad 的思路是你用自然语言把这段描述写出来系统解析成结构化的几何参数再通过几何内核生成实体最后导出成 STEP、STL、GLB 这类标准格式。整个过程的核心价值不在于炫技而在于把参数化的重复劳动交给程序把人的精力留给真正需要判断力的设计决策。这里必须先厘清一个概念很多人把 text-to-cad 和AI 画图混为一谈。它们完全是两回事。文生图比如生成一张机械零件的渲染图输出的是像素是给人看的而 text-to-cad 输出的是带拓扑结构的边界表示BRep实体是给 CAD 软件、给 3D 打印机、给仿真工具用的。这意味着它必须保证几何是封闭的、流形的、可加工的一个面不能有破洞两个实体不能有重叠。这个要求比生成一张好看的图片苛刻得多也是为什么 text-to-cad 至今仍然是个有门槛的领域。那么它适合谁来用我总结下来是三类人。第一类是做参数化零件批量生成的工程师比如标准件库、系列化产品的快速出图第二类是做产品原型验证的开发者想快速把脑子里的结构变成能 3D 打印的模型第三类是做 CAD 二次开发的技术人员需要在自己的系统里嵌入文字转模型的能力。如果你只是想画一张复杂的装配图那 text-to-cad 目前还替代不了你手里的鼠标和快捷键。搞清楚这个边界后面的内容你才不会走偏。2. 拆解 text-to-cad 的技术链路文字是怎么变成实体的2.1 自然语言到结构化参数的解析层整条链路的第一环是把人话翻译成机器能懂的参数。这一步看起来简单实际上坑最多。因为自然语言天生是模糊的而几何参数必须是精确的。比如你说一个差不多 100 毫米的圆盘差不多是多少公差给多少这些在建模里都是必须确定的量。目前主流的做法有两种。一种是基于规则模板的解析也就是预先定义好一批句式模板比如外径 X、内径 Y、厚度 Z 的圆环然后用正则或者语法解析去匹配。这种方式的优点是可控、可预测缺点是只能处理你预设过的句式稍微换个说法就歇菜。另一种是基于大语言模型的语义解析让模型把自然语言映射成 JSON 格式的参数对象。这种方式灵活度高能理解六个均匀分布的孔这种带语义的描述但缺点是可能产生幻觉把不存在的参数编出来。我在实际项目里的做法是两者结合先用大模型做语义理解和参数抽取输出一个结构化的中间表示通常是 JSON然后再用一套严格的校验规则去检查这个 JSON 是否合法——单位是否明确、数值是否在合理范围、必填字段是否齐全。校验不通过就打回去让模型重新生成或者直接报错给用户。这个生成 校验的双层结构是我踩了不少坑之后才定下来的后面会详细讲为什么。一个典型的中间表示长这样{ primitive: flange, parameters: { outer_diameter: {value: 120, unit: mm}, inner_diameter: {value: 60, unit: mm}, thickness: {value: 15, unit: mm}, bolt_holes: { count: 6, diameter: {value: 10, unit: mm}, pattern: circular, pcd: {value: 90, unit: mm} } } }注意这里每个数值都强制带单位。这是血泪教训——我见过太多因为单位混乱导致的灾难模型以为你输入的是英寸结果生成出来的零件大了 25 倍。单位必须在解析层就锁定绝不能留到几何层再去猜。2.2 参数化几何的构建从 JSON 到 BRep拿到结构化参数之后就进入真正的几何构建阶段。这一步的核心是几何内核。市面上能用的开源内核主要有 OpenCASCADE简称 OCCT、CGAL 等商业的有 Parasolid、ACIS。做 text-to-cad 基本绕不开 OpenCASCADE因为它是开源里功能最完整、对 STEP 支持最好的一个。构建的过程本质上是调用内核的 API把参数翻译成几何操作。还是拿法兰盘举例逻辑大致是先创建一个圆柱体作为外轮廓再创建一个圆柱体作为内孔两者做布尔减运算得到带孔的盘体然后在指定半径的圆周上按角度均匀分布创建 6 个小圆柱再逐一做布尔减。听起来很直白但实际操作里每一步都有讲究。比如螺栓孔的圆周分布角度怎么算6 个孔均匀分布每个孔间隔 60 度起始角度通常从 0 度开始。但如果你希望第一个孔在正上方那起始角度就得是 90 度。这种细节在自然语言里往往不会说清楚需要你在解析层给一个合理的默认值同时在文档里写明白。我一般默认从 0 度正右方开始逆时针排布这是工程制图里比较常见的约定。再比如布尔运算的顺序。如果你先把所有孔都创建出来再一次性做减运算和逐个做减运算结果在几何上是一样的但性能和稳定性差别很大。OCCT 在处理多个工具体同时做布尔运算时偶尔会出现面片丢失或者微小裂缝。我的经验是逐个做布尔减每做完一次检查一下实体的有效性用BRepCheck_Analyzer发现问题能立刻定位是哪个孔出的问题而不是等到最后面对一个千疮百孔的实体干瞪眼。2.3 导出格式的选择STEP、STL、GLB 各管一段模型建好之后导出成什么格式取决于你要拿它干什么。这三种格式在 text-to-cad 的语境里出现的频率最高但它们的定位完全不同混用会出大问题。格式本质是否保留拓扑典型用途文件特点STEP边界表示BRep是CAD 软件互导、CNC 加工、仿真精确、可编辑、体积中等STL三角网格否3D 打印、快速预览只有面片、无单位、体积大GLB三角网格 材质否Web 展示、AR/VR、游戏引擎带材质和层级、适合渲染这里有个特别容易踩的坑STL 是不带单位的。STL 文件里只有一堆三角面片的顶点坐标它不知道自己是毫米还是米。很多 3D 打印切片软件默认按毫米处理如果你从 STEP 导出 STL 时单位搞错了打出来的东西要么是蚂蚁大小要么塞不进打印机。所以我的习惯是导出 STL 时在文件名里带上单位比如flange_120mm.stl并且在导出参数里明确指定缩放。GLB 则是另一套逻辑。它本质上是 glTF 的二进制版本专为 Web 和实时渲染设计。如果你要做的是在网页上让用户旋转查看模型GLB 是最优解加载快、体积小、浏览器原生支持。但千万别拿 GLB 去 3D 打印因为它的网格精度通常是为渲染优化的面片数可能不够打出来表面会有明显的棱角。STEP 是三者里最正经的格式也是 text-to-cad 最应该保证质量的输出。因为 STEP 保留了完整的 BRep 拓扑下游的 CAD 软件无论是 SolidWorks、中望 CAD 还是 FreeCAD都能读取并继续编辑。我测试过一个用 OCCT 正确导出的 STEP 文件在主流 CAD 里打开后特征树是干净的实体是有效的可以直接拿去出工程图。3. 动手搭一条最小可用的 text-to-cad 流水线3.1 环境准备与依赖选择要自己跑通这条链路环境准备是第一步也是最容易劝退的一步。核心依赖是 OpenCASCADE但它的安装在不同平台上差异很大这里我把踩过的坑一次性说清楚。在 Linux 上相对省心Ubuntu 系直接apt install libocct-*就能装上一整套开发库。在 Windows 上就麻烦一些官方不提供预编译的二进制包你得自己用 CMake 编译或者去找第三方打包好的版本。我推荐用 conda 来管理conda install -c conda-forge occt能省掉大量编译时间。macOS 上可以用 Homebrewbrew install opencascade但要注意版本不同版本之间的 API 有细微差异。Python 侧我强烈推荐用pythonocc-core它是 OCCT 的 Python 绑定让你不用写 C 就能调用几何内核。安装同样是走 conda 最稳conda install -c conda-forge pythonocc-core。如果你非要用 pip那得做好折腾编译的准备而且版本兼容性经常出问题。除了几何内核你还需要一个自然语言解析的组件。如果只是做原型验证直接调用大模型的 API 就够了如果要离线部署可以考虑用本地的小模型做意图识别再配合规则模板。我的建议是原型阶段先用 API 快速验证链路等逻辑跑通了再考虑替换成离线方案不要一上来就追求全离线那样会把大量时间浪费在环境上而不是核心逻辑上。3.2 用 pythonocc 构建一个法兰盘实体下面这段代码是我实际项目里精简出来的最小示例展示如何用 pythonocc 从参数构建一个带螺栓孔的法兰盘。注意每一步的注释这些细节决定了生成出来的实体是否有效。from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut from OCC.Core.gp import gp_Ax2, gp_Pnt, gp_Dir from OCC.Core.BRepCheck import BRepCheck_Analyzer import math def make_flange(outer_d, inner_d, thickness, hole_count, hole_d, pcd): # 创建外圆柱轴向沿 Z 轴 axis gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)) outer BRepPrimAPI_MakeCylinder(axis, outer_d / 2, thickness).Shape() # 挖内孔 inner BRepPrimAPI_MakeCylinder(axis, inner_d / 2, thickness).Shape() body BRepAlgoAPI_Cut(outer, inner).Shape() # 逐个挖螺栓孔每挖一个检查一次有效性 for i in range(hole_count): angle 2 * math.pi * i / hole_count x (pcd / 2) * math.cos(angle) y (pcd / 2) * math.sin(angle) hole_axis gp_Ax2(gp_Pnt(x, y, 0), gp_Dir(0, 0, 1)) hole BRepPrimAPI_MakeCylinder(hole_axis, hole_d / 2, thickness).Shape() body BRepAlgoAPI_Cut(body, hole).Shape() # 关键每次布尔运算后校验实体 analyzer BRepCheck_Analyzer(body) if not analyzer.IsValid(): raise RuntimeError(f第 {i1} 个孔布尔运算后实体无效) return body这段代码里有几个点值得展开说。第一gp_Ax2定义的是圆柱的局部坐标系原点和方向都要给对方向错了圆柱就长歪了。第二布尔运算的Shape()调用不能省它返回的是拓扑形状对象。第三也是最重要的每次布尔运算后做有效性检查。我一开始图省事所有孔挖完再检查结果有一次某个孔的位置刚好和内外壁相切产生了退化面整个实体报废但我根本不知道是哪个孔的问题只能一个个试。从那以后我就养成了逐个检查的习惯虽然慢一点但排查成本低得多。3.3 导出 STEP 与 STL 的正确姿势实体建好之后导出这一步同样有讲究。pythonocc 提供了对应的导出接口但参数配置不对导出的文件下游软件可能读不了。from OCC.Core.STEPControl import STEPControl_Writer, STEPControl_AsIs from OCC.Core.StlAPI import StlAPI_Writer from OCC.Core.Interface import Interface_Static_SetCVal def export_step(shape, filepath): writer STEPControl_Writer() # 设置单位为毫米这一步至关重要 Interface_Static_SetCVal(write.step.unit, MM) writer.Transfer(shape, STEPControl_AsIs) writer.Write(filepath) def export_stl(shape, filepath, deflection0.1): writer StlAPI_Writer() # 控制网格精度值越小越精细文件也越大 writer.SetDeflection(deflection) writer.Write(shape, filepath)导出 STEP 时write.step.unit这个参数必须显式设置成MM。如果不设OCCT 会用它内部的默认单位而这个默认值在不同版本里可能不一样导致下游软件读进来的尺寸对不上。这个坑我在一个项目里踩过客户反馈说模型尺寸全错了查了半天才发现是导出单位的问题。导出 STL 时deflection参数控制的是网格化精度它表示弦高偏差——简单说就是三角面片逼近真实曲面的误差上限。值越小面片越密文件越大表面越光滑。对于 3D 打印我一般用 0.1mm对于网页预览0.5mm 就够了能显著减小文件体积。这里没有绝对标准取决于你的用途和对文件大小的容忍度。4. 实测中那些文档不会告诉你的坑4.1 单位混乱最隐蔽也最致命的错误单位问题我在前面提了两次这里单独拿出来讲因为它真的太容易出事了。text-to-cad 的输入是自然语言而自然语言里单位经常是省略的。用户说直径 100他默认是毫米但系统不一定这么认为。如果解析层没有强制单位几何层又用了内核的默认单位最后导出的文件可能整体缩放了一个数量级。我的解决方案是三层单位锁定。第一层在解析时如果用户没写单位根据上下文推断一个默认值机械零件默认毫米建筑默认米并把这个推断明确记录在中间表示里。第二层在几何构建时所有数值统一转换成内核使用的单位OCCT 内部用毫米。第三层在导出时再次显式声明目标文件的单位。三层都锁死基本就不会出问题了。还有一个更隐蔽的情况从 STL 反向导入。STL 不带单位你导入一个别人给的 STL根本不知道它是毫米还是英寸。这时候只能靠尺寸的合理性去猜——如果一个手机壳的模型尺寸是 150那大概率是毫米如果是 5.9那可能是英寸。这种猜测不可靠所以凡是经过 STL 中转的模型都要人工确认一次尺寸。4.2 布尔运算失败几何内核的脾气你得摸清布尔运算是几何建模里最容易出问题的环节没有之一。两个实体做减运算理论上很简单但实际中可能因为各种原因失败面片重合、边相切、微小间隙、自相交等等。OCCT 在这方面的鲁棒性已经算不错了但仍然会有失败的时候。我总结了几条实战经验。第一尽量避免让两个实体的面完全重合。比如你要在一个面上挖一个和面等大的孔这种零厚度的操作极易失败。解决办法是让工具体稍微超出一点比如孔深比板厚多 1mm让布尔运算有明确的相交区域。第二相切是另一个雷区。如果孔的边缘刚好和实体外壁相切会产生退化边导致后续操作失败。这时候要么调整孔的位置留出余量要么接受这个几何并做特殊处理。第三布尔运算的顺序会影响结果。多个工具体时逐个运算通常比一次性运算更稳定虽然慢一点。当布尔运算真的失败了别急着放弃。OCCT 提供了BRepAlgoAPI_Cut的SetFuzzyValue方法可以设置一个模糊容差让内核在判断相交时容忍微小的间隙。这个值一般设成 1e-5 到 1e-4 之间太大反而会引入错误。我遇到过好几次加了模糊容差之后原本失败的运算就成功了。4.3 从自然语言到几何的语义鸿沟这一条是 text-to-cad 特有的坑也是它和传统参数化建模最大的区别。传统建模里参数是人一个个填进去的含义明确。而自然语言里同一个意思可以有无数种说法而且经常有歧义。比如在圆盘上打一圈孔一圈是几个均匀分布还是随意孔径多大这些信息如果用户没说系统就得做假设。假设本身没问题问题是假设必须让用户知道。我的做法是在生成模型的同时输出一份参数说明把系统推断出来的所有默认值列出来让用户确认。这样既保证了自动化又避免了我以为你知道的尴尬。另一个语义鸿沟是空间关系的表达。孔在中心、孔在边缘、孔在四个角这些描述在自然语言里很自然但翻译成坐标就需要一套空间关系的映射规则。我一般会定义几个标准位置中心、四角、边缘均布等然后让解析层把自然语言映射到这些标准位置上。遇到无法映射的描述就报错让用户澄清而不是硬猜。4.4 导出文件在下游软件打不开的排查思路有时候模型在 pythonocc 里检查是有效的导出成 STEP 之后在 SolidWorks 或者中望 CAD 里却打不开或者打开后是空白的。这种情况我遇到过几次排查下来通常是几个原因。第一个原因是导出时没有正确设置单位导致下游软件解析失败。第二个原因是实体本身有微小的几何缺陷OCCT 的检查器没查出来但下游软件的内核更严格。第三个原因是STEP 的版本兼容性不同版本的 STEP 协议AP203、AP214、AP242支持的特性不同有些软件只认特定版本。排查的顺序我一般是先用 FreeCAD 打开试试它对 STEP 的兼容性比较好如果 FreeCAD 能打开说明文件本身没问题是下游软件的问题如果 FreeCAD 也打不开那就是导出环节的问题回去检查单位和实体有效性。另外导出时可以用STEPControl_AsIs之外的模式比如STEPControl_ManifoldSolidBrep强制导出为流形实体兼容性会更好。5. 把 text-to-cad 用起来几个真实场景的落地思路5.1 标准件库的批量生成这是 text-to-cad 最容易见效的场景。很多行业都有大量标准件比如螺栓、螺母、垫圈、法兰、轴承座它们的几何形状固定只是尺寸参数不同。传统做法是一个个建模存成文件几百个规格就是几百个文件管理起来很痛苦。用 text-to-cad 的思路你可以把每个标准件的几何逻辑写成一个函数参数就是规格表里的尺寸。然后写一个脚本读取规格表通常是 Excel 或 CSV循环调用函数生成实体批量导出 STEP。这样一套代码就能覆盖整个系列改一个参数就能重新生成全部。我做过一个项目把某类法兰的 200 多个规格用这种方式生成从写代码到出全部文件半天搞定换成手工建模至少一周。这里的关键是把几何逻辑和参数数据分离。几何逻辑是代码参数数据是表格两者独立维护。这样新增规格只需要改表格不用动代码几何逻辑要调整也只改一处所有规格同步生效。5.2 与现有 CAD 工作流的衔接text-to-cad 生成的是几何文件但实际工作中工程师往往还需要工程图、装配关系、材料属性这些信息。所以它不可能完全替代 CAD 软件而是作为前端快速生成的一环生成的结果再导入 CAD 做后续处理。衔接的时候要注意几点。第一导出的 STEP 要保证特征树干净不要有一堆无用的基准面和草图否则导入 CAD 后特征树会很难看。第二命名要规范实体、面、边的命名最好带上语义信息方便下游识别。第三如果要做装配各个零件的坐标系要统一原点位置要合理否则装配的时候要一个个挪。我一般的做法是text-to-cad 负责生成单个零件的几何导出 STEP然后在 CAD 软件里做装配、出图、加属性。这样分工明确各用各的长处。5.3 面向 3D 打印的快速原型如果你有 3D 打印机text-to-cad 能让你从想法到实物快得惊人。脑子里有个支架的想法用文字描述出来生成 STL切片打印一两个小时就能拿到实物。这种快速迭代的体验是传统建模很难比的。但要注意3D 打印对几何的要求和 CAD 建模不完全一样。打印需要的是封闭的流形网格而 CAD 实体虽然理论上封闭但导出 STL 时如果精度不够可能产生破洞。所以导出 STL 后最好用网格修复工具检查一遍比如用 MeshLab 或者 trimesh 库做一次流形性检查。另外打印还要考虑最小壁厚、悬垂角度这些工艺约束这些在 text-to-cad 阶段就要通过参数约束进去比如强制壁厚不小于 1mm。5.4 在 Web 端做交互式预览如果你的应用需要让用户在浏览器里查看生成的模型GLB 是最佳选择。用 three.js 或者 model-viewer 组件几行代码就能把 GLB 加载出来支持旋转、缩放、剖切。这种交互式预览对于让用户确认模型是否符合预期非常有用。实现路径是text-to-cad 生成实体后先导出 STL 或者直接用 OCCT 的网格化功能生成三角网格再用工具比如 trimesh 或者 assimp转成 GLB。注意 GLB 的坐标系和 CAD 不一样CAD 通常是 Z 轴向上而 glTF 是 Y 轴向上转换的时候要做一次旋转否则模型会躺着。6. 关于 text-to-cad 的几个常见误解6.1 它不是万能建模而是参数化模板的智能前端很多人对 text-to-cad 的期待是我说什么它就能建什么这目前不现实。它的本质是参数化模板 自然语言接口。也就是说底层还是预定义的几何逻辑自然语言只是让你不用手动填参数表。你能生成的模型取决于你预先定义了哪些模板。这个认知很重要因为它决定了你的预期。如果你指望它生成一个从未见过的复杂曲面造型那会失望。但如果你要生成的是标准件、规则几何体、参数化系列产品它能极大提升效率。把预期放对位置才能用好这个工具。6.2 大模型不是必须的规则引擎也能干活现在一提 text-to-cad很多人第一反应是要用大模型。其实不然。如果你的输入句式比较固定比如来自一个表单或者结构化的描述那用规则引擎正则、语法解析完全够用而且更快、更可控、更省钱。大模型的价值在于处理开放式的、多样化的自然语言如果你的场景不需要这个就别为了用而用。我的建议是先用规则引擎把链路跑通验证几何生成和导出的正确性。等这部分稳定了再考虑用大模型替换解析层提升自然语言的理解能力。这样风险可控每一步都有验证。6.3 几何有效性检查不能省这是我最想强调的一点。text-to-cad 的输出是要给下游用的一个无效的实体可能导致 3D 打印失败、CNC 加工撞刀、仿真报错。所以几何有效性检查必须作为流水线的强制环节不能因为大部分时候没问题就跳过。检查的内容包括实体是否封闭BRepCheck_Analyzer、是否有自相交、是否有退化边、体积是否为正。这些检查在 OCCT 里都有现成的 API调用成本很低但能避免大量下游问题。我现在的习惯是任何实体在导出前都必须通过检查不通过就报错绝不带着问题往下走。7. 我在实际项目里沉淀下来的几条经验做 text-to-cad 这段时间最大的体会是几何内核的稳定性决定了整个系统的下限而自然语言解析的准确度决定了上限。下限必须守住上限可以慢慢提升。具体来说几何生成这一层我现在的做法是尽量保守。能用简单几何体组合的就不用复杂曲面能逐个布尔运算的就不批量运算能加模糊容差的就不硬碰硬。宁可生成得慢一点也要保证结果有效。因为一旦几何出问题排查成本极高而且往往是随机复现的非常折磨人。自然语言解析这一层我的策略是宁可多问不可乱猜。遇到模糊的描述与其猜一个可能错的值不如返回一个澄清请求。用户体验上可能多一步交互但避免了生成错误模型再返工的更大成本。我在中间表示里专门留了一个ambiguities字段把所有不确定的地方列出来让用户确认。还有一个细节是日志。text-to-cad 的链路很长从文字到参数到几何到文件中间任何一环出问题都可能导致最终结果不对。所以我在每一环都打了详细的日志原始输入是什么、解析出的参数是什么、几何构建的每一步耗时和结果、导出的文件路径和大小。出问题的时候顺着日志一路查下去很快就能定位。这个习惯帮我省了大量调试时间。最后说一个关于格式选择的心得。如果你的下游是 CAD 软件永远优先给 STEP因为它是唯一保留完整拓扑的格式。如果下游是 3D 打印给 STL但记得确认单位和精度。如果下游是网页展示给 GLB但别拿它去做加工。三种格式各司其职用对了事半功倍用错了就是无尽的麻烦。