文本生成CAD实体:从自然语言到可编辑参数化模型的AI设计实践

发布时间:2026/10/25 6:20:24
文本生成CAD实体:从自然语言到可编辑参数化模型的AI设计实践

今年在整理AI辅助设计相关工具链的时候,我花了不少时间折腾text-to-cad这个方向。它跟常见的文生图、文生3D网格完全是两码事——输入一段自然语言,比如"一个带四个安装孔的矩形底板,厚度5毫米",输出的是一个真正能进CAM、能出工程图、能编辑尺寸的CAD实体,而不是一张渲染图或者一个水密性都无法保证的Mesh。这个方向的工作流涉及大模型微调、CAD内核重建、参数化特征序列生成,链条很长,但每一步踩清楚之后,确实能做出很实用的东西。

这篇文章我不会堆概念,只把我实际跑通、实际踩坑、实际拿来和真实设计流程对接过的内容写出来。适合有CAD或三维建模基础、同时想了解AI怎么进入工程设计环节的读者;如果你只是玩过AI画图,想看看"语言直接建模"到底靠不靠谱,也能从里面搞清楚它的能力和边界在哪。

1. text-to-cad的底层逻辑:不是生成"一个形状",而是生成"一段设计过程"

1.1 为什么输出必须是B-rep而不是Mesh

很多第一次接触text-to-cad的人会问:直接用文生3D模型不是更快吗?那些能生成高精度Mesh的扩散模型我也玩过不少,生成效果确实惊艳,但放到CAD工作流里根本没法用。原因很简单:Mesh是一堆三角形面片的集合,它描述的是"外观",不是"实体"。

CAD里真正干活的是B-rep(边界表示),也就是用拓扑面、边、顶点加上几何定义来精确表达一个实体。一个STEP文件里的圆柱面、平面、圆角特征,都是数学上的精确曲面,不是近似网格。做布尔运算、倒角、抽壳、生成工程图和CAM刀具路径,全部依赖这种精确表示。我试过把高精度Mesh转成STEP文件,转出来的结果是几万个碎面,在CAD软件里打开卡到几乎无法操作,更别说给加工师傅看图纸了。text-to-cad从一开始就是冲着B-rep去的,这是它和文生3D最本质的差别。

1.2 把设计过程当作token序列

既然目标是生成CAD实体,那模型到底该输出什么?这是整个方向最关键的决策点。目前主流的做法不是让模型直接吐出一个STEP文件,而是让它生成一段可执行的CAD建模操作序列。

你可以把这个序列想象成一张"设计配方":先画一条草图线,给定长度和角度;然后把这根线变成闭合轮廓;接着选择拉伸面、指定深度;再打一个孔、指定直径;最后做倒角。每一步对应CAD内核里的一次API调用。大模型本质上是个翻译器,把自然语言翻译成这一串结构化的建模指令。

这个思路最大的好处是:输出的东西和设计过程一一对应,完全可以回溯、修改。模型说"画一条长50毫米的线",你改写成"60毫米"再重新执行,实体就跟着变了。这不光是生成,而是"用语言驱动的一次参数化设计"。相比之下,直接回归一个STEP文件的二进制内容或者体素表示,既不可编辑也无法解释,工程上没人敢用。

1.3 文本描述的分级:从专家命令到小白口语

实际操作中还有个容易被忽略的问题:用户说的话水平差太多了。同一个零件,有经验的工程师会直接说"宽40深60高30的底板,四角M6沉头孔";小白可能就是一句"一个方板,四个角有螺丝孔"。如果模型只训练过专业表达,遇到口语化描述就会崩。

所以现在公开的数据集和模型普遍把文本提示分成了几个层次:专家级(包含完整尺寸和特征参数)、中级(部分参数缺失)、新手级(基本只有形状描述)。这其实很聪明,既让模型学会了"精确到毫米"的指令执行,也让它学会在信息不足时用合理默认值兜底。我在实际使用时也会刻意先给一个偏口语的prompt,再让它输出一段"带默认参数"的模型,比自己动手建模还省事。

2. 主流开源方案的实际选型:我的对比和取舍

2.1 Text2CAD:最容易复现的方案

