
1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词很多人脑子里冒出来的画面是对着电脑敲一句“给我画一个长宽高 100×60×40 的带孔法兰盘”然后屏幕上就自动出现一个可以旋转、可以导出、可以进仿真软件的三维模型。这个画面放在几年前还属于科幻范畴但现在已经有一批开源项目和工具链把它做成了能跑通的流程。我自己是从机械设计转过来的早些年画一个标准件要开 CAD 软件、建草图、拉伸、打孔、倒角一套下来十几分钟就没了重复劳动特别多。后来接触到用代码生成 CAD 的思路再往后看到 text-to-cad 这类方向第一反应就是这东西要是稳定了能省掉大量重复建模的时间。先把概念说清楚。text-to-cad 不是一个具体的软件而是一类“用自然语言描述几何体由程序自动生成 CAD 模型文件”的技术路线。它的输入是一段文本比如“一个外径 80、内径 40、厚度 10 的圆环”输出通常是 STEP、STL、URDF 这类标准格式文件。STEP 是通用三维交换格式几乎所有主流 CAD 软件都能打开URDF 是机器人领域描述连杆和关节的格式常用于仿真STL 则是 3D 打印最常用的网格格式。这几个格式对应了 text-to-cad 的三条主要落地路径机械零件出图、机器人模型搭建、3D 打印快速验证。为什么这件事值得单独拿出来讲因为传统 CAD 建模是“手工活”而 text-to-cad 把它变成了“可编程、可批量、可版本管理”的工程流程。举个最直接的例子你需要 20 个不同孔径的法兰盘传统做法是一个个改参数重画用代码生成的话写一个循环就出来了。再比如机器人仿真URDF 文件里全是数字手写容易出错用文本描述生成再校验效率完全不一样。适合看这篇内容的人有三类一是做机械设计、想摆脱重复建模的工程师二是做机器人仿真、需要批量生成 URDF 的同学三是想用 Python 玩三维建模、但不想学复杂 CAD 软件的开发者。我下面会按“整体设计思路—核心细节—实操流程—问题排查”这条线展开把 text-to-cad 从原理到能跑起来的代码都讲一遍。文中涉及的代码都是 Python依赖主要是 CadQuery 和 build123d 这类基于 OpenCASCADE 的建模库环境配置我会给到具体命令。你不需要有很深的 CAD 背景但最好有一点 Python 基础能看懂函数调用和列表循环就够了。2. 整体设计思路为什么是“文本→代码→几何”这条链路2.1 三种技术路线的取舍逻辑text-to-cad 听起来是一步到位实际上中间隔着好几层。目前主流实现可以归为三类理解这三类的区别你就知道该选哪条路。第一类是规则解析型。程序里预定义了一套语法模板比如“圆柱”“长方体”“圆环”“打孔”这些关键词用户输入文本后用正则或简单分词提取参数再调用建模库生成几何。优点是稳定、可控、不依赖大模型缺点是只能处理预定义的句式稍微换个说法就识别不了。适合固定场景的批量出图。第二类是大模型驱动型。用语言模型把自然语言翻译成建模代码通常是 CadQuery 或 OpenSCAD 的脚本再执行代码生成模型。优点是灵活能处理复杂描述缺点是模型可能“胡说”生成的代码语法错误或几何不合理需要加校验和重试机制。第三类是混合型。先用规则处理高频简单指令复杂描述再交给大模型同时用几何校验兜底。这是目前工程上最靠谱的做法也是我实际项目里采用的方案。选型的时候我踩过一个坑一开始想纯靠大模型结果生成十个模型有三个打不开排查半天发现是布尔运算的顺序错了导致实体自相交。后来加了“生成后必须通过体积和包围盒校验”这一步问题才压下去。所以我的建议是不管走哪条路几何校验环节不能省。2.2 为什么输出格式首选 STEP很多人会问为什么不直接输出 STL 就完事了这里要解释一下。STL 是三角网格只记录表面三角形没有“圆柱面”“平面”这些几何语义也没有参数历史。你拿到一个 STL想改孔径只能重新生成没法在 CAD 里直接编辑特征。STEP 不一样它保留了几何实体的拓扑关系是 B-rep边界表示格式能被 FreeCAD、SolidWorks、中望 CAD 这些软件识别为可编辑实体。所以 text-to-cad 的输出策略通常是主输出 STEP按需转 STL 和 URDF。STEP 作为“源文件”STL 用于 3D 打印URDF 用于机器人仿真。转换用 CadQuery 自带的导出函数就能搞定不需要额外装软件。这个设计的好处是你的文本描述和生成的 STEP 之间是一一对应的改文本重新生成版本管理用 Git 就能做比手动改 CAD 文件靠谱得多。2.3 整体架构拆解一个能用的 text-to-cad 流程我把它拆成四层输入层接收自然语言做基础清洗比如统一单位、去掉口语化词汇。解析层把文本转成结构化的参数或者转成建模代码。建模层调用 CadQuery/build123d 执行几何构建输出实体对象。校验与导出层检查实体是否有效体积大于零、无自相交然后导出 STEP/STL/URDF。这四层里解析层是最容易出问题的建模层是最需要经验的。下面我会重点讲这两层。整个流程用 Python 串起来核心依赖就两个cadquery和build123d前者成熟稳定后者 API 更现代我两个都用过后面会给对比。3. 核心细节解析文本怎么变成几何参数3.1 自然语言到参数的映射规则文本转几何第一步是把“人话”翻译成数字。这里面有几个关键点。单位统一。用户可能说“直径 5 厘米”也可能说“半径 25 毫米”程序必须统一到毫米。我的做法是在解析前先做单位归一化识别“厘米”“米”“英寸”这些词统一换算成毫米。英寸换算系数是 25.4这个别记错。尺寸指代消歧。“一个 100 的方块”这种描述100 到底是边长还是对角线工程上默认是边长。但“一个 100 的圆”就默认是直径。这些约定要在解析规则里写死否则大模型也会犯迷糊。特征顺序。文本里说“带两个孔的板”孔的位置和孔径如果没给就得有默认值。我的默认策略是孔径取板厚的 0.5 倍孔位对称分布。这些默认值不是拍脑袋是参考了常见机械件的比例。下面这张表是我整理的常见描述到参数的映射可以直接拿去用文本描述解析结果默认值策略长方体/方块length, width, height缺失项取已给项的 1 倍圆柱diameter/radius, height半径缺失取高度 0.5 倍圆环outer_d, inner_d, thickness内径取外径 0.5 倍打孔hole_d, count, position孔径取板厚 0.5 倍对称分布倒角radius取最小边长的 0.05 倍3.2 建模库选型CadQuery 还是 build123d这两个库都是基于 OpenCASCADE 的 Python 封装但风格差别很大。CadQuery 用的是链式调用写起来像这样import cadquery as cq result (cq.Workplane(XY) .box(100, 60, 40) .faces(Z) .workplane() .hole(10))build123d 用的是上下文管理器更接近传统 CAD 的操作逻辑from build123d import * with BuildPart() as p: Box(100, 60, 40) with Locations((0, 0, 20)): Hole(radius5)我的实际体验是CadQuery 生态更成熟文档多遇到问题好搜build123d 代码更直观适合复杂装配体。如果你是新手建议从 CadQuery 入手因为网上例子多。如果你要做机器人 URDFbuild123d 对装配和坐标系的支持更顺手。注意两个库不能混用同一个进程OpenCASCADE 的底层句柄会冲突。选一个就用到底。3.3 几何有效性校验的三个指标生成完实体别急着导出先校验。我用的三个指标体积大于零。solid.Volume() 0如果等于零说明实体是空的或者退化了。包围盒合理。solid.BoundingBox()的尺寸应该和输入参数吻合偏差超过 10% 就说明解析或建模有问题。实体数量正确。len(solid.Solids())应该等于预期比如一个带孔的板应该还是一个实体如果变成两个说明布尔运算失败了。这三个检查加起来不到十行代码但能拦下八成以上的错误输出。我见过太多人跳过校验结果导出的 STEP 在 CAD 里打开是空文件白白浪费时间。4. 实操过程从零搭一个能跑的 text-to-cad 脚本4.1 环境准备与依赖安装先把环境弄干净。我推荐用 conda 建虚拟环境避免和系统 Python 冲突。conda create -n text2cad python3.10 conda activate text2cad pip install cadquery build123d这里有个坑CadQuery 在 Windows 上装的时候如果之前装过其他版本的 OpenCASCADE可能会报 DLL 冲突。解决办法是先卸载干净再重装。Linux 上一般没这个问题但要注意libGL这类系统库要装全否则导入会报错。验证安装import cadquery as cq print(cq.__version__)能打印出版本号就说明环境 OK。如果报ImportError八成是 OpenCASCADE 的动态库没找到Windows 上检查 PATHLinux 上用ldd看依赖。4.2 一个最小可用的文本解析器先写一个规则版的解析器处理最常见的几种形状。这段代码可以直接抄import re def parse_text(text): text text.lower().replace( , ) # 单位归一化 if 厘米 in text or cm in text: factor 10 elif 米 in text and 毫米 not in text: factor 1000 else: factor 1 # 提取所有数字 nums [float(n) * factor for n in re.findall(r\d\.?\d*, text)] if 圆柱 in text or 圆 in text: if len(nums) 2: return {type: cylinder, d: nums[0], h: nums[1]} if 方块 in text or 长方体 in text or 板 in text: if len(nums) 3: return {type: box, l: nums[0], w: nums[1], h: nums[2]} return None这个解析器很粗糙但能覆盖“直径 50 高 100 的圆柱”这类描述。实测下来对于格式规整的输入识别率能到七成以上。剩下的复杂描述就得靠大模型或者更细的规则。4.3 建模函数与导出拿到参数字典后调用 CadQuery 建模import cadquery as cq def build_model(params): if params[type] cylinder: solid cq.Workplane(XY).circle(params[d]/2).extrude(params[h]) elif params[type] box: solid cq.Workplane(XY).box(params[l], params[w], params[h]) else: raise ValueError(unsupported type) # 校验 shape solid.val() assert shape.Volume() 0, 体积为零 bb shape.BoundingBox() print(f包围盒: {bb.xlen:.1f} x {bb.ylen:.1f} x {bb.zlen:.1f}) return solid def export(solid, name): cq.exporters.export(solid, f{name}.step) cq.exporters.export(solid, f{name}.stl)跑一遍params parse_text(直径 50 高 100 的圆柱) solid build_model(params) export(solid, test_cylinder)如果一切正常当前目录下会出现test_cylinder.step和test_cylinder.stl。用 FreeCAD 打开 STEP应该能看到一个圆柱体。这一步跑通整个链路就活了。4.4 批量生成与参数扫描text-to-cad 真正的价值在批量。比如你要生成一系列不同孔径的法兰盘for d in [20, 30, 40, 50]: params {type: cylinder, d: d, h: 10} solid build_model(params) export(solid, fflange_d{d})这段代码几秒钟就能生成四个模型手动画的话至少半小时。参数扫描在优化设计里特别有用比如你想看不同壁厚对重量的影响写个循环把体积打出来就行。4.5 URDF 导出与机器人仿真对接如果你做机器人URDF 是绕不开的。URDF 本质是 XML描述连杆的几何、质量、惯性矩阵和关节。text-to-cad 生成的 STEP 可以转成 URDF 里的 mesh 引用也可以直接用基本几何体box、cylinder描述。一个简单的连杆 URDF 片段link namelink1 visual geometry cylinder radius0.05 length0.2/ /geometry /visual collision geometry cylinder radius0.05 length0.2/ /geometry /collision inertial mass value1.0/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.0005/ /inertial /link用 Python 生成这段 XML 不难难的是惯性矩阵的计算。对于圆柱绕中心轴的转动惯量是0.5*m*r^2绕径向是m*(3r^2h^2)/12。这些公式我建议直接写成函数别每次手算。导入 CoppeliaSim 的时候注意 URDF 里的单位是米而 CAD 里通常是毫米导出前记得除以 1000否则模型会大一千倍在仿真里根本看不见。5. 常见问题与排查技巧实录5.1 建模阶段的典型报错问题一布尔运算后实体消失。这通常是因为两个实体没有实际相交或者相减时把整个实体减没了。排查方法是先分别导出两个实体确认它们的位置关系。CadQuery 里可以用translate调整位置后再运算。问题二导出的 STEP 打不开。先检查文件大小如果是 0 字节说明导出失败如果几 KB 但打不开可能是几何无效。用shape.isValid()检查返回 False 就说明有自相交或退化面。修复办法是加clean()或者调整建模顺序。问题三圆角报错。倒圆角是最容易失败的操