1. 从一段文字到三维模型:text-to-cad 到底在解决什么问题
第一次听到 “text-to-cad” 这个说法,我脑子里蹦出来的画面是:对着屏幕敲一句“给我画一个 80×60×10 的法兰盘,中心开 30 的通孔,四角打 M6 沉头孔”,然后 CAD 软件自己把模型建好、把工程图出完。这个画面在几年前还属于科幻范畴,但最近一两年,随着大模型在代码生成和结构化数据生成上的能力外溢,它已经变成了一个可以动手落地的工程方向。所谓 text-to-cad,本质上是把自然语言描述转换成CAD 可识别的几何数据,最终产出 STEP、GLB、STL 这类通用三维格式文件,让下游的建模、渲染、3D 打印、仿真环节可以直接消费。
这件事的价值在哪里?我举个自己踩过的场景。做非标设备设计的时候,经常要画大量“标准件变体”——不同孔径、不同长度、不同法兰规格的支架、连接板、垫块。这些东西结构高度相似,只是参数不同,但每改一次就要在 CAD 里重复一遍拉伸、打孔、倒角、阵列的操作。一个熟练工一天也就出十几个变体,还容易改错尺寸。如果能把“描述”直接变成模型,哪怕只覆盖 60% 的常规件,效率提升也是数量级的。这就是 text-to-cad 最直接的需求来源:参数化、批量化、低门槛的模型生成。
它适合谁来用?我梳理了一下,大致三类人受益最明显。第一类是机械、钣金、建筑领域的工程师,他们懂设计意图但不想把时间耗在重复建模上;第二类是产品经理、创客、3D 打印爱好者,他们有想法但不会用 SolidWorks、中望 CAD 这类工具,希望能用说话的方式把东西“说”出来;第三类是做 AI 应用开发的程序员,他们想把 CAD 生成能力集成到自己的平台里,比如做一个在线的零件定制页面。这三类人的诉求不一样,但底层都指向同一件事:把几何建模的门槛从“会软件”降到“会描述”。
需要先泼一盆冷水:text-to-cad 目前不是万能的。它擅长的是规则明确、参数清晰的零件,比如板类、轴类、法兰、简单壳体;对于复杂曲面、自由造型、装配体干涉这些,现阶段还很难靠一句话搞定。所以我在后面的内容里,会重点讲清楚它的能力边界在哪里,以及怎么用工程化的方式把它用稳。你如果抱着“一句话生成一台发动机”的期待,那大概率会失望;但如果你把它当成一个“参数化建模的加速器”,它会非常香。
2. 整体技术路线拆解:从一句话到 STEP/GLB/STL 的完整链路
2.1 为什么不能直接让大模型“画图”
很多人第一反应是:既然大模型能生成图片,那直接让它生成三维模型不就行了?这个思路在工程上走不通,原因很实在。图片是二维像素网格,而 CAD 模型是带拓扑关系的边界表示(B-rep),它记录的不只是形状,还有面、边、顶点之间的连接关系,以及每个面的数学定义(平面、圆柱面、NURBS 曲面等)。大模型直接“猜”出来的顶点坐标,往往面与面接不上、法线方向乱、实体不封闭,导进 CAD 里要么报错,要么变成一个没法编辑的“死网格”。
所以工业界和开源社区的主流做法,是把任务拆成两步:先让大模型生成结构化的建模指令(代码或参数),再由几何内核去执行这些指令。这就像你不可能让一个翻译直接口述一篇论文的排版,但你可以让他输出 LaTeX 源码,再由编译器排版。大模型负责“理解意图 + 生成代码”,几何内核负责“精确执行”。
2.2 三条主流技术路线对比
我把目前能跑通的方案归成三类,各有各的适用场景,下面这张表是我自己实测后的总结:
| 路线 | 核心思路 | 代表工具 | 输出格式 | 适合场景 | 上手难度 |
|---|---|---|---|---|---|
| 代码驱动型 | 大模型生成 CadQuery/OpenSCAD 代码,内核执行 | CadQuery、OpenSCAD、build123d | STEP、STL | 参数化零件、批量变体 | 中 |
| 参数映射型 | 预定义模板 + 大模型填参数 | 自研模板库 + LLM | STEP、GLB | 标准件、系列化产品 | 低 |
| 网格生成型 | 直接生成/检索三维网格 | 文生3D模型、网格重建 | STL、GLB | 概念展示、3D 打印摆件 | 低但精度差 |
我个人的建议是:如果你要做的是能用于生产、能继续编辑的模型,优先选代码驱动型。因为 CadQuery 这类库生成的模型是真正的 B-rep 实体,导出 STEP 后可以在 SolidWorks、中望 CAD 里继续改尺寸、加特征。而网格生成型出来的 STL,虽然 3D 打印能用,但想改一个孔的直径,基本等于重做。
2.3 为什么 STEP、GLB、STL 要分清楚
这三个格式经常被混着用,但它们的定位完全不同,选错了会在下游环节吃大亏。
STEP是工程领域的“通用语言”,它保存的是精确的 B-rep 几何,文件里记录的是数学曲面而不是三角面片。所以 STEP 文件可以无损地导入各种 CAD 软件继续编辑,是 text-to-cad 面向工程应用时的首选输出。缺点是文件体积相对大,且不同软件对 STEP 版本(AP203、AP214、AP242)的兼容性有差异。
STL是 3D 打印和快速预览的“老黄牛”,它只保存三角面片,没有颜色、没有材质、没有拓扑。优点是几乎所有切片软件、渲染器都认它;缺点是精度靠面片密度堆,圆孔会变成多边形,而且没法反向编辑。我见过太多人拿 STL 去 CAD 里想改尺寸,结果发现全是碎面,这就是没搞清格式定位。
GLB是面向可视化、Web 展示和游戏引擎的格式,它把几何、材质、贴图打包成一个二进制文件,加载快、体积小。如果你要做的是一个在网页上让用户旋转查看的零件展示页,GLB 是最优解。但它同样不是精确几何,不适合回传 CAD 做工程修改。
提示:text-to-cad 的输出格式选择,取决于下游是谁在用。给工程师改图用 STEP,给 3D 打印机用 STL,给网页展示用 GLB。不要指望一个格式通吃。
3. 核心实操:用 CadQuery 搭一套能跑的 text-to-cad 流程
3.1 环境准备与依赖安装
我选 CadQuery 作为主力工具,原因是它基于 OpenCASCADE 几何内核,生成的模型是真正的 B-rep 实体,导出 STEP 质量稳定,而且 Python 生态友好,方便和大模型 API 对接。下面是我在 Windows 和 Linux 上都验证过的安装方式。
# 建议用 conda 建独立环境,避免和系统 Python 冲突 conda create -n text2cad python=3.11 conda activate text2cad # 安装 CadQuery,官方推荐用 conda-forge 渠道 conda install -c conda-forge cadquery # 如果要用大模型接口,装 openai 或对应 SDK pip install openai装完之后先跑一个最小验证,确认几何内核正常:
import cadquery as cq # 画一个 80x60x10 的板,中心开 30 通孔 result = ( cq.Workplane("XY") .box(80, 60, 10) .faces(">Z").workplane().hole(30) ) cq.exporters.export(result, "test_plate.step") print("导出成功")这段代码跑通,说明你的环境没问题。如果报错找不到 OCCT 相关库,八成是 conda 渠道没配对,重新用conda install -c conda-forge cadquery装一遍基本能解决。
3.2 让大模型生成建模代码的提示词设计
这是整个流程里最关键的环节。大模型不是天生就会写 CadQuery 的,你得把“规矩”讲清楚。我反复调试后,总结出一个比较稳的提示词结构,核心是给约束、给示例、给输出格式。
你是一个 CAD 建模代码生成助手。请根据用户的自然语言描述,生成 CadQuery Python 代码。 要求: 1. 只输出可执行的 Python 代码,不要解释。 2. 代码必须以 import cadquery as cq 开头。 3. 最终模型赋值给变量 result。 4. 所有尺寸单位为毫米。 5. 如果描述缺少关键尺寸,按常见工程惯例取合理默认值,并在代码注释中标注。 6. 孔、倒角、阵列等特征要明确写出。 示例: 用户:画一个 100x50x8 的板,四角打 M5 通孔,孔中心距边 10mm 代码: import cadquery as cq result = ( cq.Workplane("XY") .box(100, 50, 8) .faces(">Z").workplane() .rect(80, 30, forConstruction=True) .vertices().hole(5) )这个提示词里,“缺少尺寸取默认值并注释”这一条特别重要。实际使用中,用户很少会把所有尺寸说全,比如“画个法兰盘”,你不给默认值,模型就生成不出来;给了默认值,至少能出一个可用的初版,用户再改。
3.3 完整链路代码:从文字到 STEP 文件
把大模型调用和 CadQuery 执行串起来,核心逻辑就是一个“生成-执行-导出”的循环。下面是我实际在用的简化版脚本:
import cadquery as cq from openai import OpenAI client = OpenAI(api_key="你的key") SYSTEM_PROMPT = """你是一个 CAD 建模代码生成助手...(上面那段提示词)""" def text_to_cad(user_input, output_name="output"): response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_input} ], temperature=0.2 ) code = response.choices[0].message.content # 去掉可能的 markdown 代码块标记 code = code.replace("```python", "").replace("```", "").strip() # 在受限命名空间中执行,避免污染 local_ns = {"cq": cq} exec(code, local_ns) result = local_ns["result"] # 导出三种格式 cq.exporters.export(result, f"{output_name}.step") cq.exporters.export(result, f"{output_name}.stl") print(f"已导出 {output_name}.step 和 {output_name}.stl") return result # 测试 text_to_cad("画一个外径 100、内径 40、厚度 15 的法兰盘,沿圆周均匀分布 6 个直径 8 的螺栓孔,分布圆直径 75")跑通之后,你会得到一个 STEP 文件,用中望 CAD 或 SolidWorks 打开,就是一个可以继续编辑的实体。这里有个细节:temperature我设成 0.2,因为建模代码需要稳定复现,不需要“创意”,温度高了同样的描述每次生成的尺寸可能不一样,这在工程上是大忌。
3.4 参数化模板:比纯生成更稳的方案
纯靠大模型生成代码,偶尔会翻车,比如把hole()的参数顺序搞错,或者忘记闭合工作平面。对于高频使用的零件类型,我的做法是预置参数化模板,让大模型只负责“填参数”,不负责“写逻辑”。这样稳定性大幅提升。
def make_flange(outer_d, inner_d, thickness, bolt_count, bolt_d, pcd): """法兰盘参数化模板""" result = ( cq.Workplane("XY") .circle(outer_d / 2) .circle(inner_d / 2) .extrude(thickness) .faces(">Z").workplane() .polarArray(pcd / 2, 0, 360, bolt_count) .hole(bolt_d) ) return result然后让大模型从用户描述里抽取outer_d、inner_d这些参数,输出 JSON,再由程序调用模板。这条路线的容错率高得多,因为几何逻辑是人工验证过的,大模型只做它最擅长的“语义理解”。我实测下来,模板法在批量生成系列化零件时,成功率接近 100%,而纯生成法大概在 70% 到 85% 之间波动。
4. 实操中的坑与排查:我踩过的那些雷
4.1 模型导出后打不开或显示为空
这是最常见的问题,表现是 STEP 文件能生成,但导入 CAD 软件后什么都没有,或者提示“无效实体”。原因通常有三个:一是模型不是封闭实体,比如用shell或offset时参数不对,导致面片之间有缝隙;二是工作平面选错,模型生成在了奇怪的位置;三是布尔运算失败,比如两个实体没有真正相交却做了cut。
排查方法我总结成一套顺序:先在 CadQuery 里打印result.val().isValid(),如果是False,说明实体本身有问题;再用result.val().Volume()看体积是否为正,体积为负或为零基本可以判定几何异常。定位到具体特征后,把复杂操作拆成单步执行,逐个确认。
注意:CadQuery 里
.hole()默认是通孔,如果你想要盲孔,必须用.cboreHole()或先extrude再cut。我见过有人用.hole()做盲孔,结果把整个板打穿了。
4.2 大模型生成的代码语法对但几何错
这种情况最隐蔽,代码能跑,模型也生成了,但尺寸完全不是你要的。比如你说“孔中心距边 10mm”,它给你理解成“孔半径 10mm”。根源在于自然语言本身有歧义,而大模型倾向于“猜一个合理值”。
我的应对策略是在提示词里强制要求输出参数表。让大模型在生成代码之前,先把它理解的参数列出来,格式如下:
参数确认: - 板长:100mm - 板宽:50mm - 板厚:8mm - 孔径:5mm - 孔中心距边:10mm这样你一眼就能看出它有没有理解错。如果错了,改提示词重新生成,比改代码快得多。这个习惯我坚持了很久,能省掉大量返工。
4.3 STL 精度不够导致 3D 打印变形
STL 是三角面片,圆孔会被离散成多边形。如果面片密度不够,打印出来的孔就是“多边形孔”,装配时螺栓塞不进去。CadQuery 导出 STL 时可以控制精度:
cq.exporters.export( result, "output.stl", tolerance=0.01, # 线性偏差,越小越精细 angularTolerance=0.1 # 角度偏差,弧度制 )tolerance=0.01意味着曲面偏离理想形状不超过 0.01mm,对于大多数 3D 打印场景够用了。但要注意,精度调太高文件会急剧变大,一个法兰盘可能从几百 KB 涨到几十 MB。我的经验值是:普通零件用 0.05,精密配合件用 0.01,展示用 0.1 就够。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查动作 | 解决方案 |
|---|---|---|---|
| STEP 导入后为空 | 实体不封闭 | 检查 isValid() | 拆分特征,修复布尔运算 |
| 尺寸与描述不符 | 语义歧义 | 输出参数表确认 | 改提示词,明确单位与基准 |
| STL 圆孔变形 | 面片精度低 | 查看 tolerance 设置 | 调小 tolerance 至 0.01 |
| 代码执行报错 | API 用法错误 | 看 traceback 定位行 | 用模板法替代纯生成 |
| 生成速度慢 | 模型复杂度过高 | 统计特征数量 | 分步生成后布尔合并 |
| GLB 材质丢失 | 未指定颜色 | 检查导出参数 | 用color参数显式指定 |
5. 能力边界与扩展方向:text-to-cad 现在能做什么、不能做什么
5.1 当前能稳定覆盖的零件类型
经过我这段时间的实测,以下几类零件用 text-to-cad 生成的成功率和质量都比较理想:板类零件(带孔、槽、倒角、圆角)、轴类零件(阶梯轴、带键槽、带螺纹)、法兰与盘类(均布孔、沉头孔、中心孔)、简单壳体(矩形壳、圆形壳、带加强筋)、型材截面拉伸件。这些零件的共同特点是特征规则、参数有限、几何逻辑清晰,正好是大模型擅长处理的。
反过来说,自由曲面、有机造型、复杂装配体、带运动约束的机构,目前还很难靠一句话生成。你如果要做的是一个仿生外形或者汽车覆盖件,text-to-cad 现阶段帮不上大忙,还是得靠传统建模或逆向工程。
5.2 从单零件到装配体的扩展思路
单零件跑通之后,自然会想能不能生成装配体。我的做法是分零件生成 + 位置约束描述。比如“一个由底板、立柱和顶板组成的支架,立柱在底板四角,顶板盖在立柱上”,可以拆成三次生成,每次输出一个 STEP,再用代码按坐标装配。
base = make_base_plate() column = make_column() top = make_top_plate() assembly = ( cq.Assembly() .add(base, name="base", loc=cq.Location(cq.Vector(0, 0, 0))) .add(column, name="col1", loc=cq.Location(cq.Vector(20, 20, 10))) .add(top, name="top", loc=cq.Location(cq.Vector(0, 0, 60))) ) assembly.save("assembly.step")这条路目前还需要人工介入坐标计算,但已经能把装配体的建模时间压缩不少。未来如果大模型能直接理解“四角”“居中”“贴合”这类空间关系词,自动化程度会更高。
5.3 和现有 CAD 工作流的衔接
text-to-cad 生成的东西,最终还是要回到工程师熟悉的工具里。我的衔接方式是:STEP 作为中间格式,导入中望 CAD 或 SolidWorks 后继续加工程特征。比如生成的初版法兰盘,导入后可以再加倒角、加中心孔、改材料属性,然后出工程图。这样 text-to-cad 负责“从 0 到 1”,传统 CAD 负责“从 1 到 100”,各司其职。
有一点要提醒:不同 CAD 软件对 STEP 的解析有差异。我遇到过 CadQuery 导出的 STEP 在某个软件里圆角丢失的情况,换一个 STEP 版本(比如从 AP214 换成 AP242)就正常了。所以导出时最好留一个版本切换的选项,遇到兼容问题可以快速试。
6. 一些实操心得与后续可以玩的方向
我个人在实际操作中的体会是,text-to-cad 这件事,七分靠工程约束,三分靠模型能力。很多人一上来就追求“全自动”,结果被各种边界情况搞得焦头烂额。更务实的做法是先把高频零件做成模板,让大模型只做参数抽取,把稳定性拉到 95% 以上,再逐步放开自由度。这个思路和做任何自动化系统都一样:先收敛场景,再扩展能力。
另外一个小技巧是建立自己的零件描述词典。比如“沉头孔”对应cboreHole,“通孔”对应hole,“圆角”对应fillet,“倒角”对应chamfer。把这些术语和 CadQuery API 的映射固定下来,写进提示词里,大模型生成的代码准确率会明显提升。我维护了一份大概 40 个词条的映射表,日常够用了。
后续可以扩展的方向,我觉得有两个比较有意思。一个是结合尺寸标注图,让用户上传一张带尺寸的草图,大模型识别尺寸后生成模型,这比纯文字描述信息量大得多。另一个是批量变体生成,给定一个基础模型和一组参数表,自动生成几十个变体并导出,这对做系列化产品的团队非常实用。这两个方向我都在试,等跑顺了再单独整理出来分享。