Text-to-CAD 这个方向,我第一次在技术周刊里看到 demo 的时候,第一反应是“又来一个噱头”。但后来自己把开源项目跑通、调参、踩完坑之后,我承认我错了——这东西真的能把“设计意图”到“几何模型”之间的距离,压缩到一个令人咋舌的程度。这篇文章不聊那些华而不实的概念,就从一个实际动手做过、对比过多种方案的人的角度,讲讲 text-to-CAD 到底是什么,它背后的技术路线怎么选,以及你要真想自己搭一套,有哪些参数和坑是躲不掉的。
1. 整体设计与技术路线拆解
Text-to-CAD,直白讲就是输入一段自然语言描述,比如“一个带圆角的矩形法兰盘,中心有一个直径 10mm 的通孔,四角有四个 M4 螺纹孔”,系统直接输出一个可编辑、可制造的 CAD 模型文件(通常是 STEP、BREP 或参数化脚本)。它解决的痛点是:传统 CAD 建模的学习曲线陡峭,从想法到三维模型的中间过程耗时太长,而自然语言是最符合人类直觉的交互方式。
先抛结论:目前主流的 text-to-CAD 方案,走的是“语言大模型 + 参数化脚本生成”的路线,而不是“文本直接生成网格”。为什么?因为网格(Mesh)模型虽然看着像那么回事,但没法直接用于数控加工、有限元分析或者装配约束,建模软件里改一个圆角半径都得回到网格层面重新折腾,这违背了 CAD 的工程本质。参数化脚本则不同——它生成的是 SolidWorks、FreeCAD 里能二次编辑的特征树,改参数就是改模型,这才是工程师要的东西。
1.1 技术路线对比:为什么参数化比直接生成网格靠谱
我在实际测试里对比过三类方案。第一类是端到端的扩散模型,类似图像生成那样直接输出体素或点云再转网格。这类方案的问题在于几何精度很差,生成一个圆柱面都会出现肉眼可见的凹凸,更别提装配配合公差了。第二类是检索式方案,从既有模型库中匹配最接近的模型再变形,思路讨巧但泛化能力约等于零,换个稍微冷门的描述就“查无此物”。第三类是本文重点讲的——大模型生成参数化脚本,也就是让语言模型输出一段构建脚本(比如 CadQuery、FreeCAD Python API 的代码),再在本地执行脚本生成实体模型。
参数化路线的核心优势有二。其一,脚本里的每一个尺寸参数都是显式的,模型可编辑、可继承、可复用,这是工程界的硬需求;其二,语言模型对代码的生成能力远强于对三维几何的直接理解,因为代码是离散符号序列,这正是大模型的舒适区。实测下来,对于“带孔的法兰盘”、“L 型支架”这类有明确结构描述的输入,参数化方案的成图率能到八成以上,而纯网格生成方案的可用率可能连三成都不到。
1.2 语言到几何的映射链路:从文本到特征树的四步走
拆开来看,一条完整的 text-to-CAD 链路包含四个环节:意图解析、参数抽取、脚本生成、几何重建。意图解析负责把自然语言里的动词和名词对应到 CAD 操作上,比如“倒角”对应 Chamfer,“拉伸”对应 Extrude,“切除”对应 Cut。参数抽取负责从描述里挖数字和单位,像“直径 10mm”“厚度 5mm”这种,挖不出来的就按默认值处理。脚本生成把前两步的结果拼接成可执行的 CAD 代码,几何重建则由 CAD 内核执行脚本、输出实体。
这里面最容易被低估的是意图解析。早期我图省事,让大模型直接从文本生成 CadQuery 脚本,结果模型经常“自由发挥”——把“孔”理解成“布尔减运算”没错,但把“阵列”理解成“复制平移”就漏了圆周阵列的旋转参数。后来我在提示词里强制要求模型先输出 JSON 格式的意图和参数清单,再输出脚本,效果立刻不一样了。这其实符合大模型的工作机制:中间推理层的存在,能把“模糊的语言”到“精确的代码”这个大跨度映射,拆成两个相对可控的小跨度映射。
2. 核心原理与细节解析
2.1 模型选型:从零微调还是调用通用模型 API
这是所有上手者面临的第一个分叉路。从零微调一个 text-to-CAD 专用模型,数据从哪来?公开数据集 Text2CAD 有大约 17 万条文本-模型对,但里面不少样本的文本描述质量参差不齐,有些就是几个关键词拼在一起,既没有空间关系也没有尺寸约束,模型学多了这种样本会变傻。我个人的建议是:除非你有明确的私有数据资产或者离线部署的硬性要求,否则优先走“通用大模型 API + 高质量提示词”路线。
以 GPT-4 和 Claude 这类模型为例,它们的代码生成能力已经足够强,关键是你能不能把 CAD 领域的先验知识塞进提示词里。我在实践中维护了一套“角色 + 约束 + 示例”三段式提示词。角色部分告诉模型“你是资深 CAD 建模工程师”;约束部分明确指定只能用 CadQuery 的哪些函数、坐标系怎么摆、单位是什么;示例部分给两三个“文本-脚本”对作为 few-shot 参考。这样调出来的效果,比直接微调一个 7B 的小模型要稳定得多。
2.2 生成脚本的坐标系与特征树设计
脚本生成环节有一个容易出问题但很少被提及的细节:坐标系的选择。CAD 建模里,特征树是从哪个基准面开始生长的,直接决定了后续所有特征的坐标计算。我在测试中发现,大模型倾向于默认使用 XY 平面作为草图平面,然后沿 Z 轴拉伸。这本身没问题,但如果你要生成的是一个轴类零件,沿着 Y 轴拉伸明显更符合加工基准。解决办法是在提示词里写清楚:根据零件的主特征方向,自动选择最合理的草图基准面,并在生成的特征树中用注释标明基准面与拉伸方向。
特征树的顺序同样关键。一个常见的错误是模型先生成倒角或圆角,再生成孔特征,结果倒角把孔边的参考边破坏了,导致布尔运算失败。正确的顺序应该是:先构造基础实体(拉伸或旋转),再做布尔减运算(打孔、切除),最后做过渡特征(倒角、圆角)。这个顺序规则看起来简单,但你直接让模型自由生成,十次里有三四次会踩雷。把特征树的设计顺序作为硬性约束写进提示词,能显著提高脚本的一次通过率。
2.3 关键参数对标:这五个数字决定成败
抛开那些花哨的模型能力不谈,从实操层面看,有五个参数直接决定生成结果能不能用。第一个是单位制,提示词里必须明确“所有尺寸默认毫米”,不然模型会写出一堆没有单位或单位混乱的代码,CAD 内核执行时不会报错但尺寸完全错乱。第二个是公差精度,生成脚本里要显式设置建模精度(CadQuery 的 tolerance 参数),默认值可能满足显示需求,但后续做布尔运算时会出现微小的面片重叠或裂缝。第三个是圆角半径的默认值,文本没提圆角时,不要自作主张加圆角——这是模型最常见的“过度设计”毛病。第四个是孔洞的深度语义,“通孔”和“盲孔”必须区分,这需要在意图解析阶段就明确。第五个是阵列参数,圆周阵列要给出中心点、数量和角度范围,矩形阵列要给出行列数和间距,这些参数如果文本里没有,优先采用符合机械设计手册的默认值,而不是模型凭空想象的数值。
3. 实操环境搭建与核心流程
3.1 本地环境配置:CadQuery 的最小可行安装
要跑通 text-to-CAD 流程,本地环境其实不需要很复杂,核心就是一个 Python 环境和 CadQuery 库。我用的是 Python 3.10 + CadQuery 2.4 + FreeCAD 内核的经典组合。安装命令很简单,但有几个隐含的坑必须提醒。CadQuery 直接 pip 安装到最新版,通常会自动拉取对应的 OCP(Open CASCADE 的 Python 绑定),但如果你系统里装过旧版 FreeCAD,或者环境变量里残留了别版本的内核库,导入时会直接报 DLL 加载错误。我踩过一次,前后折腾了两小时,最后是新建了一个干净的 venv 才解决。
python -m venv cad_env source cad_env/bin/activate pip install cadquery装完以后,建议先跑一个最简的冒烟测试。创建一个 10x10x10 的立方体并导出 STEP 文件,如果你能看到一个有效的实体文件,环境就算通了。这一步很重要,因为后续所有脚本的调试都要依赖这个环境,晚发现问题不如早发现问题。
3.2 端到端复现:法兰盘生成全流程实录
下面用一个我反复测试过的例子,完整走一遍“文本到 CAD”的流程。输入描述是:“生成一个方形法兰盘,外边长为 50mm,厚度 8mm,中心有一个直径 20mm 的通孔,四角各有 4 个 M4 螺纹孔,孔中心到相邻两边的距离均为 8mm,外轮廓四角倒圆角 R5。”
我把这段文本喂给大模型,同时附上提示词约束,生成的 CadQuery 脚本核心逻辑如下:
import cadquery as cq # 基础法兰主体 plate = ( cq.Workplane("XY") .rect(50, 50) .extrude(8) ) # 四角倒圆角 plate = plate.edges("|Z").fillet(5) # 中心通孔 plate = ( plate.workplane().center(0, 0) .hole(20) ) # 四个 M4 螺纹孔(简化处理为直径 4.2mm 的过孔) for x, y in [(-19, -19), (19, -19), (-19, 19), (19, 19)]: plate = plate.workplane().center(x, y).hole(4.2)这段脚本生成的模型,和输入描述是吻合的。注意几个细节:倒圆角用的是edges("|Z")只选中垂直边,避开了顶面和底面的边缘——这个细节如果模型没处理好,圆角会加在顶面边缘上导致模型变形;螺纹孔在脚本里简化成了 4.2mm 的过孔,这是一个值得展开说的点,见下文。
3.3 工程化细节:螺纹孔与标准件的最优处理方案
关于螺纹孔,很多 text-to-CAD 的示例代码会直接画螺旋线加扫掠切割出一个真实的螺纹形状。这在演示层面很漂亮,但绝不推荐用于实际工程。原因有二:一是生成真实螺纹的运算代价高,一个简单的 M4 螺纹孔就得几千个面,四个螺孔一加,模型体量膨胀到不适合后续装配分析;二是 STEP 交换格式里螺纹孔的标准做法是使用孔特征标注外加螺纹公差标注,而不是实体螺纹。我在实操中统一采用“底孔 + 标注”的方案:生成一个底孔(M4 对应 3.3mm 钻底孔),然后在模型属性里附加 ISO 螺纹标注。这样模型轻、制造语义明确、下游 CAM 软件也能正确识别。
这个思路其实也反映了一个更大的原则:text-to-CAD 的终极目标不是生成几何,而是生成有制造语义的模型。一味追求视觉效果,反而偏离了工程核心。在提示词里明确“螺纹使用简化表示”“标准件使用 ISO 标注而非实体建模”,能避免 AI 生成一堆中看不中用的模型。
4. 调参、效果优化与效果评价
4.1 提示词调优:从“能用”到“好用”的三次迭代
先说结论:提示词对生成效果的提升,远比换模型大。我最初用最朴素的提示词“根据描述生成 CadQuery 脚本”,生成的脚本有相当概率出现逻辑错误,比如变量未定义、特征顺序颠倒、坐标对象使用错误。后来我把工作流改成“先输出 JSON 中间表示,再输出 Python 脚本”,效果有了质的提升——因为大模型被迫先把想法整理成一个结构化的“施工图”,然后照着施工图写代码,跳步的毛病大幅减少。
第二次迭代是给提示词里加入了“错误模式排除”段落。这听起来有点反直觉,但实测非常有效。我在提示词里直接写:不要使用cq.Workplane的链式调用超过三层,否则容易丢失工作平面上下文;不要使用rotate变换;不要依赖隐式坐标变换。让模型知道哪些是它容易犯的错,它就能主动规避。这本质上是把“我踩过的坑”转移成了“模型的约束”。
第三次迭代是引入了“质量自检”环节。脚本生成后,不要直接拿到 CadQuery 里执行,而是先把脚本发给模型让它自己检查一遍,找出可能导致布尔运算失败的步骤。模型自己review自己的代码,虽然不能发现所有问题,但能过滤掉很大一部分低级错误。这三次迭代之后,我的脚本一次通过率从大概35%涨到了65%左右,剩余没能通过的脚本,问题也通常集中在局部坐标计算的精度上,人工修一下就好。
4.2 几何精度评估:Chamfer Distance 与 IoU 双指标实测
很多人问怎么客观评估生成模型的正确性,有没有可量化的方法。我在实验里跑了几组数据,结论是用两个指标结合看才比较可靠。第一个是 Chamfer Distance(倒角距离),做法是将参考模型和生成模型各自采样成点云(我一般每个面采样20个点),然后计算两个点云之间的双向最近邻距离平均值。这个指标对整体几何形状的偏离程度非常敏感,如果生成结果缺了一个孔或尺寸差了几毫米,Chamfer Distance 会明显增大。第二个是 Intersection over Union(IoU),做法是把两个模型体素化到同一个网格(我用的是 0.5mm 分辨率),计算交集体素与并集体素之比。IoU 对局部特征的重叠率更敏感,可以抓住“孔的位置偏移”这类 Chamfer 指标不一定能暴露的问题。
拿法兰盘这个例子说,我调优前的第一次生成结果 IoU 大概在 0.85,看着还行,但用 Chamfer 检查发现四个螺纹孔的位置整体向右偏了约 1.2mm——这种误差在工业场景就是废品。而 IoU 之所以没有完全反映出来,是因为底孔直径只有 4.2mm,在 0.5mm 体素分辨率下,几个孔的并集体积累积损失占比不高。所以用双指标复核会稳妥得多。
4.3 扩散模型方案的参考对比:为什么我没选它
顺带多聊一种方向,2024年以来有一些工作尝试用扩散模型直接生成 CAD 的 BREP 边界表示,思路是让模型预测一个面片序列,再重建实体。我在测试集上跑过这类方法,发现它在“泛化性”上确实比参数化方案更强——模型似乎真的从数据里学到了一点点“几何直觉”,而不是死记结构模板。但代价是可控性差得离谱。你输入“直径 20mm”它可能给你生成 19.7mm 的孔,文本里的所有精确尺寸都被当成“参考”而非“约束”。
工程世界容不得这种随机性。这也是我最终锁死参数化路线的根本原因:它把“生成”这个行为,降维成了“代码生成 + 执行”,每一步都可解释、可追责。不夸张地说,如果生成结果出错,我能打开脚本一眼定位到是哪几行代码写错了,这种调试体验是端到端黑盒方案给不了的。
5. 常见问题与排查实录
5.1 特征丢失与法兰盘实例的错误定位
遇到最多的报错类别当属“生成结果缺了某个特征”——比如描述里要求 4 个孔,生成结果只有 3 个。排查思路要分两层:先看意图解析的 JSON 输出,看看模型是不是把“四个孔”理解成了“一个阵列”或者漏读了一个坐标;再看脚本的循环结构,是不是循环变量迭代次数写错了。我碰到过一次很隐蔽的问题:模型输出的 JSON 里四个孔坐标是对的,但生成 Python 脚本时 for 循环里的range参数从(4)被写成了(3),导致最后一个孔被静默丢弃。
这种问题用自动化检查很难发现,因为脚本本身语法合法、执行无误,只是少了一个特征。我后来加的“自检”环节就是针对这个场景:让模型对照 JSON 中间表示逐条检查脚本中的特征是否一一实现,相当于“合同”和“施工”对账,能有效拦截这类静默丢失问题。
5.2 布尔运算失败:内核报错信息并不友善
CadQuery 基于 Open CASCADE 内核,报错信息长得像乱码——一大堆十六进制地址和内部类名,对新人来说非常劝退。我总结的排查顺序是:先看是不是草图自相交(常见于模型生成的轮廓里有反向重叠边,简化做法是把剖面画成“整体轮廓 + 布尔减”而不是“多个叠加”);再看是不是特征顺序问题(先倒角后打孔的典型报错是“BRep_API: command not done”);最后才怀疑内核 bug。
一个非常实用的技巧:在提示词里要求每次生成时,在关键布尔运算前用material("debug")将当前实体导出为 STEP 文件。这样即使最终结果出错,你也能一步步回放特征树,看到是哪个环节开始变形的。“分段导出 + 逐步回放”比面对一个完整但坏掉的模型要直观得多,也帮我查出了不少难点。
5.3 模型精度与生成速度的取舍
还有一个容易忽略的实际问题:生成精度。CadQuery 默认的建模精度可以满足显示,但如果你把生成结果拿去 3D 打印或者 CNC 加工,小圆角和小孔径的误差会被放大。建议在脚本开头统一配置全局精度:
cq.Workplane("XY").rect(50, 50).extrude(8) # 在上下文中设置精度参数(以 cadquery 的 cq.occ_impl 的导入方式为例)严格说 CadQuery 没给你一个一键全局改精度的开关,需要到 OCP 的底层配置里调BRepMesh的弦高误差。我一般不做这个操作,因为默认参数做常规验证足够了,真到制造环节就把 STEP 导到专业 CAD 里重设公差。这里想提醒大家的是:text-to-CAD 是“设计辅助工具”而非“制造精度保障工具”,后端加工工艺的事交给后端处理,强行把精度要求塞进生成环节,只会徒增模型输出不合理代码的概率。
6. 应用场景与经验延伸
6.1 三个最适合当前落地的场景
在评估了一大堆场景之后,我认为现阶段有三个方向最值得落地,也是最容易出成果的。首先是设计前期概念草图生成:产品经理或甲方给一段需求文字,设计工程师用它快速生成几个可选结构的初版模型,用来评估布局可行性和空间占比。这类场景对精度宽容度高、对速度敏感,正好是 text-to-CAD 的长处。
其次是标准件与常用结构库搭建:把公司里常用的支架、法兰、卡扣、底座这类“高重复度、低创新度”的零件描述成标准文本模板,文本进模型出,等于给自己做了一个可搜索、可调参的私有标准件库。这个方向的 ROI 很高,因为很多工程师大量建模时间其实花在这些“没什么技术含量”的重复结构上。
第三是机械设计教学:让学生输入文本描述,生成模型,再对照标准答案找差异。这个场景对生成模型的质量要求不高,但能锻炼学生从文字到三维空间想象的转化能力,也是知识库产品可以切入的方向。
6.2 目前的技术边界:别指望它生成装配体
但要泼一盆冷水:目前的 text-to-CAD 对“多零件装配体”的生成能力非常有限。我尝试过输入“一个带底座的电机支架,底座与支架之间用四个螺丝连接”——模型单独生成底座没问题,单独生成支架也没问题,但让他理解两者之间的配合关系、生成带配合约束的装配模型,基本做不到。原因在于语言模型对“装配约束”这类关系型信息的学习,远不如对“零件几何”的学习充分。现阶段可行的办法是把装配体拆解成若干单零件分别生成,再手工装配。这其实也符合主流的工作流:AI 负责零件级建模,人负责系统级集成。
另外,text-to-CAD 对非规则自由曲面的生成还是弱项。像鼠标外壳、跑车车身这种大量依赖曲面造型的零件,参数化脚本的表达能力有限,这时候扩散模型反而有一定优势。但如前述,扩散模型的尺寸不可控问题还没解决,所以 2025 年的现实是:有明确规则形状的机械零件用文本转 CAD 已经可用了,艺术化曲面还是交给传统手工建模或者专用子方向更靠谱。
回归到出发点,我认为 text-to-CAD 最迷人的地方,恰恰是它带来的那种“从思想到实物的最短路径感”。哪怕它现在还有种种边界,但当一个模糊的想法能快速被变成一个可以旋转、可以剖切、可以标注的实体模型时,那种在传统流程下需要数小时才能获得的沉浸感,现在几分钟就能抵达。这就是我深耕这个方向的核心动力。如果你也打算入坑,我的建议很朴素:别一开始就追求完美模型,先把一条简单的“文本-脚本-实体”链路跑通,你会在第一个成功生成的零件上,理解我为什么如此看好这个方向。