
1. 从一段文字到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个词很多人脑子里冒出来的画面大概是对着电脑敲一句“给我画一个法兰盘”然后屏幕上就自动长出一个带螺栓孔的三维实体。这个画面不算离谱但也不完全准确。text-to-cad 本质上是一类把自然语言描述转换成计算机辅助设计模型的技术方案集合它的输出通常不是一张二维图纸而是可以直接进入下游流程的三维几何数据常见格式包括STEP、GLB、STL这几类。我在实际接触这个方向之前一直觉得“文字生成模型”是个偏概念的东西直到自己动手把一条描述跑通、拿到一个能打开的 STEP 文件才意识到它真正有价值的地方不在于“炫”而在于把建模的门槛从“会软件”降到了“会描述”。传统流程里你要做一个零件得先打开 CAD 软件熟悉草图、拉伸、旋转、布尔运算这一整套操作光是找命令就得花不少时间。而 text-to-cad 想做的事情是让描述需求的人直接跳过这些操作细节把精力放在“我要什么”而不是“我怎么画”上。它适合谁来参考我梳理下来大概有三类人。第一类是产品经理、工业设计师这类有明确几何需求但不一定精通建模软件的人他们可以用它快速把想法变成可视化的三维草模方便和团队沟通。第二类是工程师和开发者他们关心的是怎么把这套能力集成到自己的工具链里比如批量生成标准件、自动出图、对接仿真流程。第三类是刚入门 CAD 的学习者通过观察文字到模型的映射关系反过来理解建模里的特征、约束、坐标系这些抽象概念到底是怎么回事。需要先泼一盆冷水text-to-cad 目前还远没到“一句话生成复杂装配体”的程度。它能稳定处理的是结构相对清晰、特征可枚举的零件比如带孔的板、阶梯轴、简单支架、法兰、齿轮毛坯这类。你让它生成一个完整的汽车变速箱那是不现实的。所以理解它的能力边界比盲目吹捧它的上限更重要。下面我会从整体设计思路、核心格式的取舍、实操流程、以及踩过的坑几个角度把这件事讲透。2. 整体设计思路为什么是“文字→几何”而不是“文字→图纸”2.1 核心链路的四个环节把 text-to-cad 拆开看它的处理链路大致是四个环节语义解析 → 几何参数化 → 实体建模 → 格式导出。这四个环节里真正决定成败的是前两个后两个更多是工程实现问题。语义解析这一步要做的是从一段自然语言里抽出几何意图。比如“一个长 100 毫米、宽 60 毫米、厚 10 毫米的板四角各有一个直径 8 毫米的孔孔中心距边缘 12 毫米”这句话里包含了尺寸、形状、特征数量、位置约束这几类信息。解析器需要把它们结构化成一个参数字典类似{shape: plate, length: 100, width: 60, thickness: 10, holes: [{diameter: 8, count: 4, offset: 12}]}这样的形式。几何参数化则是把这些参数映射到具体的建模操作序列上。同样是“板”用拉伸一个矩形草图来做还是用长方体加布尔减运算来做结果一样但过程不同。选择哪种取决于你后面要不要修改、要不要保留特征树。这一步是 text-to-cad 和传统参数化建模之间的桥梁。2.2 为什么输出格式的选择这么关键很多人一开始不重视输出格式觉得“能打开就行”结果到了下游环节才发现问题。STEP、GLB、STL 这三种格式定位完全不同选错了会直接影响你能不能继续往下走。格式本质保留特征树适用场景典型体积STEP边界表示B-rep实体部分保留工程制造、CNC、装配中等GLB三角网格 材质不保留可视化、网页展示、AR较小STL纯三角网格不保留3D 打印、快速原型较大精度高时我个人的经验是只要下游涉及加工、测量、装配一律优先 STEP。因为 STEP 保留的是数学曲面圆柱就是圆柱孔就是孔尺寸是精确的。而 STL 和 GLB 都是把曲面离散成三角面片一个直径 8 毫米的孔在网格里可能变成一圈多边形精度取决于网格密度。你拿 STL 去量孔径量出来永远是个近似值。提示如果你的 text-to-cad 流程最终要对接 3D 打印STL 是通用选择但导出前一定要检查网格是否封闭watertight否则切片软件会报错。2.3 方案选型的三种主流路线目前实现 text-to-cad 大致有三条路线各有取舍。第一条是基于规则模板。预先定义好一批常见零件的模板用户输入的文字通过关键词匹配填进模板参数里。这条路线的优点是稳定、可控、结果精确缺点是覆盖面窄遇到模板外的描述就歇菜。适合做垂直领域的标准件生成比如紧固件、型材、法兰。第二条是基于代码生成。让模型输出一段建模脚本比如 CadQuery、OpenSCAD 的代码再执行脚本生成几何。这条路线的优点是灵活理论上能表达任意可参数化的形状而且生成的代码可读、可改。缺点是对语义理解的要求高脚本一旦有语法或逻辑错误就整个失败。第三条是基于神经网络的直接生成。用深度学习模型直接预测几何表示比如点云、体素、隐式场。这条路线的优点是理论上能处理复杂形状缺点是精度和可编辑性差生成结果往往“看着像但尺寸不对”目前还很难用于实际工程。我在实际项目里用的是第二条路线为主、第一条路线兜底的混合策略常见标准件走模板保证精度和速度非标件走代码生成给用户一个可编辑的起点。这样既不会因为模板覆盖不全而卡死也不会因为纯生成的不确定性导致结果不可用。3. 核心细节解析语义、参数与几何的三角关系3.1 自然语言里的几何信息怎么抽自然语言描述几何有个天然的麻烦人说话是模糊的几何是精确的。你说“厚一点的板”多厚算厚你说“几个孔”几个算几个所以语义解析的第一步是把模糊表达转成明确数值这一步通常需要一套默认规则或者追问机制。我整理了一套在实际中比较管用的抽取维度基本能覆盖大部分简单零件的描述形状词板、块、轴、套、法兰、支架、齿轮、槽、壳尺寸词长、宽、高、厚、直径、半径、角度后面通常跟数值和单位特征词孔、槽、倒角、圆角、螺纹、凸台、加强筋数量词一个、两个、四个、若干、均匀分布位置词中心、边缘、四角、沿轴线、对称、等距约束词平行、垂直、同心、相切、共面把这六类词抽出来基本就能拼出一个零件的参数骨架。比如“一个 200x100x8 的板四角各一个 M6 通孔孔中心距边 15”抽出来就是形状板尺寸200/100/8特征孔×4规格M6位置四角约束距边15。注意单位是重灾区。用户可能说“毫米”也可能说“mm”也可能什么都不说。我的做法是默认毫米但在解析结果里显式标注单位如果用户描述里出现了英寸、厘米就做换算并提示。3.2 参数化建模的“特征顺序”问题拿到参数之后怎么组织建模步骤这里有个容易被忽略的坑特征顺序会影响结果也会影响可修改性。举个简单的例子。你要做一个带孔的板有两种顺序先拉伸整块板再打孔或者先画带孔的草图再拉伸。这两种在几何结果上是一样的但在特征树里完全不同。前者你后面想改孔的位置直接改孔特征就行后者你得回到草图里改如果草图约束没做好一改就乱。我的经验是主体形状用最少的特征做出来细节特征尽量后置。也就是先做毛坯再打孔、倒角、开槽。这样特征树清晰修改起来也方便。text-to-cad 生成代码的时候如果按这个原则组织用户拿到脚本后二次编辑的体验会好很多。3.3 从参数到代码一个可复现的映射示例下面这段是用 CadQuery 风格描述一个带孔板的建模脚本我把它拆开讲一下每个部分对应什么。import cadquery as cq # 主体200x100x8 的板 result ( cq.Workplane(XY) .box(200, 100, 8) # 长宽厚 .faces(Z) # 选顶面 .workplane() # 在顶面建立工作平面 .rect(170, 70, forConstructionTrue) # 构造矩形用于定位孔 .vertices() # 取四个角点 .hole(6) # 每个角点打直径6的孔 ) cq.exporters.export(result, plate.step)这段代码里box对应“板”这个形状和三个尺寸faces(Z)是选面操作rect加vertices是定位孔的常用手法hole(6)是打孔。整个逻辑和前面说的“先主体后细节”是一致的。实际写的时候孔的位置计算是最容易出错的。上面用构造矩形加顶点的方式是因为“四角各一个孔、距边15”这个描述转换成坐标就是四个点(15,15)、(185,15)、(15,85)、(185,85)。用构造矩形的方式可以避免手算坐标但如果描述里给的是“距边15”而板是200x100那构造矩形就应该是 (200-30) x (100-30) 170x70这个减法很容易漏。提示凡是涉及“距边”“内缩”“偏移”的描述都要做一次尺寸减法建议在代码里把原始尺寸和偏移量都写成变量方便核对。4. 实操过程从一句话到可用的 STEP 文件4.1 环境准备与工具链搭建要跑通一条 text-to-cad 的链路环境上需要几样东西一个能执行建模脚本的内核、一个语义解析的入口、以及格式导出的支持。我用的组合是 Python CadQuery 做几何内核前面接一个轻量的语义解析层导出用 CadQuery 自带的 exporter。安装 CadQuery 这一步实测下来最省事的方式是用 conda 建一个独立环境避免和系统里的其他包打架。conda create -n text2cad python3.11 conda activate text2cad conda install -c conda-forge cadquery装完之后验证一下能 import 并且能导出一个简单的盒子就说明环境没问题。import cadquery as cq box cq.Workplane(XY).box(10, 10, 10) cq.exporters.export(box, test.step)这里有个坑要提前说CadQuery 依赖 OCP 这个几何内核在某些系统上装的时候会因为编译工具链缺失而失败。如果 conda 装不上可以试试 pip但 pip 版本对系统依赖更敏感。我遇到过在干净系统上 pip 装完 import 报错的情况最后还是回到 conda 解决的。4.2 语义解析层的实现思路语义解析层不需要一上来就搞得很复杂。我的做法是先做一个基于正则和关键词的解析器把常见的描述模式覆盖掉跑通之后再考虑要不要上模型。核心逻辑是分两步先识别形状再抽取该形状对应的参数。因为不同形状关心的参数不一样板关心长宽厚轴关心直径和长度法兰关心外径、内径、厚度和孔数。用一个统一的解析器去处理所有形状反而容易乱。import re def parse_plate(text): # 抽取三个尺寸 nums re.findall(r(\d(?:\.\d)?)\s*(?:mm|毫米)?, text) # 抽取孔信息 hole_match re.search(r[MΦφ]?(\d(?:\.\d)?)\s*(?:的)?(?:通孔|孔), text) hole_dia float(hole_match.group(1)) if hole_match else None return { shape: plate, dims: [float(n) for n in nums[:3]], hole_dia: hole_dia }这段代码很粗糙但能跑通基本流程。实际用的时候我会把“四角”“中心”“均匀分布”这些位置词也解析出来映射到不同的打孔策略上。注意正则抽取数字的时候要小心把“M6”里的6和尺寸数字混在一起。我的做法是先把螺纹规格、孔规格这类带前缀的数字单独抽走再从剩下的文本里抽纯尺寸。4.3 生成、校验、导出三步走拿到参数之后生成几何、校验、导出这三步我建议分开做不要一口气跑完。因为一旦出错你需要知道是哪一步的问题。生成阶段就是把参数填进建模脚本执行得到几何对象。校验阶段要检查几件事几何是否有效valid、体积是否为正、有没有自相交。CadQuery 提供了isValid()方法导出前跑一下能挡掉不少低级错误。result build_plate(params) if not result.val().isValid(): raise ValueError(生成的几何无效请检查参数) cq.exporters.export(result, output.step)导出阶段要注意格式和精度。STEP 导出一般不用额外设置STL 导出则要指定线性公差和角度公差这两个参数直接决定网格密度和文件大小。cq.exporters.export(result, output.stl, tolerance0.01, angularTolerance0.1)tolerance0.01表示线性偏差不超过 0.01 毫米angularTolerance0.1表示角度偏差不超过 0.1 弧度。这两个值越小网格越密文件越大。做 3D 打印的话0.01 到 0.05 之间比较合适做网页展示可以放宽到 0.1 以上。4.4 一次完整的实操记录我拿一个实际例子走一遍。输入描述是“一个 120x80x6 的安装板四角各一个直径 5 的通孔孔中心距边 10另外在板中心开一个 40x20 的腰形槽。”解析结果形状板尺寸120/80/6孔直径5×4孔位距边10槽40x20 中心。建模脚本按“先主体、后孔、再槽”的顺序组织。主体用 box孔用构造矩形加顶点定位槽用 slot2D 或者矩形加圆角的方式做。这里腰形槽我用的是slot2D因为它的语义就是“腰形”比用矩形加两个圆再布尔运算简洁得多。result ( cq.Workplane(XY) .box(120, 80, 6) .faces(Z).workplane() .rect(100, 60, forConstructionTrue).vertices().hole(5) .faces(Z).workplane() .slot2D(40, 20).cutThruAll() )跑完之后校验通过导出 STEP 和 STL 各一份。STEP 文件用 FreeCAD 打开尺寸量下来和描述一致STL 丢进切片软件网格封闭没有报错。整个过程从输入到拿到文件熟练之后大概两三分钟。5. 常见问题与排查技巧实录5.1 生成失败的五种典型情况实操中遇到的失败我归了归类基本逃不出下面这五种。现象可能原因排查方向解决思路脚本报语法错误参数缺失或类型不对打印解析结果补默认值或加校验几何为空尺寸为0或负检查尺寸抽取加正数校验孔打不出来工作平面选错确认选面逻辑显式指定面导出文件打不开几何无效跑 isValid修复或重建尺寸对不上单位或减法错误核对原始描述统一单位、显式变量这五类里尺寸对不上是最隐蔽的因为文件能打开、看着也正常但量出来就是差一点。我踩过最典型的一次是“距边10”我直接用了10作为孔中心坐标忘了板是120宽另一侧的孔应该是110而不是120-10算错成别的值。后来我养成了一个习惯所有涉及偏移的尺寸都在代码里写成edge_offset变量坐标用length - edge_offset表达一眼就能看出对不对。5.2 精度与文件体积的平衡STL 的体积问题在实际项目里很突出。一个简单的板公差设 0.001 的时候能到几十兆设 0.05 的时候只有几百K。这个差异在单个文件上不明显但如果你要批量生成几百个零件差距就出来了。我的经验值是功能验证阶段用 0.05最终交付用 0.01网页展示用 0.1。另外STL 是纯网格没有压缩如果只是传输和展示GLB 会更合适它支持 Draco 压缩体积能小一个数量级。提示GLB 导出的时候记得检查法线方向有些内核导出的网格法线是反的在网页里渲染出来会是黑的。CadQuery 导出 GLB 一般没问题但如果中间经过了格式转换就要留个心眼。5.3 批量生成时的性能问题单个零件生成很快但批量跑的时候性能瓶颈往往不在建模本身而在进程启动和内核初始化上。CadQuery 每次 import 和初始化内核都要花时间如果你用子进程逐个跑开销会很大。我的做法是把批量任务放在一个进程里复用同一个内核实例只把参数循环传入。实测下来一百个简单零件从几分钟降到几十秒。如果任务量更大可以考虑用多进程但要注意每个进程独立初始化内核内存占用会上去。5.4 几个容易被忽略的细节第一个是坐标系约定。不同工具对“上”方向的定义不一样有的 Z 向上有的 Y 向上。text-to-cad 生成的模型如果方向不对导入下游软件后可能要重新摆正。我的做法是在导出前统一把模型摆到 Z 向上的标准姿态。第二个是命名。批量生成的文件如果都叫 output.step管理起来是灾难。建议用“形状_尺寸_时间戳”的规则命名比如plate_120x80x6_20240101.step一眼能看出内容。第三个是日志。每次生成都记一条日志包含输入描述、解析结果、输出路径、是否成功。出问题的时候翻日志比重新跑一遍快得多。6. 格式转换与下游对接的实战经验6.1 STEP 转 STL 的正确姿势很多人以为 STEP 转 STL 就是换个后缀其实中间有个网格化的过程质量完全取决于转换参数。我见过有人转出来的 STL 圆柱面是明显的多边形就是因为公差设太大了。转换的时候线性公差建议不超过模型最小特征的十分之一。比如模型上最小的孔是直径 2 毫米那线性公差最好在 0.02 以下否则孔的圆度会明显失真。角度公差一般 0.1 到 0.5 弧度之间太小了文件会爆。6.2 STL 转 STEP 的可行性与局限反过来STL 转 STEP 是可行的但结果和原始 STEP 完全不是一回事。STL 转出来的 STEP 是一堆三角面片拼成的壳体不是实体也没有特征树。你没法在上面直接改孔的位置因为根本没有“孔”这个特征只有一堆三角形。如果下游必须要实体STL 转 STEP 之后还得做一步曲面重建把三角网格拟合成光滑曲面。这一步工具不少但自动化程度参差不齐复杂形状基本要人工介入。所以我的建议是能拿到 STEP 就别用 STL 转从源头保证格式正确比事后补救省事得多。6.3 对接 3D 打印的注意事项3D 打印对模型的要求主要是封闭和流形。封闭指的是网格没有缺口流形指的是每条边恰好被两个面共享。text-to-cad 生成的模型如果经过了布尔运算有时候会在交界处产生微小的缝隙或重叠面这些在 CAD 里看不出来但切片软件会报错。我的检查流程是导出 STL 后用网格修复工具跑一遍自动检测有问题的自动修修不了的标记出来人工看。这一步花不了多少时间但能挡掉大部分打印失败。6.4 对接可视化与网页展示如果模型是要放到网页上给人看的GLB 是首选。它把几何、材质、层级打包在一个文件里加载方便。但要注意两点一是面数控制网页渲染对三角面数量敏感超过几十万面就会卡二是坐标系网页里通常是 Y 向上和 CAD 的 Z 向上不一致导出时要做旋转。我一般的做法是CAD 里保持 Z 向上导出 GLB 的时候做一次坐标变换把 Z 向上转成 Y 向上。这样两边都符合各自的习惯不用在网页代码里再转。7. 我对 text-to-cad 的一点实际体会折腾这个方向有一段时间了最大的感受是它现在的价值不在于替代建模而在于加速“从想法到草模”的那一段。真正复杂的零件还是得靠人来做因为很多设计意图是文字描述不出来的比如“这里要留个工艺圆角”“这个面要配合另一个零件”。但那些结构清晰、参数明确的标准件和非标简单件用文字生成确实能省下大量重复劳动。另一个体会是语义解析的准确率决定了整个流程的可用性。几何内核再强如果解析出来的参数是错的结果就是错的。所以我在解析层上花的时间比建模层多得多各种边界情况、单位混用、描述歧义都得一条条处理。这件事没有捷径就是靠实际用例堆出来的。最后分享一个小技巧如果你也在做类似的东西建议先把输入描述的格式约定好哪怕只是内部约定。比如统一用“形状 尺寸 特征 位置”的顺序描述解析起来会稳定很多。完全自由的描述虽然听起来美好但实际处理起来歧义多到让人崩溃。约束一下输入反而能让整个系统跑得更顺。