1. 从一句话到三维实体:text-to-cad 到底在解决什么问题
第一次听到 "text-to-cad" 这个词,很多人脑子里浮现的画面大概是:对着电脑说一句"给我画个法兰盘",屏幕上就自动长出一个带螺栓孔的三维模型。这个想象不算离谱,但真正落地的时候,它解决的问题比"省几次鼠标点击"要深刻得多。
传统 CAD 工作流的本质是人肉翻译。设计师脑子里有一个几何意图,比如"一个外径 80mm、内径 40mm、厚度 12mm 的圆环,沿圆周均布 6 个直径 6mm 的通孔",然后他要把这个意图翻译成一连串操作:草图、约束、拉伸、阵列、倒角。这个翻译过程占了建模时间的绝大部分,而且极易出错——改一个尺寸,可能要重新走一遍特征树。text-to-cad 想干的事情,是把"几何意图"直接变成"几何结果",中间那层手工翻译交给程序。
这里必须先把一个概念掰清楚:text-to-cad 不是"AI 画图"。市面上很多所谓 AI 生成 3D 模型,输出的是三角网格(mesh),比如 STL、OBJ 这类格式。网格模型看着像那么回事,但它没有参数、没有特征历史、没有精确的圆柱面和平面,你没法在它上面标注尺寸,也没法改一个孔径让整条特征链自动更新。而真正的 CAD 模型是边界表示(B-rep),由精确的解析曲面(平面、圆柱面、圆锥面、球面、环面)和 NURBS 曲面构成,带拓扑关系,能被下游的 CAM、仿真、装配直接消费。
所以 text-to-cad 的技术核心,不是"生成一个看起来像的模型",而是"生成一个可编辑、可制造、可装配的精确模型"。这就决定了它的输出格式选择非常关键,也是后面要重点聊的 STEP、URDF、G-code 三条路线分野的根源。
从关键词和热搜词能看出来,关注这个方向的人大致分三类。第一类是机械/结构工程师,他们关心的是"能不能直接出 STEP 给加工";第二类是机器人方向的研究者,热搜里 urdf 导入 coppeliasim 这种词暴露了他们的需求——他们要的是带关节、带运动学链的模型,用来做仿真;第三类是创客和 DIY 玩家,他们想要的是能直接丢给 3D 打印机或 CNC 的 G-code。这三类人的需求差异巨大,但底层都指向同一件事:用文本描述驱动几何生成。
我个人的判断是,text-to-cad 目前最有价值的场景不是"替代设计师",而是批量化和参数化。比如你要生成 200 个不同规格的法兰,或者要根据一份 Excel 参数表自动出图,这种活儿人做起来痛苦且容易错,程序做起来又快又稳。理解了这一点,后面的技术选型和实操才有方向。
2. 文本描述怎么变成几何:解析、约束与建模内核的三层拆解
要把"一句话"变成"一个实体",中间至少要过三道关。很多人以为难点在"理解自然语言",其实那只是第一关,真正难的是后面两关。
2.1 第一层:从自然语言里抽出结构化参数
自然语言描述几何有个天然缺陷——歧义和缺省。"一个带孔的圆盘",孔在哪?几个?多大?这些信息人可能靠上下文脑补,但程序不行。所以 text-to-cad 的第一步,通常不是直接上大语言模型硬生成几何,而是先把文本结构化成一份参数清单。
常见的做法是定义一个中间表示(IR),比如 JSON schema:
{ "primitive": "cylinder", "params": { "outer_diameter": 80, "inner_diameter": 40, "thickness": 12 }, "features": [ { "type": "hole_pattern", "hole_diameter": 6, "count": 6, "pattern": "circular", "pcd": 60 } ] }这份 JSON 才是真正驱动建模的东西。大语言模型在这里的角色是"翻译官",把中文/英文描述翻译成这份结构化参数,而不是直接吐几何。这样做的好处非常实在:参数可校验、可复用、可批量替换。你只要改 JSON 里的数字,就能生成一整个系列。
提示:如果你打算自己搭一套 text-to-cad 流程,强烈建议先定义好这份中间表示,再考虑接哪个大模型。IR 设计得好,后面换模型、换建模内核都不伤筋动骨;IR 设计得烂,模型再强也救不回来。
这里有个实操经验:单位必须显式声明。我见过太多翻车案例,模型默认按英寸理解,结果生成一个 80 英寸的圆盘,导入装配体直接爆炸。在 IR 里强制加一个"unit": "mm"字段,能省掉无数麻烦。
2.2 第二层:几何约束求解,决定模型"能不能改"
参数有了,接下来是把它变成带约束的草图。这一步是 text-to-cad 和"网格生成"最大的分水岭。真正的 CAD 建模内核(比如 OpenCASCADE、Parasolid、ACIS)支持参数化特征,你拉伸一个圆,这个圆是"直径 80 的圆",而不是"由 64 段直线拼成的近似圆"。
为什么这很重要?因为下游要改。假设客户说"孔径从 6 改成 8",参数化模型只需要改一个数,特征树自动重算;网格模型则要重新生成整个网格,而且孔壁会变得粗糙。这就是为什么工业界坚持用 B-rep。
开源方案里,OpenCASCADE(OCCT)是绕不开的选择。它提供了完整的 B-rep 建模能力,Python 绑定有pythonocc-core,也有更上层的CadQuery和build123d。CadQuery 的定位就是"用代码写 CAD",它的语法非常接近 text-to-cad 需要的表达方式:
import cadquery as cq result = ( cq.Workplane("XY") .circle(40) # 外径 80,半径 40 .circle(20) # 内径 40,半径 20 .extrude(12) # 厚度 12 .faces(">Z") .workplane() .polarArray(30, 0, 360, 6) # PCD 60,半径 30,6 个 .hole(6) # 孔径 6 )这段代码生成的模型,导出 STEP 之后在任何主流 CAD 里打开都是可编辑的实体,特征清晰。这就是 text-to-cad 该有的样子——文本描述经过 IR,最终落到参数化建模 API 上。
2.3 第三层:建模内核的选型,直接决定输出能力
选哪个内核,取决于你要输出什么。这里给一张对照表,是我自己踩过坑之后总结的:
| 建模内核/库 | 输出格式 | 参数化能力 | 适用场景 | 上手难度 |
|---|---|---|---|---|
| OpenCASCADE (OCCT) | STEP, IGES, STL | 强 | 通用机械、工业级 | 高 |
| CadQuery | STEP, STL, DXF | 强 | 脚本化建模、批量出图 | 中 |
| build123d | STEP, STL | 强 | 新一代 Python 建模 | 中 |
| trimesh | STL, OBJ, PLY | 无 | 网格处理、3D 打印 | 低 |
| FreeCAD (Python API) | STEP, IGES, STL, FCStd | 强 | 桌面集成、二次开发 | 中 |
如果你只是想做 3D 打印的小玩意,trimesh 加个网格生成就够了,没必要上 OCCT 这种重武器。但如果你要出工程图、要做装配、要对接 CAM,那必须走 B-rep 路线,CadQuery 或 build123d 是性价比最高的入口。
我自己的习惯是:原型阶段用 CadQuery 快速验证几何逻辑,量产阶段把逻辑固化成参数化脚本。CadQuery 的exporters.export(result, "part.step")一行就能出 STEP,非常省事。
3. STEP、URDF、G-code:三种输出格式背后的三条技术路线
热搜词里同时出现了 STEP、URDF、G-code,这不是巧合。这三个格式代表了 text-to-cad 落地的三个完全不同的下游方向,选错了格式,整个项目就白干。
3.1 STEP:机械制造的通用语言
STEP(ISO 10303)是工业界交换 CAD 数据的标准格式。它的核心价值是保真——精确的 B-rep 几何、装配结构、颜色、图层信息都能带过去。你从 CadQuery 导出的 STEP,丢进 SolidWorks、UG、中望 CAD、FreeCAD 里打开,几何是精确的,尺寸是可测的。
text-to-cad 输出 STEP 的典型流程:
import cadquery as cq # 建模 part = cq.Workplane("XY").box(50, 30, 10).edges("|Z").fillet(3) # 导出 STEP cq.exporters.export(part, "bracket.step")导出之后,你可以直接把这个 STEP 丢给 CAM 软件做刀路,或者丢给仿真软件做有限元。这是最"正统"的 text-to-cad 落地路径。
注意:STEP 有 AP203、AP214、AP242 等多个版本。AP242 支持 PMI(产品制造信息,也就是三维标注),如果你要做 MBD(基于模型的定义),务必选 AP242。CadQuery 默认导出的版本在多数场景够用,但对接高端 PLM 系统时要注意版本兼容。
3.2 URDF:机器人仿真的入场券
URDF(Unified Robot Description Format)是 ROS 生态里的机器人描述格式,本质是一个 XML。它描述的不是"一个零件",而是"一堆零件怎么连起来、怎么动"。热搜里"urdf 导入 coppeliasim"说明很多人卡在把模型送进仿真环境这一步。
text-to-cad 生成 URDF 的难点在于:URDF 需要的是带关节的装配体,而不是单个实体。你得先有各个连杆(link)的几何,再定义关节(joint)的类型、轴向、限位。一个典型的 URDF 片段长这样:
<robot name="arm"> <link name="base_link"> <visual> <geometry> <mesh filename="base.stl" scale="0.001 0.001 0.001"/> </geometry> </visual> </link> <joint name="joint1" type="revolute"> <parent link="base_link"/> <child link="link1"/> <axis xyz="0 0 1"/> <limit lower="-3.14" upper="3.14" effort="10" velocity="1"/> </joint> </robot>这里有个大坑:URDF 的 visual 几何通常用 mesh(STL/DAE),而不是 STEP。因为仿真引擎(Gazebo、CoppeliaSim)对 B-rep 支持很差,它们要的是三角网格。所以 text-to-cad 走 URDF 路线时,往往要"双份输出"——STEP 给制造,STL 给仿真,两者共享同一套参数。
单位问题在 URDF 里尤其致命。ROS 默认单位是米,而 CAD 建模常用毫米。上面代码里的scale="0.001 0.001 0.001"就是在做毫米到米的转换。忘了这一步,你的机器人会在仿真里变成一栋楼那么大。
3.3 G-code:从模型到机床的最后一步
G-code 是数控机床和 3D 打印机的指令语言。text-to-cad 直接输出 G-code 的场景,主要是 3D 打印和简单 2.5 轴加工。但严格来说,G-code 不该由 CAD 直接生成,中间必须经过 CAM(切片或刀路规划)。
正确的链路是:text → CAD 模型(STEP/STL)→ CAM/切片 → G-code。跳过 CAM 直接生成 G-code,等于让建模程序去干工艺规划的活,结果通常不能用。
以 3D 打印为例,CadQuery 出 STL,再用切片软件(Cura、PrusaSlicer)出 G-code:
# 第一步:出 STL cq.exporters.export(part, "part.stl") # 第二步:命令行切片(以 PrusaSlicer 为例) # prusa-slicer --export-gcode --load config.ini part.stl如果你要做的是激光切割或钣金,那输出的是 DXF 而不是 G-code,CadQuery 同样支持exporters.export(part, "part.dxf")。
三条路线的选择逻辑,我总结成一句话:要造实物走 STEP,要跑仿真走 URDF,要上机器走 G-code,但 G-code 前面必须补 CAM。
4. 动手搭一条最小可用的 text-to-cad 流水线
光讲原理没意思,这一节直接给一条能跑起来的流水线。目标:输入一句中文描述,输出一个 STEP 文件。技术栈选 Python + CadQuery,因为它的依赖相对干净,社区活跃,文档也够用。
4.1 环境准备里最容易翻车的依赖问题
CadQuery 的安装是新手第一道坎。它底层依赖 OCCT,而 OCCT 的二进制包在不同平台上差异很大。最省心的方式是用 conda 装,而不是 pip:
conda create -n t2cad python=3.11 conda activate t2cad conda install -c conda-forge cadquery为什么推荐 conda?因为 conda-forge 上的 cadquery 包已经把 OCCT 的二进制依赖打包好了,pip 装的话经常遇到编译错误或者运行时找不到动态库。热搜里"安装 cad 一直出现 c++2005 cpi 错误"这类问题,本质都是运行库缺失,conda 能规避掉大部分。
装完之后验证一下:
import cadquery as cq print(cq.__version__) box = cq.Workplane("XY").box(10, 10, 10) cq.exporters.export(box, "test.step")能导出 test.step 就说明环境通了。
4.2 把中文描述翻译成建模脚本的完整链路
假设用户输入:"生成一个 100x60x8 的底板,四角各有一个直径 5 的通孔,孔中心距边缘 10mm。"
第一步,用大模型把它转成结构化参数。这里给一个 prompt 模板的思路:
你是一个 CAD 参数解析器。把用户的几何描述转成如下 JSON: { "base": {"type": "box", "length": ..., "width": ..., "height": ...}, "features": [{"type": "hole", "diameter": ..., "positions": [...]}] } 只输出 JSON,不要解释。第二步,写一个渲染器,把 JSON 变成 CadQuery 代码:
import cadquery as cq import json def build_from_spec(spec): base = spec["base"] wp = cq.Workplane("XY").box(base["length"], base["width"], base["height"]) for feat in spec.get("features", []): if feat["type"] == "hole": for pos in feat["positions"]: wp = wp.faces(">Z").workplane().center(pos[0], pos[1]).hole(feat["diameter"]) return wp spec = { "base": {"type": "box", "length": 100, "width": 60, "height": 8}, "features": [ {"type": "hole", "diameter": 5, "positions": [[-40, -20], [40, -20], [-40, 20], [40, 20]]} ] } part = build_from_spec(spec) cq.exporters.export(part, "plate.step")这段代码跑通,你就有了一个最小可用的 text-to-cad 原型。注意孔的位置计算:底板 100x60,孔中心距边缘 10,所以 x 方向是 ±(50-10)=±40,y 方向是 ±(30-10)=±20。这种坐标换算,最好在 IR 层面就算好,别留给建模脚本,否则逻辑会越来越乱。
4.3 批量生成时怎么避免"改一个崩一片"
批量场景是 text-to-cad 真正发光的地方。比如你要生成 50 个不同长度的支架,参数来自一份 CSV:
import csv import cadquery as cq def make_bracket(length): return (cq.Workplane("XY") .box(length, 20, 5) .faces(">Z").workplane() .rect(length-10, 10, forConstruction=True) .vertices().hole(3)) with open("params.csv") as f: for row in csv.DictReader(f): part = make_bracket(float(row["length"])) cq.exporters.export(part, f"bracket_{row['id']}.step")这里的关键是把建模逻辑封装成纯函数,输入参数、输出实体,不依赖任何全局状态。这样每个模型都是独立可复现的,改一个参数不会影响其他模型。我见过有人把参数写成全局变量,结果批量生成时后一个模型覆盖了前一个的设置,排查了半天。
提示:批量生成时给每个文件加上参数指纹(比如把关键尺寸拼进文件名),后期追溯会轻松很多。别小看这个习惯,几十个模型混在一起的时候,没有命名规范就是灾难。
5. 实测中那些文档不会告诉你的坑
这一节全是血泪。文档里不会写的东西,往往才是决定项目成败的。
5.1 单位、精度与容差:三个隐形杀手
单位前面提过,但值得再强调。CAD 内核本身不关心单位,它只认数字。是 STEP 文件头里的单位声明、是 URDF 里的 scale、是切片软件里的设置,在决定这个数字是毫米还是米。整条链路上任何一环单位不一致,结果就是灾难。我的做法是:IR 里强制带单位,导出前做一次单位断言。
精度是第二个坑。浮点数运算在几何里会累积误差,尤其是做布尔运算(并、交、差)的时候。两个面理论上重合,实际可能差 1e-9,导致布尔运算失败或者产生碎面。OCCT 有容差(tolerance)机制,默认 1e-7 米,但不同操作可能需要调整。遇到布尔运算莫名其妙失败,先怀疑容差。
容差还影响 STEP 的互操作性。你导出的 STEP 在 A 软件里好好的,在 B 软件里报"几何无效",多半是容差设置不兼容。导出时尽量用保守的容差,别为了追求"精确"把容差调到极小。
5.2 复杂特征树导致的导出失败排查链路
有一次我做一个带 30 多个特征的零件,CadQuery 里显示正常,导出 STEP 却报错。排查过程值得记录:
第一步,二分定位。把特征树从中间砍断,只导出前半部分,看是否成功。成功说明问题在后半段,失败说明在前半段。反复二分,快速缩小范围。
第二步,单独复现。把可疑的特征单独拎出来建一个最小模型,看能否导出。我最后定位到是一个fillet(倒圆角)操作,圆角半径大于相邻面的尺寸,导致几何自交。
第三步,降级处理。把出问题的圆角半径改小,或者改用chamfer(倒角),问题消失。根本原因是圆角半径和局部几何冲突,这在薄壁件上特别常见。
这个排查思路可以推广到所有几何报错:二分定位 → 单独复现 → 降级或重构。别一上来就怀疑内核有 bug,99% 的问题出在几何本身。
5.3 从 STEP 到 URDF 的转换为什么总是丢东西
把 CAD 装配体转成 URDF,是机器人方向最常踩的坑。STEP 里有装配层级、有零件名、有配合关系,但 URDF 要的是 link 和 joint,两者的语义模型不一样。转换时常见的丢失:
- 配合关系丢失:STEP 里的"同轴配合"在 URDF 里要显式写成 joint 的 axis,不会自动继承。
- 材质和颜色丢失:URDF 的 visual 要单独指定 material,STEP 里的颜色不一定带得过来。
- 坐标系错位:STEP 里每个零件有自己的局部坐标系,URDF 里 link 的坐标系原点要手动对齐,否则装配起来是散的。
实操建议:别指望全自动转换。用 FreeCAD 或 Blender 做中间处理,手动确认每个 link 的坐标系和 joint 的轴向,比事后在仿真里调半天强。热搜里"urdf 导入 coppeliasim"的问题,八成都是坐标系没对齐。
6. 这套东西到底适合谁,以及我踩过之后的几点判断
text-to-cad 不是万能药,它有明确的适用边界。用对了场景,效率提升是数量级的;用错了,还不如手画。
最适合的场景:参数化系列件(法兰、支架、型材连接件)、标准件库批量生成、需要频繁改尺寸的迭代设计、机器人连杆的快速建模。这些场景的共同点是几何逻辑清晰、参数可枚举,程序化生成的优势最大。
不太适合的场景:高度自由曲面(比如汽车外形、消费电子外壳)、需要大量审美判断的造型设计、一次性非标件。这些场景里,人的直觉和审美还是不可替代的,硬上 text-to-cad 反而绕远路。
我自己的体会是,text-to-cad 的价值不在"生成",而在"可复现"。手画一个零件,三个月后你自己都记不清当时怎么建的;用脚本生成的零件,参数和逻辑都在代码里,随时能复现、能改、能追溯。这种可复现性,在团队协作和长期维护里,比省下的那点建模时间值钱得多。
最后分享一个我常用的技巧:把常用的几何模式沉淀成函数库。比如"带均布孔的圆盘""带加强筋的支架""标准型材截面",每个都封装成一个函数,下次直接调用。积累半年,你会发现大部分建模需求都能用现成的函数拼出来,这才是 text-to-cad 真正的复利所在。