text-to-cad 实战:从自然语言到参数化三维模型的工程化落地 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个说法是在一个做机械设计的朋友那里。他当时正对着屏幕上一堆拉伸、旋转、倒角特征发愁嘴里念叨着“要是能直接打一行字模型就自己长出来该多好。” 这句话其实点中了传统 CAD 工作流里最耗时的环节——从设计意图到几何特征的翻译过程。text-to-cad直译就是“文本转 CAD”它要干的事情非常直接把你用自然语言描述的一个零件、一个结构、甚至一个装配体自动或半自动地转换成可编辑的三维 CAD 模型文件。这个方向最近一年热度上升得很快原因也不复杂。大语言模型在代码生成、结构化输出上的能力越来越稳而 CAD 领域恰好有一套非常成熟的参数化建模体系两者一结合就出现了“用文字驱动几何”的可行性。它解决的核心痛点有三个第一降低 CAD 软件的上手门槛让不熟悉草图约束、特征树逻辑的人也能快速得到模型第二加速概念设计阶段的迭代设计师不用从零画草图而是先拿到一个可编辑的初版再在上面改第三打通文本需求与制造数据之间的断点比如产品经理写了一句“一个 80x60x10 的安装板四角各一个 M4 沉头孔”这句话可以直接变成模型而不是靠人再翻译一遍。适合关注这个内容的人其实比想象中广。做机械结构设计的工程师可以把它当成快速原型工具做创客、DIY 硬件的人可以用它生成简单外壳和支架做工业设计、建筑概念方案的人可以拿它做体量推敲甚至做机器人仿真、游戏资产生成的人也能用它批量产出基础几何体。当然如果你期待的是“说一句话就得到一个能直接开模的精密零件”那目前还不太现实但如果你需要的是快速拿到一个结构合理、尺寸可控、可继续编辑的 CAD 初稿text-to-cad 已经能帮上不少忙了。我接下来会从整体设计思路、核心技术细节、实操落地流程、常见坑与排查方法几个层面把这个方向拆开讲清楚。内容会尽量贴近实际工程视角不堆概念重点放在“为什么这么设计”和“实际怎么跑通”上。2. 整体设计与思路拆解为什么不是直接生成网格而是走参数化路线2.1 两条技术路线的取舍网格生成 vs 参数化特征在 text-to-cad 这个方向里最上层的分叉其实只有两条路。一条是直接生成三角网格也就是常说的 mesh 或 STL 那一类另一条是生成参数化特征序列最终输出 STEP、IGES 或者原生 CAD 文件。这两条路看起来只是输出格式不同但背后的工程逻辑差别非常大。直接生成网格的思路可以类比成“雕刻”。模型是一堆三角面片拼出来的形状可以很自由曲面也能做得很复杂。很多基于隐式场、点云、神经辐射场的方案走的就是这条路。它的优点是生成速度快对复杂有机形状友好适合做视觉展示、3D 打印预览。但问题也很明显网格模型没有特征历史。你拿到一个 STL 之后想改一个孔的直径基本只能重新做布尔运算或者重新生成没法像在 SolidWorks、Fusion 360 里那样双击一下尺寸就改掉。对于工程用途来说这个缺点几乎是致命的。参数化路线则完全不同。它生成的是一串建模操作序列先画一个矩形草图拉伸 10mm然后在四个角打孔孔型是沉头直径 4.5mm沉头角 90 度。这串操作可以被 CAD 内核逐条执行最终得到一个带特征树的模型。用户拿到之后可以直接修改任意一步的参数整个模型会自动重建。这才是工程上真正可用的东西。所以目前 text-to-cad 里真正有落地价值的方案基本都走参数化路线或者至少是“参数化为主、网格为辅”的混合路线。注意如果你只是要做视觉展示或者 3D 打印一个摆件网格路线完全够用但只要涉及后续修改、装配、出工程图就必须优先考虑参数化输出。2.2 为什么中间层要用“结构化中间表示”从自然语言到最终 CAD 文件中间其实隔着好几层翻译。如果让大语言模型直接输出 STEP 文件的文本内容基本不可行因为 STEP 的语法太底层、太冗长模型很容易在细节上出错。更合理的做法是定义一个结构化的中间表示让模型先输出这个中间层再由确定性的代码把它翻译成 CAD 内核能执行的命令。这个中间表示通常是一个 JSON 或类似的结构里面描述了几何体的类型、尺寸、位置、布尔关系、特征参数等。比如一个带孔安装板的中间表示可能长这样{ type: plate, width: 80, height: 60, thickness: 10, features: [ { type: hole, pattern: rectangular, count: 4, diameter: 4.5, counterbore: { diameter: 8, depth: 4.5 }, margin: 8 } ] }这样做的好处非常明显。第一大语言模型只需要负责它擅长的事情——理解语义、抽取参数、组织结构而不需要去处理复杂的几何内核语法。第二中间表示可以被校验。比如孔的位置不能超出板子边界沉头深度不能大于板厚这些规则可以用代码写死在生成最终模型之前就拦截掉错误。第三中间表示和具体 CAD 内核解耦今天用某个开源内核明天换成商业内核只需要换翻译层上层逻辑不用动。2.3 整体架构的分层设计把整个 text-to-cad 流程拆开大致可以分成四层。最上面是输入理解层负责把用户那句自然语言解析成结构化的设计意图。这一层要处理的问题包括识别零件类型、抽取尺寸、理解特征描述、处理单位、消解歧义。比如“一个 80 乘 60 的板子厚 10 毫米四角打 M4 沉头孔”这里“M4”需要被翻译成公称直径 4mm 的螺纹孔沉头尺寸要根据标准查表得到。第二层是中间表示层也就是上面说的结构化 JSON。这一层的关键是定义一套足够表达常见零件特征的 schema同时保持可扩展。schema 设计得太窄稍微复杂一点的零件就表达不了设计得太宽模型又容易生成出无效结构。实际项目中通常会先覆盖拉伸、旋转、孔、圆角、倒角、阵列、布尔运算这几类基础特征再逐步扩展。第三层是几何执行层负责把中间表示翻译成具体 CAD 内核的 API 调用。这一层是确定性的代码不涉及模型推理。常用的开源内核有 OpenCASCADE、CadQuery、Build123d 等商业的则有 Parasolid、ACIS 等。选择哪个内核主要看输出格式要求、授权成本和团队熟悉程度。第四层是输出与校验层负责导出 STEP、STL、DXF 等格式同时做几何有效性检查比如是否封闭、是否有自相交、壁厚是否过薄。这一层往往被新手忽略但在实际使用中非常关键因为一个看起来没问题的中间表示执行出来可能是破面或者零厚度实体。2.4 方案选型的几个关键考量在实际搭建 text-to-cad 流程时有几个选型决策会直接影响后续的开发效率和最终效果。第一个是用通用大模型还是微调专用模型。通用模型在语义理解上更强但输出格式的稳定性需要靠提示词工程和输出校验来保证微调模型在特定零件类型上更稳但泛化能力会下降。我的经验是早期先用通用模型加严格 schema 约束等积累了一定量的失败案例再考虑做轻量微调。第二个是中间表示的粒度。粒度太粗比如只描述“一个板”那后续可编辑性就很差粒度太细比如直接描述每一条边模型又容易出错。比较合理的粒度是特征级也就是以孔、槽、凸台、圆角这样的加工特征为单位来描述。第三个是是否引入检索增强。很多常见零件其实有标准结构比如法兰、支架、外壳。如果能在生成之前先从标准件库里检索到相似结构再让模型做参数适配成功率会明显提高。这个思路在工业场景里特别实用因为大量设计其实是变型设计而不是从零创新。3. 核心细节解析与实操要点从文本到几何的关键环节3.1 输入文本的规范化处理用户输入的那句话往往是不完整、有歧义、甚至带口语的。比如“做个大概 100 长的支架孔随便打几个”这种描述直接丢给模型结果基本不可控。所以在进入模型之前需要做一轮输入规范化。这一步的目标不是替用户做设计决策而是把模糊描述转成可执行的约束。具体操作上我会先做单位统一。如果用户没写单位默认按毫米处理同时在返回结果里明确标注“未指定单位按毫米处理”。然后是尺寸补全对于缺失的关键尺寸要么给出合理默认值要么明确提示用户补充。比如“一个板子四角打孔”没有长宽厚那就需要追问或者用常见默认值先出一版。还有一个容易被忽略的点是特征顺序。自然语言里描述特征时顺序往往和实际建模顺序不一致。比如“一个带圆角的板上面有四个孔”实际建模时通常是先拉伸板再打孔最后倒圆角。如果顺序搞反圆角可能会和孔相交导致几何失败。所以在规范化阶段需要把特征按合理的建模顺序重排。实操心得我通常会在提示词里明确要求模型按“基础体 - 减材特征 - 倒角圆角”的顺序输出中间表示这样执行成功率会高很多。3.2 尺寸与公差的合理推断text-to-cad 目前最大的短板之一是对公差和配合的理解。用户说“一个轴和一个孔配合”模型可以生成轴和孔但配合公差是间隙配合、过渡配合还是过盈配合模型基本靠猜。在实际工程里这个信息往往比几何形状本身更重要。我的处理方式是在中间表示里预留公差字段但默认不自动填充而是标注为“待定”。如果用户明确说了“松配合”或者“能转动就行”那就按间隙配合给一个推荐值比如 H8/f7。如果用户没说就在输出结果里提示“配合公差未指定建议根据实际工况确认”。这样做虽然不能完全解决问题但至少不会让用户误以为模型已经考虑了装配要求。另一个相关问题是螺纹孔的表达。很多 text-to-cad 方案会把 M4 螺纹孔简化成一个直径 4mm 的光孔。这在视觉上没问题但导出工程图或者做装配干涉检查时就不对了。更合理的做法是在中间表示里区分“螺纹孔”和“光孔”螺纹孔按小径生成几何同时附带螺纹标注信息。如果目标 CAD 内核支持螺纹特征就直接生成螺纹如果不支持至少要在属性里保留螺纹规格。3.3 特征树的组织与可编辑性保障参数化 CAD 的核心价值在于特征树。一个 text-to-cad 方案好不好用很大程度上取决于它生成的特征树是否干净、可读、可修改。我见过一些方案生成的模型虽然形状对了但特征树里是一堆无意义的布尔运算和孤立草图用户根本没法改。要保证可编辑性有几个细节必须注意。第一草图要尽量简单且约束完整。比如一个矩形草图应该用水平和垂直约束加上尺寸标注而不是用四个自由点连起来。第二特征命名要有意义。不要用“Extrude1”“Cut2”这种默认名而是用“底板拉伸”“安装孔阵列”这样的名字。第三避免过度布尔运算。能用特征直接做的就不要用布尔加加减减因为布尔运算会破坏特征历史。在实际实现中这一层往往需要在中间表示里就体现出来。比如每个特征对象都带一个name字段和一个order字段执行层按 order 排序按 name 命名。这样生成出来的模型用户打开特征树一看就明白每一步在干什么。3.4 几何有效性校验的必备检查项模型生成出来之后不能直接丢给用户必须先过一遍几何有效性检查。这一步在开源内核里尤其重要因为不同内核的容差处理不一样同样的操作在一个内核里成功在另一个里可能就产生破面。我通常会检查以下几项。第一实体是否封闭。用内核的isValid()或者isClosed()接口判断如果不封闭说明有破面或者零厚度区域。第二是否有自相交。特别是做布尔减运算之后孔和边缘距离太近时容易出问题。第三最小壁厚。对于注塑件或者 3D 打印件壁厚太薄会导致制造失败一般建议不小于 1mm具体看工艺。第四特征是否完全定义。在参数化模型里如果草图有欠约束后续修改时形状会乱跑。这些检查项可以写成一个校验清单每次生成后自动跑一遍把不通过的项和原因返回给用户。虽然不能保证 100% 正确但能拦掉大部分低级错误。4. 实操过程与核心环节实现手把手跑通一条 text-to-cad 流水线4.1 环境准备与工具链选择要自己搭一条 text-to-cad 流水线工具链的选择其实没有唯一答案但有一条原则尽量用成熟的开源组件把精力集中在中间表示和提示词工程上。下面是我实际用过的一套组合供参考。环节工具/库选择理由文本理解通用大语言模型 API语义理解强迭代快中间表示校验JSON Schema 自定义规则轻量易扩展几何执行CadQuery / Build123dPython 生态好文档全内核OpenCASCADE开源STEP 支持完善输出校验内核自带检查 自定义规则覆盖常见几何问题可视化预览导出 STL 轻量查看器方便快速确认形状这套组合的好处是全部可以在 Python 环境里跑通不需要装庞大的商业 CAD 软件。CadQuery 的 API 比较直观适合做中间表示到几何的翻译层。Build123d 更接近传统 CAD 的操作逻辑如果你熟悉特征建模用起来会更顺手。注意OpenCASCADE 的容差比较敏感做布尔运算时如果两个面几乎相切很容易失败。实际使用中建议在中间表示阶段就把可能相切的特征拉开一点距离比如孔边到板边至少留 1mm 余量。4.2 提示词设计与中间表示生成提示词的设计直接决定了中间表示的质量。我的做法是把 schema 定义和几个示例一起放进系统提示词让模型明确知道输出格式。示例要覆盖常见零件类型比如板类、轴类、支架类每个示例都展示完整的 JSON 结构。一个简化的系统提示词骨架大概是这样你是一个 CAD 中间表示生成器。用户会用自然语言描述一个零件 你需要输出一个 JSON 对象描述这个零件的几何特征。 JSON 必须符合以下结构 { part_name: string, units: mm, base: { ... }, features: [ ... ] } base 支持的类型plate, cylinder, box features 支持的类型hole, slot, fillet, chamfer, pattern 规则 1. 所有尺寸默认单位为毫米。 2. 特征按建模顺序排列先基础体再减材最后倒角圆角。 3. 孔的位置用相对于基础体中心的坐标表示。 4. 如果用户未指定某个尺寸使用合理默认值并在 notes 中说明。实际使用中我会在提示词里再加两到三个完整示例覆盖“带孔板”“阶梯轴”“L 型支架”这三种常见结构。这样模型输出的稳定性会明显提高。生成之后先用 JSON Schema 做格式校验再用自定义规则做语义校验比如孔是否在板内、沉头深度是否小于板厚。4.3 从中间表示到 CadQuery 代码的翻译中间表示校验通过之后下一步就是把它翻译成 CadQuery 代码并执行。这一步是确定性的不需要模型参与。下面是一个简化的翻译示例对应前面那个带沉头孔安装板的中间表示。import cadquery as cq def build_plate(spec): # 基础板 plate cq.Workplane(XY).box( spec[width], spec[height], spec[thickness] ) # 提取孔特征 hole_spec None for f in spec[features]: if f[type] hole: hole_spec f break if hole_spec: margin hole_spec[margin] x_offset spec[width] / 2 - margin y_offset spec[height] / 2 - margin # 四个角的位置 positions [ (x_offset, y_offset), (-x_offset, y_offset), (-x_offset, -y_offset), (x_offset, -y_offset), ] # 沉头孔 cb hole_spec[counterbore] plate ( plate.faces(Z).workplane() .pushPoints(positions) .cboreHole( hole_spec[diameter], cb[diameter], cb[depth] ) ) return plate result build_plate(spec) cq.exporters.export(result, mounting_plate.step)这段代码的关键点在于孔的位置计算要基于基础体的实际坐标系而不是想当然地放在原点。很多生成失败的情况都是因为位置计算和基础体的局部坐标系对不上。另外cboreHole的参数顺序是“孔直径、沉头直径、沉头深度”写反了会直接报错。4.4 参数计算与默认值选取的实际案例举一个具体的例子用户输入是“做一个 120 毫米长、80 毫米宽、8 毫米厚的安装板四角各一个 M5 沉头孔孔中心距边 10 毫米。”这里需要做的参数计算有几项。第一M5 螺纹孔的公称直径是 5mm但实际底孔直径通常按 4.2mm 或 4.5mm 取具体看材料。在几何建模阶段如果只是做形状可以直接用 5mm 表示如果要出工程图就需要标注螺纹规格。第二M5 沉头螺钉的沉头直径标准值一般是 9.3mm 到 10mm沉头角 90 度。在中间表示里我会取沉头直径 10mm沉头深度按板厚 8mm 的 60% 取也就是 4.8mm但不超过板厚减去最小剩余壁厚。第三孔中心距边 10mm意味着孔中心坐标是 (50, 30) 这样的值因为板中心在原点半长 60半宽 40减去 10 得到 50 和 30。这些计算看起来简单但实际写代码时很容易搞错正负号和坐标系方向。我的习惯是在中间表示里统一用“相对于基础体中心”的坐标然后在翻译层里根据基础体的实际位置做偏移。这样即使基础体不在原点孔的位置也不会错。4.5 输出格式选择与导出注意事项最后一步是导出。常见的输出格式有 STEP、STL、DXF、IGES 等。STEP 是参数化模型的首选因为它保留了 B-Rep 表示可以被大多数 CAD 软件读取和编辑。STL 只适合 3D 打印和视觉预览没有特征信息。DXF 主要用于二维图纸如果用户需要的是钣金展开图或者激光切割图可以额外导出。导出 STEP 时有一个细节要注意单位。OpenCASCADE 默认单位是毫米但有些导出接口会按米处理导致模型缩小 1000 倍。实际使用中建议在导出后用一个简单的尺寸检查确认一下比如量一下包围盒的长宽高是否和预期一致。如果不对检查导出参数里的单位设置。另外如果模型里有螺纹特征STEP 导出时通常不会保留螺纹的几何细节只会保留光孔。这是正常现象因为 STEP 的螺纹表示方式在不同软件里兼容性不好。如果需要螺纹信息建议在文件属性或者单独的标注文件里说明。5. 常见问题与排查技巧实录踩过的坑和绕过的路5.1 模型生成失败的高频原因速查在实际跑 text-to-cad 流程时失败是常态成功才是意外。下面这张表整理了我遇到过的最高频的几类问题以及对应的排查方向。现象可能原因排查方法布尔运算失败特征相切或重叠检查孔边距、圆角半径是否过大导出 STEP 后模型为空实体未封闭用isValid()检查查看破面位置尺寸整体偏大/偏小单位不一致检查中间表示和导出参数的单位孔位置错乱坐标系方向搞反确认基础体局部坐标系和孔坐标定义特征树全是默认名中间表示缺少 name 字段在 schema 里强制要求命名圆角导致模型破面圆角半径大于相邻边减小圆角半径或调整特征顺序这张表里的每一行背后都是至少一次实际调试。比如“布尔运算失败”这一项最常见的情况是孔打得太靠边孔壁和板边之间只剩零点几毫米内核在计算时容差处理不过来直接报错。解决办法很简单在中间表示校验阶段就加一条规则孔边到板边的最小距离不小于 1mm不满足就自动调整或者提示用户。5.2 提示词不稳定导致的输出波动用通用大模型做中间表示生成最大的问题就是输出不稳定。同样的输入今天生成的结构合理明天可能就多了一个莫名其妙的特征。这种波动在早期特别让人头疼因为你会以为是代码有问题其实是模型在“自由发挥”。我的应对策略有三条。第一降低温度参数。把生成温度调到 0.1 到 0.3 之间输出会稳定很多。第二在提示词里加负面约束。比如明确写“不要生成用户未提到的特征”“不要自行添加圆角或倒角”。第三做输出后处理。即使模型多生成了特征也可以在中间表示校验阶段过滤掉只保留用户明确要求的和合理推断的。还有一个技巧是用少样本示例锚定输出风格。在提示词里放两到三个完整示例模型会倾向于模仿示例的结构和详细程度。示例不要太多三到五个就够了太多会占用上下文窗口反而影响理解。5.3 几何内核的容差与精度问题OpenCASCADE 的容差默认是 1e-7 米也就是 0.0001 毫米。这个精度对于大多数机械零件够用但在做微小特征或者大尺寸模型时可能会出问题。比如一个 1000mm 长的板上面打一个 1mm 的孔内核在计算时可能会因为数值精度导致孔变形或者布尔失败。实际使用中如果遇到这类问题可以尝试几个方向。第一调整内核容差。OpenCASCADE 允许在操作时指定容差适当放宽容差可以提高成功率但会牺牲一点精度。第二分步执行。不要一次性做所有布尔运算而是分步做每步之后检查有效性。第三避免极端比例。如果模型里同时有米级尺寸和微米级特征考虑拆成多个零件分别建模最后再装配。实操心得我通常会在中间表示里加一条规则如果最大尺寸和最小特征尺寸的比例超过 1000:1就提示用户拆分模型。这个比例不是绝对的但超过之后出问题的概率明显上升。5.4 可编辑性丢失的补救方法有时候模型生成出来了形状也对但特征树一团糟根本没法改。这种情况在早期方案里很常见因为模型倾向于用最少的操作生成形状而不是用最合理的特征结构。补救方法有两个方向。第一个方向是在中间表示阶段就强制特征结构化。比如要求每个孔必须作为独立特征存在而不是合并成一个布尔运算。这样翻译层就会按特征逐个执行生成的特征树自然就清晰。第二个方向是后处理重建。如果已经生成了一个乱糟糟的模型可以尝试用特征识别工具反推特征但这在开源工具里支持有限效果也不稳定。更实际的做法是把可编辑性作为生成质量的一等指标。在评估一个 text-to-cad 方案时不要只看形状对不对还要看特征树是否干净、草图是否约束完整、命名是否有意义。这些指标虽然不能完全自动化评估但可以通过人工抽查来把关。5.5 从失败案例中积累规则库跑 text-to-cad 时间长了你会发现很多失败其实是重复的。今天这个孔打失败了明天换个零件还是同样的原因。所以我会建议建一个规则库把每次失败的原因和对应的校验规则记下来逐步加到中间表示校验层里。比如最开始没有检查孔边距失败几次之后加上了后来发现沉头深度超过板厚也会失败又加上了再后来发现圆角半径大于相邻边长度会破面继续加。这个规则库不需要很复杂用简单的 if-else 或者 JSON Schema 的约束就能表达。关键是持续积累每踩一个坑就补一条规则时间长了生成成功率会明显提升。这个思路其实和软件工程里的回归测试很像。每次修复一个 bug就加一个测试用例防止以后重新引入。text-to-cad 的规则库就是几何领域的回归测试只不过测试的不是代码逻辑而是几何有效性。6. 这个方向后续还能怎么扩展跑通基础流程之后text-to-cad 其实还有很多可以延伸的方向。一个比较自然的扩展是装配体生成。现在大多数方案只能生成单个零件但实际设计里更多是多个零件的配合。如果能用自然语言描述一个装配关系比如“一个轴穿过两个轴承座两端用卡簧固定”然后自动生成装配体和配合约束那价值会大很多。这个方向的难点在于装配约束的表达和求解比单零件复杂不少。另一个方向是与工程图联动。生成三维模型之后自动投影出二维工程图标注关键尺寸和公差。这个在商业 CAD 里是标配但在 text-to-cad 流程里还很少见。如果能做到“一句话生成模型加图纸”对非专业用户来说会非常友好。还有一个我觉得很有意思的方向是基于制造约束的自动优化。比如用户说“这个零件要 3D 打印”那生成模型时就可以自动检查悬垂角、最小壁厚、支撑需求甚至自动调整方向。如果用户说“这个要 CNC 加工”那就检查刀具半径、深孔比例、装夹可行性。这些制造知识目前主要靠人判断如果能沉淀成规则库自动应用到生成过程中实用性会提升一个档次。我个人在实际操作中的体会是text-to-cad 目前最合适的定位不是替代 CAD 工程师而是把工程师从重复性的基础建模中解放出来。那些结构简单、变型频繁、尺寸驱动的零件最适合用这种方式快速生成初稿然后人工做精修和校验。把省下来的时间用在真正需要判断力的地方比如结构优化、材料选择、装配调试这才是这个方向最实在的价值。