很多人听说text-to-cad是从Text2CAD这篇工作开始的。它做了一个自动生成训练数据的管线:先用CadQuery(一个用Python写参数化CAD模型的库)批量生成大量零件,再为每个零件自动编写多级难度的自然语言描述。训练语料里既有"cmd=lineTo, len=50"这种命令级的表达,也有"画一个长50毫米的边"这种接近人类工程师的说法。模型架构上直接用了Llama和Mistral做微调,输入是文本,输出是一串token化的CAD命令序列。

我的评价是:它的技术路径非常清晰,开源程度也够,适合拿来做起点。不过跑下来的感受是,它擅长处理"由拉伸和打孔构成"的零件,对倒角、圆角、扫掠这类偏自由曲面的特征就弱一些。

2.2 num2cad:聚焦数值可控

还有一个值得关注的是num2cad,它的卖点是数值精度。Text2CAD这类方案生成的是相对语义,比如"长边是短边的两倍",而不见得能准确给出"32.7毫米"这种带小数位的尺寸。num2cad专门强化了数字令牌的预测,让模型学会输出精确到小数点后一位的尺寸,并且和几何约束对齐。

我在做标准件库自动生成时倾向于用它,因为标准件(比如带沉孔的支架、带螺纹孔的连接板)要求一字不差的尺寸,不是"看着差不多"。它比Text2CAD更难部署一些,环境依赖更复杂,但对尺寸敏感的场景值得折腾。

2.3 基于大模型Agent的脚本式方案

除了端到端的文本到CAD命令序列,还有一条路线是Agent方案:直接让大模型调用CadQuery、OpenSCAD的参数化脚本API,模型不直接输出序列token,而是输出一段可执行的Python建模代码,由解释器执行产出STEP文件。这类方案上限很高,因为模型能用上Python的所有库和逻辑控制,但翻车概率同样高——如果生成的代码里有错误,怎么Debug是个大问题。

2.4 我整理的对比表

方案输出形式精度可编辑性部署难度适合场景
Text2CADCAD命令序列语义级强(序列可改)中概念方案、教学演示
num2cadCAD命令序列+数值强化精确数值强较高带具体尺寸的标准件
Agent脚本式Python/CadQuery Code取决于代码极强中复杂逻辑、批量生成
商用云端产品通常是参数化模型导入中高中低非专业用户快速出坯模

选型时我的建议是:如果你主要做早期方案验证,就从Text2CAD的checkpoint开始;如果你需要生成结果直接进装配体和加工流程,那必须选数值强化或Agent方案,并且后续强制加一道尺寸审查,不能完全信任模型生成的任何数字。

3. 实操记录:从文本提示到STEP文件,我跑通一条最小链路

3.1 环境准备和依赖安装

先说结论:在本地跑通一个最小text-to-caddemo,不需要什么夸张的显卡,我用的是一张8GB显存的中端卡,CPU推理也行,就是慢一些。依赖方面最麻烦的是CadQuery和OCCT内核的版本匹配问题。CadQuery基于OpenCascade,不同版本的内核在布尔运算、倒角行为上确实有差异,别随便升级。

以下是我在Ubuntu环境下的操作记录:

# 创建独立Python环境,避免系统Python环境被弄脏 python -m venv .venv-text2cad source .venv-text2cad/bin/activate pip install --upgrade pip pip install cadquery==2.4.0 # 版本要特别注意,高版本可能不兼容旧数据 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install transformers accelerate sentencepiece

安装完成后建议先敲一个CadQuery冒烟测试,生成一个最简单的立方体导出STEP文件。这一步能隔离"环境问题"和"模型问题":

import cadquery as cq result = cq.Workplane("XY").box(20, 20, 20) cq.exporters.export(result, "smoke_test.step")

能正常运行再往下走。我最初就是跳过了这步,结果排查了很久才发现是CadQuery升级后API签名变了,和模型的输出解析代码不兼容。

3.2 拉取模型权重和推理

数据部分我用的是公开仓库里的预训练权重。拉下来之后运行:

python scripts/t2c_predict.py \ --model-path ./checkpoints/text2cad_expert \ --prompt "a rectangular base plate with four holes" \ --out-seq ./output/pred_seq.json

