1. 为什么说 text-to-cad 不是“3D版文生图”
1.1 从“看得像”到“算得对”
上周我在整理标准件库,同事扔过来一句话:“能不能直接说‘我要一个 M6×30 的六角螺栓’,软件就自己画出来?”我差点脱口而出“能”,直到自己把 text-to-cad 的完整链路跑了一遍,才发现这个词听起来浪漫,做起来全是工程上的硬骨头。
先说结论:text-to-cad 的目标不是生成一张“看起来像螺栓”的渲染图,而是生成一个可以被 CAD 软件打开、可以编辑特征、可以标注公差、可以进入装配体、可以出工程图、甚至可以直接送去加工的实体模型。也就是说,它要从“像素级正确”跃迁到“几何级正确”和“语义级正确”。文生图模型画出六角头、螺杆、螺纹纹理,那是视觉游戏;而 text-to-cad 必须保证螺纹的牙型角是 60 度、公称直径是 6mm、对边宽度是 10mm,这些数字差 0.1mm,装配就会出问题。
我对这个领域最早的判断是:它很像是给 CAD 软件装了一个“人类语言前端”。传统 CAD 的操作门槛在于,用户必须把脑子里的三维构思拆解成“草图 → 拉伸 → 倒角 → 阵列”这一系列离散操作。text-to-cad 则是反过来,让用户直接描述最终物体或功能意图,然后由模型自动补全中间步骤。这个设想如果成立,机械设计、工业设计、3D 打印、零部件选型这些场景都会发生一次不小的效率跃迁。
但真正动手之后,你会发现它跟文生图完全不是一回事。文生图允许模型“自由发挥”,画坏了重画一张就行;CAD 模型则必须满足可计算、可验证、可制造这三个硬条件。哪怕模型长得完全正确,只要五个面围不成一个封闭实体,它就是废的。
1.2 CAD 是一个强约束的符号系统
很多刚接触的人会问:直接用现在的 3D 生成模型(比如生成 NeRF、 mesh、SDF)不就行了吗?把文本变成点云或者三角网格,再丢给 3D 打印,是不是就算 text-to-cad 了?
问题恰恰出在这里。CAD 领域的通用语言是边界表示(B-Rep),而不是三角网格。网格适合做渲染和 3D 打印切片,但它没有“参数历史”,没有“特征树”,没有“草图约束”,更难标注公差和表面粗糙度。你拿到一个 STL 文件,想改一个孔的直径,必须重新建模;想在倒角半径从 2 改成 3,网格根本不知道“哪个凸起是倒角”。工程师日常用的是“参数化实体模型”:一个螺栓由拉伸六边形、旋转螺纹、倒角几个特征组成,改一个参数,全模型联动更新。这才是 CAD 的正规军。
text-to-cad 之所以难,就在于它输出的对象必须是这种强语义、强约束的符号系统。模型要理解“M6”不是“6 毫米长的线”,而是“公称直径 6mm、螺距 1mm、牙型角 60 度的公制螺纹”这一整套工程语义。它还要理解“30mm 是螺杆长度还是总长度”“是否带全螺纹”“头部要不要内六角”这些隐藏信息。这些信息在自然语言里通常被压缩成一个名词短语,但在 CAD 里是几十个参数。
我还观察到,用户输入的描述往往也分好几个层次。有人会说“我要一个能放手机的桌面支架”,这是功能意图;有人会说“设计一个 L 形支架,底板 80×60×5,立板 60×50×4,两根加强筋,孔距 55mm”,这是参数化描述;还有人直接说“按 DIN 933 标准,M6×30”,这是标准件语义。三种输入对 text-to-cad 系统的要求完全不一样。第一种需要 AI 做功能推理和结构设计,难度最大;第二种需要 AI 做参数抽取和特征识别,目前最可控;第三种需要系统内置标准件知识库,几乎算不上生成,更像是智能检索。想清楚你的用户属于哪一层,才能选对技术路线,而不是一听“自然语言生成 CAD”就热血上头。
2. 我拆过的几条技术路线:生成、参数化、检索
2.1 端到端生成模型:理想很丰满,B-Rep 还很骨感
学术界叫“text-to-cad”的技术路线,最吸引人的是端到端生成模型。它的思路是:把 CAD 建模过程表示成一个序列,比如“拉伸一个正六边形,高度 4mm;在顶面画一个圆,直径 6mm,拉伸 30mm;在末端切一个倒角……”,然后用类似语言模型的自回归方式,让模型根据文本预测这个序列。这样输出的不是网格,而是可重建出 B-Rep 实体的建模指令序列。
这个方向确实有论文做出了不错的结果,比如用文本编码器(像 CLIP 那种)把描述映射成向量,再用解码器生成草图参数和拉伸/倒角操作。我实际测试过一些开源权重,简单场景还行:一句话生成一个带孔方块、一个法兰盘、一个简化的支架,这些都能跑通。但一旦文本里出现“四个均布孔”“螺纹深度 18mm”“与底面成 30 度夹角”这类工程约束,模型就开始胡来。
端到端模型最大的问题有三个:一是训练数据不足。人类历史上留下的 CAD 模型很多,但完整记录“建模操作序列+自然语言描述”的数据极少,导致模型学到的只是“形似”而非“神似”。二是几何合法性没有保证。自回归生成的是离散 token,模型并不知道这些 token 拼起来能不能形成一个封闭实体。可能画出来的草图有自交线段,可能拉伸方向反了,可能两个特征根本没有相交。三是可解释性差。用户没法知道模型为什么选择这个倒角半径,出了问题也没法局部修正。所以我的判断是:端到端生成模型适合跑 demo、适合做造型灵感探索,但离工程落地还有距离。
2.2 LLM + 参数化建模脚本:当前最容易被工程化的路线
我实际项目里最推荐、也最好落地的一条路,是用大语言模型(LLM)做“语义到参数的转换”,再用参数化建模引擎(比如 CadQuery、OpenSCAD、FreeCAD)把参数变成实体模型。原因很简单:LLM 不擅长精确计算几何,但非常擅长理解自然语言、抽取关键参数、生成符合格式要求的代码;而参数化建模引擎恰恰相反,它笨、但它算得准。
整个流程是一个清晰的三段式:先让 LLM 把输入的文本解析成结构化参数,比如 JSON 对象;然后把参数填入预先写好的建模模板函数,生成 CadQuery/OpenSCAD 脚本;最后用开源内核执行脚本,输出 STEP/STL,再做自动验证。这样做的好处是,“AI 负责理解,代码负责精确”。即使 LLM 输出的参数是错的,你也可以通过校验规则拦截,而不会让一个乱七八糟的几何体混进模型库。
我在下面会详细展开这条路的实操细节。这里先给一个很直观的类比:我们不是在训练一个“会画画的 AI”,而是在给一个“会看图纸的实习生”配了一把绝对精确的数字卡尺。LLM 负责读懂图纸上写的是什么,卡尺负责量出准确数字,最后交给数控机床加工。只要卡尺是好的,整个链路就基本可控。
2.3 检索-装配式方案:不生成,去匹配
还有一个容易被忽略但实际很高效的路线:检索+装配。很多用户说“生成一个 M6 螺栓”,其实他们不想要一个从未见过的新螺栓,而是希望从标准件库里快速找到对应规格。这种情况下,与其让模型从零画,不如让 LLM 把描述转成结构化查询条件,去数据库里检索已有模型,再把检索结果装配到目标位置。
这套方案特别适合企业场景。绝大多数制造业公司里,重复使用的标准件、通用件、历史件占整个物料体系的 70% 以上。它们不需要“发明”,只需要“找得到”。text-to-cad 在这里的价值不是生成几何,而是把“帮我找一个法兰面上的 8 个 M8 螺栓”这句话,翻译成“螺栓规格 M8、长度 30、数量 8、分布圆直径 100、角度 45 度起始”的查询和装配指令,然后自动完成装配。
三种路线相比,端到端生成上限最高但下限也最低,LLM+参数化脚本是当前投入产出比最高的选项,检索装配则是最容易让老板看到实际收益的方案。我建议团队在立项时先想清楚:你要做的是“创造新模型”,还是“快速把已有模型用起来”。大多数场景其实是后者。
3. 实操复盘:用 CadQuery 把“M6 螺栓”变成实体模型
这一节我用自己的实测过程,演示 LLM+参数化脚本这条路线怎么落地。我用的是开源工具链,不需要商业 CAD 许可证,预期效果是:输入一句话,输出一个带标准参数的 STEP 文件和一个可编辑的 CadQuery 脚本。
3.1 先磨好环境:Python/CadQuery/验证工具
我的环境是 Python 3.11 + CadQuery 2.4。安装非常简单,用 conda 建一个干净环境,然后 pip 安装即可:
conda create -n text2cad python=3.11 -y conda activate text2cad pip install cadqueryCadQuery 底层封装了 OpenCASCADE(OCP),所以安装完之后,你实际上等于拥有了一套完整的 B-Rep 建模内核。之后我还会装manifold3d做网格检查,装numpy做坐标计算。如果你要本地跑 LLM,可以再装vllm或者ollama;我这次用了开源模型做参数抽取,避免把整个流程绑在某个云服务上。
这里有一个非常值得注意的坑:CadQuery 对 Python 版本有要求,拿到新环境先跑一句python -c "import cadquery; print(cadquery.__version__)"。很多所谓“装不上”的问题,其实都是 conda 环境混用了不同 Python 版本。单独建环境,别偷懒。
3.2 提示词设计:让大模型输出结构化参数
LLM 做参数抽取,不是把用户的原始描述直接丢给它,然后让它“画一个模型”。我是用一套固定的提示词,要求它只输出 JSON,字段名全部提前定义好。下面是我常用的提取 schema:
{ "part_type": "hex_bolt", "thread_dia": 6.0, "pitch": 1.0, "head_style": "hex", "head_width": 10.0, "head_height": 4.0, "body_len": 30.0, "thread_len": 18.0, "standard": "DIN933", "material": "steel" }提示词大致是这样的:
你是机械零件参数抽取器。根据用户输入的零件描述,提取 JSON 参数。只输出 JSON,不要解释。如果描述中缺少某个字段,使用默认值填充。单位是毫米。如果描述中提到标准号,优先按标准覆盖默认值。
你可能会问:为什么不直接让模型生成 CadQuery 代码,而要先输出 JSON?因为 JSON 是稳定的中间表示,可以校验、可以存档、可以让后续不同的建模后端共用。直接生成代码,模型一旦写了不存在的 API,你就得不断修复;JSON 参数就简单得多,抽取值放在模板里,十行代码跑完。
3.3 生成代码与模型:从 JSON 到 B-Rep
拿到 JSON 之后,我用一个预先写好的建模函数生成实体。下面是一个简化版的函数,用来生成六角头螺栓的拉伸主体:
import cadquery as cq def hex_bolt(thread_dia=6.0, pitch=1.0, head_width=10.0, head_height=4.0, body_len=30.0, thread_len=18.0): # 头部:正六边形拉伸,对边宽度 head_width head = (cq.Workplane("XY") .polygon(6, head_width / 0.866) # 六边形外接圆直径公式 .extrude(head_height)) # 光杆:圆柱拉伸 shank = (cq.Workplane("XY") .circle(thread_dia / 2) .extrude(body_len) .translate((0, 0, head_height))) return head.union(shank)这里polygon(6, x)的x是外接圆直径,而螺栓头部对边宽度是 10mm,所以要除以cos(30°)≈0.866。这就是建模模板里需要工程知识的地方,LLM 不一定懂,但我们预先写好的模板懂。
真正的 ISO 螺纹我不会用简单的圆柱代替,而是会用一个独立的make_iso_thread函数去生成螺旋体。但这部分代码较长,而且涉及牙底圆弧、螺距补偿等情况。如果你只是做装配验证和渲染,可以用简化螺纹;如果要出加工图或 3D 打印,还是建议去调标准的螺纹库。下面只展示最终导出 STEP 和 STL:
cq.exporters.export(bolt, "M6x30.step") cq.exporters.export(bolt, "M6x30.stl", tolerance=0.01, angularTolerance=0.1)导出 STL 时,tolerance和angularTolerance要按用途来:做有限元网格、快速预览,分辨率可以低一点;做 3D 打印切片,建议tolerance=0.01,否则螺纹表面会呈多边形。
3.4 模型验证清单:面积、体积、干涉、加工性
生成模型只是第一步,紧接着要做自动验证。我把验证拆成四层:
- 有效性:模型是不是一个封闭实体?在 CadQuery 里,
shape.val().Volume()如果为 0,说明模型可能不是实体,或者根本没封闭。 - 参数回读:用
importStep读回模型,测量关键尺寸是否与期望一致。比如头部对边距离是否约等于 10mm,光杆直径是否约等于 6mm。 - 干涉检查:把螺栓放进预先准备好的螺母模型里,用布尔求交看干涉体积是否为 0。如果干涉大于某个阈值,说明螺纹参数不匹配或者装配方向有问题。
- 制造性:这个比较主观,但我们可以检查最小的壁厚、孔径与螺栓直径的比例,甚至直接用切片软件做一次模拟切片。模型好看不等于能加工,后面我会单独说。
以下是简单的读回和体积检查:
shape = cq.importers.importStep("M6x30.step") vol = shape.val().Volume() if vol < 1e-6: raise ValueError("模型体积为零,生成失败") print(f"Volume: {vol:.3f} mm^3")单项检查容易,难的是把检查结果和文本描述做“闭环”。我最后的流程是:如果验证失败,就把失败原因和模型状态反馈给 LLM,让 LLM 修正参数后重新生成。这个“生成→验证→再生成”的循环,才是真正实用的 text-to-cad 形态。
4. 我在实测中踩过的五个坑
4.1 同一个词,三种理解
第一坑来自“M6×30”这个写法和语义歧义。我让模型生成一个“M6×30 六角螺栓”,它给出了一个总长 30mm 的螺栓,头部占掉 4mm,光杆只有 26mm。但我预期的是“公称长度 30mm”,即头部以下光杆加螺纹共 30mm。两种理解差出 4mm,在装配时可能直接导致螺栓不够长。
更麻烦的是“M6×30”还可能被理解成“螺纹长度 30mm”的命名方式。标准件行业里,不同公司、不同时代的图纸都有自己的缩写习惯。解决办法不是去“纠正”模型,而是在提示词里写清楚字段定义,并且在产品界面上让用户二次确认。我后来在参数 schema 中增加了length_definition字段,取值为"overall_length"或"shank_length",默认按 GB/DIN 的定义设为“公称长度=头部以下长度”,歧义率立刻降了很多。
4.2 螺纹到底要不要画出来
这个坑几乎每个做 text-to-cad 的人都躲不掉。大部分文生图模型输出的螺栓图片里螺纹是“画”出来的,但 CAD 里螺纹是一个螺旋扫描特征,计算量比圆柱大很多,生成时容易报错,而且对显示性能影响巨大。实际项目里,我见过太多团队为了追求“看起来专业”,非要在螺栓上生成完整螺纹,结果一个 M6 螺栓的 STEP 文件体积超过 50MB,下游装配变得奇慢无比。
我的经验是:先问用途。如果目标是快速选型、装配示意,光杆+简化螺纹环带就够;如果目标是模具加工、3D 打印或有限元接触分析,那必须建立真实的螺纹螺旋线,并且按标准校验牙型。text-to-cad 系统里应该内置一个“螺纹精度等级”开关,而不是一刀切。
4.3 坐标系与装配方向:单件看着对,装配全错
模型单独打开,什么问题都没有,往装配体里一放,才发现螺栓轴线和孔轴线夹角不对,或者头部方向装反了。这个问题不是几何形状的问题,而是模型缺少“装配语义”。
文本里说“把螺栓装入法兰”,这其实包含位置、方向、配合关系三层信息。目前的 LLM 只会回答“螺栓头是六角形”,要它理解“螺栓轴线与法兰孔轴线重合,头部朝上”还需要额外提供装配接口。我在落地时采用了一个比较土但有效的办法:让提示词固定输出一个placement字段,包含原点(x, y, z)、轴向(dx, dy, dz),然后在建模模板里自动做一个旋转变换。这样至少让系统具备“先生成、再摆放”的能力,不至于每一步都要人工拖拽。
4.4 STL 好看不能算 CAD
有一次我给团队看 demo,生成出来的零件在渲染器里非常漂亮,大家都很兴奋。后来一位老工程师问:“这个模型能不能改孔距?”我试了一下,发现系统输出的只有 STL。那一刻我意识到,text-to-cad 如果最终输出 STL,那就等于把用户踢出了 CAD 工作流。
STL 是万能的“显示格式”,但不是“编辑格式”。改一个孔距,需要把表面三角面片里的几百个节点全部重算,这在工程上是不可接受的。正确做法是,系统至少同时输出 STEP(B-Rep 实体)和原始建模脚本(CadQuery/OpenSCAD 源码)。STEP 用于下游 CAM/CAE,脚本用于后期参数修改。如果只能输出一种,我会毫不犹豫地放弃“好看”的 STL,保存“耐改”的脚本和 STEP。
4.5 大模型的“幻觉式公差”
这是最隐蔽的坑。模型对“间隙配合”这类术语有模糊的理解,有时会擅自决定配合间隙大小。比如描述里写“M6 螺栓和通孔间隙配合”,模型生成一个直径 6.5mm 的孔。如果对方在精密装配里要求 H8/h7 的配合,6.5mm 的间隙会造成明显松动,根本没法用。
解决办法是在建模模板里内置配合表:当 LLM 识别到“间隙配合/过渡配合/过盈配合”,系统自动根据公称尺寸查对应的公差带,而不是把“间隙大小”交给 LLM 自由发挥。同样的逻辑也适用于倒角大小、壁厚、拔模斜度这些容易被 LLM 编出怪异数值的参数。一句话:让 LLM 做选择题,别让它做计算题。
| 坑 | 现象 | 缓解手段 |
|---|---|---|
| 长度定义歧义 | 总长/杆长/螺纹长互相混淆 | 增加字段定义,强制约定标准 |
| 螺纹细节 | 简化或过于复杂 | 按用途提供精度开关 |
| 坐标系方向 | 单件正常,装配错位 | 固定输出 placement 字段 |
| 输出格式 | 只有 STL,无法编辑 | 同时输出 STEP+脚本 |
| 公差幻觉 | 配合间隙乱填 | 内置配合表,查表取值 |
5. 对前线的价值判断与落地节奏
5.1 最适合首批尝试的任务
我建议团队在起步阶段,别野心太大,把 text-to-cad 用于下面几类任务,成功率最高:
- 标准件库的智能调取:把“M6 六角螺栓,长度 30,镀锌”变成标准件编码和装配关系。这不是生成,是智能检索,但用户体验上已经有“输入一句话就出来模型”的效果。
- 简单拉伸/旋转类零件:比如垫片、法兰、轴套、支架。这些零件特征数量少、参数清晰,非常适合 LLM 参数抽取 + 模板建模。
- 历史模型的参数化重构:老图纸只有 PDF 或 STL,让 LLM 读取文字标注,生成参数化模型,再人工确认。虽然还做不到全自动,但能省掉 80% 的重复建模时间。
- 创意阶段的快速打样:设计师描述一个概念,系统生成 3-5 个候选模型,供用户挑选和修改。这里对精度要求低,对多样性和出图速度要求高,反而是端到端生成模型能发光的地方。
5.2 短期不要碰的场景
有些场景看起来很诱人,但做起来容易翻车,比如:
- 自由曲面产品设计:汽车车身、消费电子外壳,这些模型的曲面连续性、美学要求极高,目前的 text-to-cad 根本生成不了可控的 A 级曲面。
- 复杂装配体设计:一台减速器几十个零件,彼此有齿轮啮合、轴承配合、密封要求。文本很难表达完整装配逻辑,系统也很难自动推理。
- 安全关键件:承力结构、压力容器、医疗植入物,这类零件需要完整的强度校核和可追溯设计过程,法律与合规上也不会允许“AI 直接生成图纸就投产”。
- 需要频繁人工创意决策的场景:如果整个设计过程是一连串的“非标选择”,那 text-to-cad 只能做一个辅助工具,不能作为主流程。
5.3 团队落地的一些方法
最后聊聊怎么把 text-to-cad 真正用起来。我发现最容易成功的落地方式,不是做一个“万能输入框”,而是圈定一个很小的零件家族,做端到端闭环。
先选 20 个典型零件,人工写出标准提示词和标准建模模板,把“输入一句话→生成 STEP→自动检查”→这个链路跑通。然后让设计团队每天用,记录哪些描述经常被误解,把误解案例反哺到提示词和校验规则里。这个循环跑上一个月,系统的可用度会明显提升。
另一个建议是,不要追求 100% 自动化。合理的人机协作方式是:AI 快速生成初稿,CAD 工程师负责审单和微调。只要“从零开始建模”的时间能缩短一半,这个工具就有价值。一次性把“全自动、免审核”作为目标,实践里几乎都会卡在质量风险和信任问题上。
从我个人的经验看,text-to-cad 这个方向真正成熟还需要一段时间,但“LLM 理解意图 + 参数化模板生成模型”这条路,现在已经可以给实际工作流带来真金白银的效率提升。如果你也准备试,不妨从小而美的场景切入,跑通一个闭环,再谈扩展。到时候你可能会发现,最有用的不是那个“生成模型的 AI”,而是你为了让它干活而梳理清楚的那套参数体系和标准规范。