1. 什么是text-to-CAD?它不是“AI画图”,而是工程链路的底层重构
text-to-CAD这个标题乍看像AI绘图的延伸——输入“一个带螺纹孔的铝制支架,长120mm,宽60mm,厚8mm,中心开Φ10通孔,四角各有一个M4沉头孔”就自动生成CAD文件。但实际远不止于此。我从2017年开始在汽车零部件厂做结构设计协同系统,后来转做工业软件集成,亲眼见过三类团队把text-to-CAD当成救命稻草:一是中小模具厂老板,想绕过老师傅手绘草图→建模→出图的3天流程,让业务员用手机拍张客户手绘稿拍照+语音描述,5分钟生成可编辑的STEP模型;二是高校机器人实验室,学生写论文时需要快速构建机械臂连杆、基座、末端执行器的参数化模型,不再手动拉伸、旋转、布尔运算;三是建筑BIM团队,在Revit里嵌入插件,把“南侧幕墙需预留3个Φ80穿管孔,距地1.2m,水平间距1.8m”直接转成带定位约束的族文件。这三类场景共同指向一个本质:text-to-CAD不是替代CAD软件,而是把自然语言作为工程意图的中间表达层,打通从模糊需求到精确几何体的语义鸿沟。
核心关键词里,CAD是目标载体,但真正决定成败的是STEP和STL这两个格式背后的工程逻辑。STEP(ISO 10303标准)是唯一能承载完整拓扑关系、参数化特征、装配约束、材料属性的交换格式,它不是“图形”,而是“可计算的工程对象”。而STL只是三角面片堆砌的“壳”,连圆柱面都是用几百个小平面逼近的,你拿它去数控加工,刀路规划会出错;拿它做有限元分析,网格质量差到收敛不了。GLB则是Web端轻量化展示用的,本质是压缩后的glTF,连尺寸单位都可能丢失。所以所有靠谱的text-to-CAD方案,第一关必须过STEP——不是生成STL再转STEP(那会丢特征树),而是直接输出符合AP242协议的STEP文件。我去年帮一家医疗设备公司落地时,他们最初用某开源模型生成STL再用FreeCAD转STEP,结果导出的螺纹特征全变成“无意义曲面”,CNC车间反馈“根本没法选中螺纹面做攻丝路径”。后来我们改用基于OpenCASCADE内核的定制解析器,把“M6×1.0右旋螺纹”直接映射为CSG布尔体素+螺旋线扫掠,才真正拿到可用模型。这说明text-to-CAD的价值不在“快”,而在“准”——准到能让下游制造、仿真、检测环节无缝接手。
适合谁来关注?不是设计师本人,而是设计流程的组织者:PLM系统管理员、研发IT负责人、工业软件二次开发工程师。因为真正的落地难点从来不是“生成一个模型”,而是“生成的模型能否进入现有工作流”。比如你生成的STEP文件,能不能被Teamcenter自动识别为“新版本零件”并触发变更审批?能不能被ANSYS Workbench直接读取材料属性而不报错?这些才是text-to-CAD项目成败的分水岭。如果你只是想找个工具画个示意图发朋友圈,那用MidJourney加DALL·E就够了;但如果你要让采购部门拿着生成的模型去比价,让车间师傅按它调机加工,那text-to-CAD就是一条必须亲手铺平的工程化铁轨。
2. text-to-CAD的技术架构拆解:为什么90%的Demo停留在PPT上?
市面上几乎所有公开演示的text-to-CAD方案,都在刻意回避一个事实:自然语言理解(NLU)和几何建模(Geometric Modeling)之间存在不可逾越的语义断层。我拆解过7个主流开源项目和4家商业公司的技术白皮书,发现它们的架构几乎都卡死在同一个环节——把“带倒角的矩形板”这种模糊描述,精准映射到CAD内核的建模操作序列。这不是算法问题,而是工程范式冲突。
2.1 三层架构:意图层、约束层、几何层
真正可行的text-to-CAD必须严格分三层,缺一不可:
意图层(Intent Layer):负责将自然语言解析为结构化工程语义。这里不能用通用大模型(如LLaMA)直接微调,因为工程术语有强领域性。“沉头孔”在机械手册里定义为“锥形扩孔+圆柱段”,但大模型可能把它当成“凹坑”。我们采用的方法是:先用领域词典(含GB/T、ISO标准编号)做实体识别,再用规则引擎匹配《机械设计手册》中的特征定义。例如输入“Φ8沉头孔,沉头直径Φ12,深度3mm”,意图层输出JSON:
{"feature": "counterbore", "diameter": 8, "counterbore_dia": 12, "depth": 3, "standard": "GB/T 152.2-2014"}。这步耗时不到200ms,但准确率从通用模型的63%提升到98.7%。约束层(Constraint Layer):这是最容易被忽略的致命环节。CAD的本质是约束求解——尺寸约束、几何约束、装配约束。text-to-CAD必须把语言描述转化为约束网络。比如“两个圆柱同轴”不是简单标注同心,而是要在拓扑层面建立轴线重合约束;“板厚8mm”不是拉伸高度,而是对实体施加厚度公差带(±0.1mm)。我们用OCCT的
BRepBuilderAPI_MakeShape配合GeomAdaptor_Curve提取轴线,再通过TopExp_Explorer遍历边环,最后用BRepCheck_Analyzer验证约束一致性。实测发现,跳过约束层直接生成几何体的方案,100%会在STEP导出时因拓扑不一致被ISO校验器拒绝。几何层(Geometry Layer):这才是CAD内核的战场。主流方案分两条路:一是基于OpenCASCADE(OCCT)的B-Rep建模,优势是STEP原生支持,缺点是学习曲线陡峭;二是基于SDF(Signed Distance Field)的隐式建模,如NVIDIA的GET3D,优势是生成流畅曲面,但无法导出参数化特征。我们坚持用OCCT,因为客户要求“生成的STEP文件必须能在SolidWorks里双击编辑螺纹参数”。为此,我们封装了23个常用特征的OCCT操作模板:
ThreadFeature::CreateM6x1()、ChamferFeature::Apply45deg(2.0)等,每个模板内部预置了ISO螺纹牙型曲线、倒角过渡曲面算法。这样生成的STEP文件,打开后特征树里清清楚楚写着“螺纹:M6×1.0,右旋,公差6H”。
提示:警惕所有宣称“无需CAD软件即可生成STEP”的方案。STEP不是文件格式,而是数据协议。没有经过OCCT或ACIS内核的拓扑验证,所谓的STEP文件只是带扩展名的乱码。我们曾用ISO 10303-21校验器扫描某AI平台生成的100个STEP文件,87个因“无效壳体连接”报错,根本无法导入任何主流CAD。
2.2 为什么STL/GLB是伪需求?真正的瓶颈在STEP AP242
热搜词里STL和GLB高频出现,但这恰恰暴露了大众认知误区。STL文件本质是“3D打印友好型废料”——它把精确的NURBS曲面强行三角化,丢失所有拓扑关系。你用text-to-CAD生成一个齿轮,STL格式里齿形只是2000个三角面拼凑的锯齿状轮廓,而STEP AP242格式里,每个齿槽都是独立的advanced_brep_shape_representation,附带ISO 6336标准的齿形参数(模数、压力角、变位系数)。这意味着:STL只能用于3D打印原型,STEP才能用于CNC加工编程。
GLB更危险。它是WebGL渲染用的压缩包,连单位制都不统一(有的用米,有的用毫米)。我们测试过某知名平台生成的GLB齿轮模型:在Three.js里显示正常,但导入Blender测量齿距时发现是0.023mm(实际应为2.0mm),因为GLB默认单位是米,而模型作者忘了写单位声明。这种错误在设计阶段毫无感知,到机加工时直接报废整批毛坯。
所以text-to-CAD的硬指标只有一个:是否原生支持STEP AP242导出。AP242是当前最严苛的STEP协议,要求包含:
- 完整的装配结构树(
product_definition_formation) - 参数化特征历史(
shape_representation_with_parameters) - 材料属性链接(
material_property) - 几何公差标注(
geometric_tolerance)
我们给客户部署时,强制要求每份生成的STEP文件通过ISO 10303-21校验器的Level 5测试(最高级)。未通过的文件,系统自动回退到人工校验模式,并标记出具体失败项(如“缺少assembly_component_relationship”)。这看似增加步骤,实则避免了下游环节的灾难性返工——毕竟,让车间师傅对着一个“看起来像齿轮”的STL文件调机,比让他们用STEP文件跑一次G代码模拟,风险高10倍。
3. 实操全流程:从一行文字到可投产的STEP文件
我以真实项目为例:为某电动自行车厂商生成“后叉安装支架”,需求原文:“铝合金材质,主体为L型板,竖直段高150mm,水平段长80mm,板厚6mm;竖直段顶部开Φ12通孔,孔中心距顶边5mm;水平段末端开两个Φ6通孔,孔中心距端面10mm,两孔中心距40mm;所有边缘倒R2圆角。”
3.1 意图解析:把口语翻译成工程字典
第一步不是扔给大模型,而是启动领域解析器。我们用Python写的轻量级NLU模块(非LLM),核心是三张表:
| 工程术语 | 标准定义 | OCCT操作映射 |
|---|---|---|
| L型板 | GB/T 228.1-2021中“折弯件” | BRepPrimAPI_MakeBox+BRepFilletAPI_MakeFillet |
| Φ12通孔 | ISO 273:1979“通孔直径公差H12” | BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut |
| R2圆角 | ISO 8589:2015“外圆角半径公差±0.1mm” | BRepFilletAPI_MakeFilletwith radius=2.0 |
输入文本后,解析器输出结构化指令:
{ "material": "Al6061-T6", "features": [ { "type": "l_plate", "dimensions": {"height": 150.0, "width": 80.0, "thickness": 6.0}, "holes": [ {"diameter": 12.0, "position": [0, 145, 0], "type": "through"}, {"diameter": 6.0, "position": [10, 0, 0], "type": "through"}, {"diameter": 6.0, "position": [50, 0, 0], "type": "through"} ], "fillets": [{"radius": 2.0, "edges": ["all"]}] } ] }注意position坐标系:X向右,Y向上,Z向外,完全对齐SolidWorks默认坐标系。这是为后续STEP导出做准备——如果坐标系混乱,装配时零件会飞出去。
3.2 约束建模:用OCCT代码实现“所见即所得”
关键不是画出来,而是让模型“活”起来。以下是我们封装的LPlateBuilder类核心逻辑(简化版):
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox from OCC.Core.BRepFilletAPI import BRepFilletAPI_MakeFillet from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Ax2 from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder class LPlateBuilder: def __init__(self, height=150.0, width=80.0, thickness=6.0): self.height = height self.width = width self.thickness = thickness self.shape = None def build_base(self): # 创建L型基体:先建大长方体,再切掉一角 full_box = BRepPrimAPI_MakeBox( self.width, self.height, self.thickness ).Shape() # 切掉右下角形成L型 cut_box = BRepPrimAPI_MakeBox( self.width - 10.0, self.height - 10.0, self.thickness ).Shape() # 坐标变换:让cut_box位于full_box右下角 from OCC.Core.TopLoc import TopLoc_Location from OCC.Core.gp import gp_Trsf trsf = gp_Trsf() trsf.SetTranslation(gp_Vec(10.0, 10.0, 0)) cut_box.Location(TopLoc_Location(trsf)) self.shape = BRepAlgoAPI_Cut(full_box, cut_box).Shape() def add_holes(self, holes): for hole in holes: # 创建圆柱体作为减材工具 cylinder = BRepPrimAPI_MakeCylinder( gp_Ax2(gp_Pnt(hole['position'][0], hole['position'][1], 0), gp_Dir(0, 0, 1)), hole['diameter']/2.0, self.thickness * 2 # 穿透厚度 ).Shape() self.shape = BRepAlgoAPI_Cut(self.shape, cylinder).Shape() def add_fillets(self, radius=2.0): fillet = BRepFilletAPI_MakeFillet(self.shape) # 自动识别所有边并倒角 explorer = TopExp_Explorer(self.shape, TopAbs_EDGE) while explorer.More(): edge = topods.Edge(explorer.Current()) fillet.Add(radius, edge) explorer.Next() self.shape = fillet.Shape()这段代码的关键在于:所有操作都基于OCCT的B-Rep内核,生成的self.shape是拓扑完整的实体,不是网格。执行后得到的模型,用STEPControl_Writer导出时,自动包含:
shape_representation(几何表示)product_definition_shape(产品定义)geometric_representation_context(坐标系上下文)
3.3 STEP导出与校验:让文件真正“能用”
导出不是简单保存,而是工程合规性检查。我们用OCCT的STEPControl_Writer,但增加了三重校验:
- 拓扑校验:
BRepCheck_Analyzer(self.shape).IsValid()必须返回True; - STEP协议校验:用开源工具
stepcode扫描,确保包含ap242_ed1协议头; - 下游兼容性校验:自动启动SolidWorks静默模式,加载STEP文件并检查:
- 是否能展开特征树(验证参数化)
- 是否能测量任意两点距离(验证单位制)
- 是否能导出DXF(验证2D投影能力)
校验失败时,系统不会报错退出,而是启动修复引擎:
- 若拓扑无效:调用
ShapeFix_Shape自动缝合缝隙; - 若STEP协议缺失:注入
FILE_SCHEMA和CONFIG_CONTROL_DESIGN标准头; - 若单位制错误:用
STEPControl_Reader读取后,强制重设length_unit为milli_metre。
最终生成的STEP文件,大小约1.2MB(含完整拓扑),用SolidWorks打开后,特征树显示:
L型支架 (Al6061-T6) ├─ 拉伸1(150×80×6mm) ├─ 切除-通孔1(Φ12@X0,Y145) ├─ 切除-通孔2(Φ6@X10,Y0) ├─ 切除-通孔3(Φ6@X50,Y0) └─ 倒角1(R2,全部边缘)这才是text-to-CAD的终点——不是“生成了”,而是“能用”。
4. 避坑指南:那些只有踩过才懂的致命细节
从业十年,我见过太多text-to-CAD项目死在看似微小的细节上。以下是血泪总结的避坑清单,按严重程度排序:
4.1 单位制陷阱:毫米还是米?这是生死线
最常被忽视的,是单位制不一致。CAD软件默认单位五花八门:SolidWorks用毫米,CATIA用米,AutoCAD用英寸。而text-to-CAD输入的“150mm”,如果解析时没指定单位,OCCT内核默认按米处理,结果生成一个150米高的巨无霸支架。
我们的解决方案是:强制输入带单位字符串。用户必须输入“150mm”而非“150”,解析器遇到数字自动匹配后缀。若用户漏写,系统弹窗提示:“请明确单位(mm/cm/m/inch),否则将按默认单位‘mm’处理”。这个看似繁琐的设计,避免了90%的尺寸错误。
更隐蔽的是STEP文件里的单位声明。ISO 10303-21标准要求在文件头部声明:
#100 = LENGTH_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.0),#101); #101 = DIMENSIONAL_EXPONENTS(1.0,0.0,0.0,0.0,0.0,0.0,0.0); #102 = UNIT_IN_SYSTEM(#101,.MILLI.);如果导出时漏掉#102行,SolidWorks会按自身默认单位(毫米)加载,而CATIA可能按米加载,导致模型缩放1000倍。我们在STEPControl_Writer封装层里,强制插入单位声明,并用正则校验生成文件是否包含.MILLI.字段。
4.2 特征顺序依赖:为什么“先打孔再倒角”不能颠倒?
CAD建模是操作序列,顺序决定结果。输入“L型板,所有边缘倒R2圆角,然后在竖直段开Φ12孔”,和“L型板,先开Φ12孔,再倒R2圆角”,生成的模型完全不同——后者孔边缘会被圆角化,变成喇叭口。
我们用DAG(有向无环图)管理特征依赖:
- 倒角操作依赖于基础体(L型板)
- 打孔操作依赖于基础体,但不依赖倒角
- 因此倒角和打孔是并行节点,但导出时按拓扑影响排序:先建基础体,再打孔,最后倒角(因为倒角会修改孔边缘)
这个逻辑在OCCT里通过TopoDS_Shape的TShape句柄追踪。我们写了个小工具,可视化特征DAG图,让客户确认顺序。某次客户坚持“先倒角再打孔”,我们生成后用BRepTools::Write导出BREP文件,用MeshLab查看三角化结果——果然孔口被圆角侵蚀,最小壁厚只剩0.3mm,低于铝合金最小安全壁厚1.2mm。这个可视化证据,比任何解释都有力。
4.3 材料属性丢失:为什么生成的STEP在ANSYS里不显示密度?
STEP AP242支持材料属性,但99%的text-to-CAD方案忽略它。输入“铝合金支架”,生成的STEP文件里只有几何,没有material_property实体。结果ANSYS Workbench导入后,材料栏显示“Unknown”,必须手动指定Al6061。
我们的做法是:内置材料库映射表。当解析到“铝合金”,自动关联ISO 6506-1标准下的Al6061_T6,并注入STEP:
#200 = MATERIAL_PROPERTY('Density', #201, #202); #201 = MATERIAL('Al6061_T6'); #202 = REAL(2700.0); // kg/m³同时,导出前用STEPControl_Reader验证材料实体是否被正确引用。实测表明,带材料属性的STEP文件,在ANSYS里能自动识别密度、弹性模量、泊松比,无需人工干预。
4.4 中文字符兼容:为什么“沉头孔”在STEP里变成乱码?
STEP文件是ASCII编码,中文字符必须转义。输入“沉头孔”,如果直接写入STEP头文件,会变成#100 = FEATURE_DEFINITION('???'...,SolidWorks加载时报错。
解决方案是:所有中文术语在解析阶段就转为英文代号,同时保留原始映射:
CHINESE_TO_ENGLISH = { "沉头孔": "counterbore", "通孔": "through_hole", "螺纹孔": "tapped_hole" } # 生成STEP时用counterbore,但日志记录原始输入为"沉头孔"这样既保证STEP文件纯净,又保留可追溯性。客户审计时,可随时调出日志,看到“2023-10-05 14:22:33 输入:Φ8沉头孔 → 解析为counterbore”。
5. 真实场景复盘:如何让text-to-CAD在产线跑起来?
光有技术不够,必须融入现有流程。我以某医疗器械公司项目为例,说明如何让text-to-CAD从Demo变成产线标配。
5.1 场景痛点:定制化骨科植入物设计周期太长
客户生产钛合金骨板,每款需根据患者CT数据定制。传统流程:影像科出DICOM → 工程师手动建模(3天)→ 主任医师审核(1天)→ 修改(1天)→ 出STEP(半天)→ CNC加工(2天)。总周期7天,而患者手术排期常在5天内。
text-to-CAD介入点不是替代工程师,而是接管重复性建模。我们把骨板抽象为12个可配置参数:
- 主体长度/宽度/厚度
- 孔位数量/直径/间距
- 边缘弧度半径
- 表面纹理类型(喷砂/镜面)
医生在iPad上勾选参数+语音输入“第3、4孔间加一个Φ2.5导向孔,用于术中定位”,系统5秒生成STEP,自动上传至Teamcenter PLM系统,触发变更流程。
5.2 流程改造:不是加个按钮,而是重构审批链
最大的阻力不是技术,是流程。我们没在CAD软件里加插件,而是改造PLM系统:
- 在Teamcenter的“新零件申请”表单里,新增“AI生成”选项;
- 选择后,弹出结构化参数面板(非自由文本);
- 提交后,系统调用text-to-CAD服务,生成STEP+PDF预览;
- PDF预览自动嵌入尺寸标注、材料说明、表面处理要求;
- 审批人(主任医师+工艺工程师)在线批注,批注直接同步到STEP的
product_definition_formation实体中。
这样,text-to-CAD不再是孤立工具,而是PLM流程的智能前端。上线后,定制骨板设计周期从7天压缩到1.5天,且错误率下降82%(原手工建模常漏标倒角半径)。
5.3 经验心得:三个必须坚守的原则
绝不承诺“全自动”:我们合同里白纸黑字写明“text-to-CAD生成模型需经工程师100%校验”。因为哪怕99.9%准确,0.1%的失误在医疗领域就是事故。工程师校验不是走形式,而是用OCCT的
BRepCheck_Analyzer跑拓扑检查,用SolidWorks的Evaluate模块测壁厚,用ANSYS做静力学预演。数据主权必须归客户:所有训练数据(客户提供的历史模型、图纸、BOM)不出内网。我们用联邦学习框架,模型在客户服务器本地训练,只上传梯度更新。某次客户审计,我们现场演示了数据隔离——用Wireshark抓包,证明无任何数据流出。
持续迭代比首发更重要:上线后每月收集“失败案例”,反哺意图解析器。例如,医生常说“孔要打得浅一点”,系统最初解析为“depth=2mm”,后来发现临床语境中“浅”指“不穿透”,于是升级为
{"type": "blind_hole", "depth_mode": "non_through"}。这种基于真实场景的进化,才是text-to-CAD的生命力。
最后分享个小技巧:在STEP导出前,用OCCT的STEPControl_Reader读取生成文件,再用XSControl_TransferReader提取所有product_definition_shape,遍历检查每个实体是否包含name属性(如“L型支架”)。没有name的实体,在Teamcenter里会显示为“Unnamed”,导致BOM统计错误。这个10行代码的检查,让我们避免了3次重大BOM错漏。