模型输出的不是一个STEP文件,而是一段JSON格式的命令序列。这一步会让人困惑:怎么生成的东西是文字?其实这就是这类方案的核心设计——先把命令序列生成出来,再由后续脚本调用CAD内核重建实体。命令序列里通常包含类似这样的结构:

{ "operations": [ {"type": "sketch_line", "start": [0, 0], "end": [80, 0]}, {"type": "sketch_line", "start": [80, 0], "end": [80, 50]}, {"type": "close_sketch"}, {"type": "extrude", "depth": 10}, {"type": "hole", "position": [10, 10], "diameter": 6} ] }

之所以要这个中间表示,是为了可编辑性。你可以在重建前任意修改序列里的参数,例如把10毫米的板厚改成12毫米,再重新执行重建脚本,输出全新的模型。如果直接把模型权重绑死在输出STEP文件上,这个灵活性就没了。

3.3 拿到序列之后如何重建实体

下一步是把命令序列翻译成CadQuery调用。仓库里通常带一个执行器脚本,核心逻辑类似:

import cadquery as cq def reconstruct(seq): workplane = cq.Workplane("XY") # 遍历命令序列,逐个执行对应的建模操作 for op in seq["operations"]: if op["type"] == "sketch_line": workplane = workplane.line(op["end"][0], op["end"][1]) elif op["type"] == "close_sketch": workplane = workplane.close() elif op["type"] == "extrude": workplane = workplane.extrude(op["depth"]) elif op["type"] == "hole": workplane = workplane.hole(op["diameter"]) return workplane model = reconstruct(pred_seq) cq.exporters.export(model, "result.step")

真实场景里命令类型比这多得多,还有圆角、阵列、镜像、旋转拉伸等,原理都一样:命令序列是"设计意图",执行器是"实现方式",两者解耦。

提示:执行完重建后,务必先用查看器打开STEP文件确认形状,不要直接拿去做网格渲染或是3D打印切片。模型生成的序列偶尔会出现"自相交拉伸"这类几何上成立、工程上却非法的操作,必须肉眼检查。

3.4 验证输出:用OCCT检查几何合法性

我强烈建议在管线里加入合法性校验。CadQuery自带一些几何检查功能,另外可以通过OCCT内核的ShapeFix接口检查:

from OCC.Core.ShapeFix import ShapeFix_Shape from OCC.Core.TopoDS import TopoDS_Shape from OCC.Core.STEPControl import STEPControl_Reader # 读取STEP文件 reader = STEPControl_Reader() reader.ReadFile("result.step") reader.TransferRoots() shape = reader.Shape() # 运行ShapeFix修复几何问题 fix = ShapeFix_Shape(shape) fix.Perform()

如果这一步报了大量的修复记录,说明模型生成的几何质量偏低。正常情况下,一个合格输出应该几乎不需要修复。我在实际跑批时发现,数据分布不同导致的成功率差异很大——处理简单钣金件时修复率很低,一旦涉及曲面造型,修复量直线上升。

4. 实测中反复踩坑的记录:CAD精度问题的真实面貌

4.1 语言里的"大""薄""差不多"没法直接变成毫米

边界表示里的尺寸必须是确定数值,但自然语言天生是模糊的。模型收到"做一个大一点的底板"时,它怎么决定"大"是100毫米还是500毫米?训练数据里的默认值分布决定了它的选择。

我踩过的具体坑是:让模型生成一个"承受中等载荷的支架",它给了一个5毫米的壁厚。这个值对塑料件可能够,对钢结构完全不够。问题不在模型,而在提示语没有给约束。解决办法是在prompt里强制加入数值语境,比如"壁厚不低于8毫米"或"适配M8螺栓"。如果模型没能满足这个约束,就说明它的数值理解还不到位,不应该用于正式交付。

4.2 布尔运算失败是家常便饭

text-to-cad的序列里常有布尔运算步骤:拉伸一个基体,再减去一个圆柱作为孔,或者并上一个凸台。但在OCCT内核里,两个B-rep做布尔运算不是无条件的,面与面处于相切、共面、或者非常接近的容差范围时,运算会失败或产生退化边。

我在复现很多测试用例时,至少有15%~20%的情况会出现布尔失败。后来总结出一个规律:让模型尽量用"草图里直接带孔轮廓再拉伸"的方式建模,而不是拉伸完再用圆柱去减。前者生成的几何在拓扑上更干净,后者对内核鲁棒性依赖很高。这个经验其实和人类建模师的操作习惯完全一致——能在一个特征里完成的事,不要拆成多次布尔。

4.3 倒角、螺纹和制造特征容易被忽略

另一个在生成结果中反复出现的问题是:模型"忘记"了制造特征。你明明说"所有锐边倒角R2",但输出的序列里可能只有一个倒角操作,剩下的边全是尖角。定位这类问题没有捷径,只能重建之后做几何特征检查:遍历所有边,检查是否存在非0的圆角半径;遍历圆柱面,检查是否有螺纹线。用pythonOCC可以写这类巡检脚本。

也正因如此,我一般不把text-to-cad的结果直接当最终图纸,而是当可编辑的初稿。生成后进入传统的CAD环境补特征,效率比从零画高很多。

4.4 模型幻觉:生成了合理形状却完全不是你要的东西

最后一种坑最隐蔽:输出在几何上完全合法,从形状到尺寸都很漂亮,但它和你描述的根本不是一回事。让模型"生成一个带中心孔的圆形法兰"它可能给了一个方形的带孔板,原因是训练数据里方形板占比太高,模型学了先验分布。

解决这个问题只能靠完善的测评指标,把把生成的模型和参考模型做特征级别对齐,而不仅仅是看渲染图。我在实际流程里会额外把关键特征抽出来做结构化比对——有没有孔、孔的数量对不对、孔是通孔还是盲孔、外轮廓是圆形还是矩形。这些用一套简单的规则脚本就能自动检查,比人眼扫模型可靠得多。

5. 落地边界:哪里能用,哪里还在画饼

5.1 最合适的场景:概念设计、标准件、教学演示

折腾了这么长时间,我的结论是text-to-cad目前最适合三类场景。

第一类是概念设计的快速坯模。比如投标时给客户看结构方案的大致形态,不需要精确标注,但需要一个能转STEP、能进装配的实体文件,这个生成速度就很有价值。第二类是标准件库生成。你手里有一批参数相近的连接板、支架、垫片,写一段描述让它批量生成基础几何,然后统一挂到参数表里调优,节省大量重复劳动。第三类是教学演示。给学生或非专业人士演示"一个零件是怎么一步步建出来的",命令序列天然就是建模步骤,比看建模录屏直观得多。

5.2 参数化约束是下一步的关键

现在绝大多数text-to-cad模型的输出虽然可编辑,但不是真正的参数化模型——没有尺寸约束方程、没有特征之间的父子关系、没有设计意图表达。你改一个孔的直径,其他关联孔不会跟着变。这和现代CAD的"全参数化"理念差距很大。

这也是我认为接下来最有价值的方向:让模型同时生成特征树和约束关系,而不是只生成一维的命令序列。已经有团队在做这方面的探索,比如把构建历史保存下来再结合数学约束求解器,让输出变成真正"活"的参数化模型。一年内如果这是能稳定做到,text-to-cad的工程价值会上一大个台阶。

5.3 人机协作的正确姿势:文本+草图+点选

最后分享一个使用上的心得:别想着完全靠聊天完成建模。自然语言描述不清的地方,结合草图或点选来补。最有效的工作流是:

  1. 用文字描述总体思路和关键特征;
  2. 导入一张手绘草图或一个参考模型;
  3. 在关键位置点选几个用于定位的基准点;
  4. 让模型在这些约束下生成特征序列。

我试过在提示词里插入类似"以图片中左上角孔为原点"的描述,再给定坐标系,模型输出位置的准确率明显提升。这种做法其实是在降低大模型对空间关系的理解难度,人和模型各发挥所长。

另一个值得建立的意识是版本心态:不要指望一次生成一步到位,而是把它当做一个"可以无限重新生成初始方案"的助手。我通常一口气让它生成20个变体,丢到CAD里快速筛选,挑出两三个符合直觉的再细化。这个流程很接近创意思考时的头脑风暴,只是速度被拉快了一个数量级。实测下来的体验是,把text-to-cad定位成"设计灵感引擎"而非"自动出图机",它的价值才能发挥出来,也不会因为偶尔的生成失败而丧失信心。