☰
text-to-cad 实战:从自然语言到精确 CAD 模型的工程化管线
2026/10/8 8:20:48 网站建设 项目流程

1. 从一句话到三维模型:text-to-cad 到底在解决什么问题

第一次听到 text-to-cad 这个词,我脑子里蹦出来的画面是:对着电脑敲一行字,屏幕上直接长出一个能用的三维零件。这个方向这两年确实火,但真正动手做过的人都知道,它远没有宣传里那么"一键生成"。我前后折腾了大半年,从最早的纯文本生成网格,到后来接 STEP、GLB、STL 各种格式的导出链路,踩的坑比想象中多得多。

先把概念说清楚。text-to-cad 指的是用自然语言描述一个零件或结构,由程序自动生成对应的 CAD 模型文件。这里的 CAD 不是指某个具体软件,而是指参数化、可编辑、带精确尺寸的几何模型,最终落地成 STEP、GLB、STL 这类通用格式。它要解决的问题很实际:传统建模需要人手动拉伸、打孔、倒角,一个简单支架可能就要画半小时;而 text-to-cad 想做到的是,你说"一个 80x60x5 的底板,四角各一个 M4 通孔,中心一个直径 30 的凸台高 10 毫米",程序直接把模型吐出来。

适合看这篇内容的人,我大致分三类。第一类是做机械设计或产品结构的工程师,想把手头重复性的建模工作自动化;第二类是做 AI 应用开发的程序员,想在自己的产品里集成模型生成能力;第三类是创客和 3D 打印玩家,手里有打印机,想快速把脑子里的想法变成 STL 去切片。这三类人的诉求不一样,但底层要打通的链路是同一套:文本解析、几何构造、格式导出、精度校验。

我自己的项目背景是这样的:一开始只是想做个批量生成标准件的小工具,比如法兰、支架、垫片这些结构固定的东西。后来发现光生成网格(mesh)不够用,因为网格没法精确改尺寸,加工厂也不认。于是转向参数化建模,再往后才接触到用大模型做文本到代码的转换。整个过程走下来,我对 text-to-cad 的理解从"魔法"变成了"一套需要精心设计的工程管线"。下面我把这套管线拆开讲,包括选型逻辑、核心实现、实操步骤和那些文档里不会写的坑。

2. 整体方案设计:为什么不能只靠一个大模型

2.1 三种主流技术路线的取舍

做 text-to-cad,绕不开的第一个决策就是走哪条技术路线。我实测下来,市面上能落地的方案基本归为三类,各有各的适用边界。

第一类是文本直接生成网格,代表思路是用扩散模型或点云生成网络,输入文本描述,输出三角网格。这条路生成速度快,形状自由度高,适合做概念草图、艺术造型。但问题也很致命:生成的网格拓扑混乱,尺寸不可控,你让它生成"直径 30 的孔",它可能给你个 28.7 的近似圆。对于需要装配的零件,这基本没法用。

第二类是文本转代码再执行,也就是让大模型输出建模脚本(比如 CadQuery、OpenSCAD 的代码),再由脚本引擎执行生成精确几何。这条路是我最终选定的方向,因为它的尺寸精度完全可控,生成的模型天然带参数,改一个数字就能重新生成。代价是对模型的代码能力要求高,描述稍微复杂一点就容易生成语法错误或逻辑错误的代码。

第三类是文本转参数表,预先定义好一批参数化模板,大模型只负责从文本里抽取尺寸和特征,填进模板。这条路最稳,但灵活性最差,只能覆盖预设好的结构类型。

我把三类的核心差异整理成一张表,方便你对照自己的需求选:

路线精度灵活性开发成本适合场景
文本生成网格低高中概念设计、艺术造型
文本转代码执行高中高高工程零件、可编辑模型
文本转参数表高低低标准件批量生成

提示:如果你的目标是做能直接送去加工或 3D 打印的零件,别在网格生成上浪费时间,直接上文本转代码这条路。我早期在网格方案上耗了两个月,最后发现精度问题根本绕不过去。

2.2 为什么选 CadQuery 而不是 OpenSCAD

确定走代码路线后,下一个问题是选哪个建模引擎。主流的有两个:OpenSCAD 和 CadQuery。我两个都深度用过,最后选了 CadQuery,理由值得说清楚。

OpenSCAD 的优势是语法简单,像写伪代码,大模型生成起来错误率低。但它的底层是 CSG(构造实体几何),所有操作都是布尔运算的堆叠,做复杂曲面和倒角非常吃力,而且导出的 STEP 质量一般。更麻烦的是,OpenSCAD 的坐标系和特征定位全靠手动算,写一个带多个孔的板子,代码里全是 translate 和 rotate 的嵌套,可读性差。

CadQuery 基于 OCCT(Open CASCADE Technology)内核,这是工业级的几何内核,导出的 STEP 精度高,支持真正的 B-rep(边界表示)建模。它的 API 更接近工程思维,比如选面、选边、在面上打孔这些操作都很自然。缺点是学习曲线陡,大模型生成 CadQuery 代码的出错率比 OpenSCAD 高一些。

我的做法是用大模型生成 CadQuery 代码,但加一层校验和重试机制。具体来说,生成的代码先在沙箱里执行,捕获异常,把错误信息回传给模型让它自我修正,最多重试三次。这套机制把成功率从最初的六成左右提到了九成以上。这个思路后面在实操部分会详细展开。

2.3 格式导出的链路设计

模型生成出来,最终要落地成文件。text-to-cad 涉及的主要格式有三个:STEP、GLB、STL,它们各自解决不同的问题,不能混用。

STEP 是精确的 B-rep 格式,保留了完整的几何定义和拓扑关系,是 CAD 软件之间交换的标准。你要把模型导进 SolidWorks、中望 CAD 或者 FreeCAD 继续编辑,必须用 STEP。它的缺点是文件大,且不含材质和颜色信息。

GLB 是glTF 的二进制版本,主打轻量和 Web 友好,带材质、颜色、光照信息。你要在网页里做 3D 预览,或者导入 Blender 做渲染,GLB 是最佳选择。它本质上是网格格式,精度不如 STEP。

STL 是3D 打印的事实标准,只描述三角面片,没有单位、没有颜色、没有拓扑。切片软件认它,但它是最"笨"的格式,一旦导出就基本没法再精确编辑。

我的导出链路是这样设计的:以 CadQuery 的模型对象为唯一数据源,同时导出三种格式。STEP 直接由 CadQuery 导出,GLB 通过中间转换成网格再打包,STL 也是从网格导出。这样保证三种格式的几何是一致的,不会出现 STEP 和 STL 对不上的情况。这里有个细节:从 B-rep 转网格时,弦高容差(tolerance)这个参数直接决定网格精度和文件大小,设太小文件爆炸,设太大圆孔变多边形,后面会讲怎么调。

3. 核心实现细节:文本怎么变成精确几何

3.1 文本解析与特征抽取的关键设计

text-to-cad 的第一步是把人话翻译成结构化的建模意图。这一步做不好,后面全白搭。我的做法是分两层:先做意图分类,再做参数抽取。

意图分类是判断用户想要什么类型的操作。是生成一个新零件,还是修改已有模型,还是查询某个尺寸?这个用大模型做 few-shot 分类就能搞定,准确率很高。参数抽取才是难点,因为工程描述里的尺寸、位置、特征关系非常密集。

举个例子,用户说"一块 100 长 50 宽 8 厚的板,左边两个 M5 沉头孔,孔心距边 15,间距 30"。这句话里包含了:基体尺寸(100x50x8)、特征类型(沉头孔)、规格(M5)、数量(2)、定位约束(距边 15、间距 30)、方位(左边)。如果直接让大模型生成代码,它很可能把"距边 15"理解成距某一条边,而实际工程里这个"边"是有歧义的。

我的解决方案是在提示词里强制模型输出结构化的 JSON 中间表示,而不是直接输出代码。JSON 里明确定义每个特征的坐标系、参考基准、尺寸值。然后再用一个确定性的代码生成器把 JSON 转成 CadQuery 代码。这样做的好处是,JSON 层可以做校验,比如检查孔是否超出板边界、尺寸是否矛盾,把错误拦在生成代码之前。

# 中间表示的结构示例 { "base": {"type": "box", "length": 100, "width": 50, "thickness": 8}, "features": [ { "type": "counterbore_hole", "spec": "M5", "count": 2, "positions": [ {"x": 15, "y": 15}, {"x": 15, "y": 45} ], "reference": "bottom_left_corner" } ] }

这个中间层是我整个项目里最有价值的设计。它把"理解"和"生成"解耦了,理解错了可以单独调提示词,生成错了可以单独调代码模板,排查问题的时候不会一团乱麻。

3.2 参数化建模的坐标系与基准选择

做精确建模,坐标系是命根子。我见过太多项目因为坐标系定义混乱,导致生成的模型位置飘忽不定。CadQuery 默认用全局坐标系,原点在 (0,0,0),Z 轴向上。但工程描述里的"左边""顶部""中心"这些词,必须映射到明确的基准上。

我的做法是强制约定一套基准规则:所有零件默认以底面中心为原点,Z 轴向上,X 轴指向零件长度方向,Y 轴指向宽度方向。用户描述里的"左边"默认指 X 负方向,"顶部"指 Z 正方向。这套规则写进提示词,让模型在抽取参数时就按这个基准换算。

为什么选底面中心而不是角点?因为中心基准在做对称特征时最省事。比如"四角各一个孔",用中心基准就是 (±L/2∓offset, ±W/2∓offset),对称性一目了然。用角点基准的话,每个孔都要单独算,容易出错。

注意:如果你的用户群体习惯用角点基准(很多机械图纸是这么标的),那就在中间表示里加一个 reference 字段,明确标注基准类型,代码生成器根据这个字段做换算。别指望用户改习惯,让程序去适配人。

3.3 从 B-rep 到网格的容差控制

前面提到 STEP 转 GLB 和 STL 需要网格化,这里的容差参数是精度和体积的平衡点。CadQuery 底层用 OCCT 的网格化算法,核心参数有两个:线性偏差(linear deflection)和角度偏差(angular deflection)。

线性偏差控制的是曲面离散成三角面片时,面片和真实曲面的最大距离。设 0.1 毫米,意味着曲面上的点最多偏离真实曲面 0.1 毫米。角度偏差控制相邻面片法向的最大夹角,影响曲率变化剧烈区域的细分程度。

我的经验值是:做 3D 打印预览,线性偏差设 0.05 到 0.1 毫米足够;做网页展示,可以放宽到 0.2 毫米,文件能小一半;做精密装配检查,得压到 0.01 毫米,但文件会大得离谱。角度偏差一般设 0.1 到 0.5 弧度,圆孔多的话调小一点,否则孔会变成明显的多边形。

这里有个坑:容差设太小会导致网格化时间爆炸。我试过一个带 200 个孔的板子,线性偏差设 0.001 毫米,网格化跑了将近两分钟。后来改成 0.05,时间降到三秒,肉眼几乎看不出差别。所以别盲目追求高精度,按实际用途定。

4. 完整实操流程:从零搭一套可用的生成管线

4.1 环境准备与依赖安装

先把环境搭起来。我用的技术栈是 Python + CadQuery + 一个大模型 API。CadQuery 的安装是第一个坎,因为它依赖 OCCT,在不同系统上的安装方式不一样。

# 推荐用 conda 装,pip 装 CadQuery 经常出 OCCT 链接错误 conda create -n text2cad python=3.10 conda activate text2cad conda install -c conda-forge cadquery # 网格处理和格式转换 pip install trimesh numpy

为什么强调用 conda?因为 CadQuery 的 OCCT 依赖在 pip 下经常出现动态库找不到的问题,尤其是 Windows 上。我一开始用 pip 装,报了一堆 DLL 错误,换成 conda 一次过。如果你非要用 pip,记得先装好系统级的 OCCT 库。

大模型这块,我用的是支持函数调用和代码生成的通用模型,通过 API 调用。这里不绑定具体厂商,因为不同模型的提示词要微调,但整体流程是一样的。关键是要选支持长上下文和结构化输出的模型,因为提示词里要塞建模规则、示例、格式约束,短上下文模型扛不住。

4.2 提示词工程:让模型稳定输出可用代码

提示词是 text-to-cad 的灵魂。我前后改了十几版,总结出几个关键原则。

第一,给足示例。在系统提示词里放三到五个完整的"文本描述到 JSON 中间表示"的示例,覆盖板类、轴类、壳体类零件。示例要包含边界情况,比如带倒角、带阵列孔的描述。模型看到示例后,输出格式的稳定性会大幅提升。

第二,明确禁止项。告诉模型不要输出解释性文字,不要用未定义的变量,不要假设单位(统一用毫米)。这些约束看起来琐碎,但能省掉大量后处理。

第三,分步引导。让模型先输出中间表示,确认无误后再生成代码。我在实际管线里是分两次调用的:第一次调用只生成 JSON,程序校验 JSON 的合法性;第二次调用把 JSON 和代码模板一起给模型,让它填充生成 CadQuery 代码。两次调用比一次调用慢,但成功率高一截。

# 提示词的核心结构(简化版) SYSTEM_PROMPT = """ 你是一个 CAD 建模助手。用户会用自然语言描述一个零件。 你需要输出 JSON 格式的中间表示,包含基体和特征列表。 所有尺寸单位为毫米。坐标系约定:底面中心为原点,Z 轴向上。 不要输出任何解释文字,只输出 JSON。 示例: 输入:一个直径 50 高 20 的圆柱,中心一个直径 10 的通孔 输出:{"base": {"type": "cylinder", "diameter": 50, "height": 20}, "features": [{"type": "through_hole", "diameter": 10, "position": {"x": 0, "y": 0}}]} """

4.3 代码生成与沙箱执行

拿到 JSON 后,代码生成器把它转成 CadQuery 脚本。我一开始让大模型直接生成代码,但发现它经常在 API 细节上出错,比如把Workplane的方法名记混。后来改成模板加填充的方式:我预先写好各类特征的代码模板,模型只负责把 JSON 里的参数填进去。这样代码的正确率接近百分之百。

import cadquery as cq def build_from_spec(spec): # 基体 base = spec["base"] if base["type"] == "box": wp = cq.Workplane("XY").box( base["length"], base["width"], base["thickness"]) elif base["type"] == "cylinder": wp = cq.Workplane("XY").circle( base["diameter"] / 2).extrude(base["height"]) # 特征 for feat in spec["features"]: if feat["type"] == "through_hole": wp = wp.faces(">Z").workplane().pushPoints( [(feat["position"]["x"], feat["position"]["y"])] ).hole(feat["diameter"]) elif feat["type"] == "counterbore_hole": # 沉头孔需要两步:先钻通孔,再铣沉头 wp = wp.faces(">Z").workplane().pushPoints( [(p["x"], p["y"]) for p in feat["positions"]] ).cboreHole(feat["spec"]["shaft"], feat["spec"]["head"], feat["spec"]["depth"]) return wp

执行环节一定要放沙箱。生成的代码在独立进程里跑,设超时(我设 30 秒),捕获所有异常。如果执行失败,把错误信息回传给模型,让它修正 JSON 或代码,最多重试三次。这套重试机制是稳定性的关键,实测能把端到端成功率从六成提到九成以上。

4.4 多格式导出与精度校验

模型建好后,导出三种格式。CadQuery 导出 STEP 很简单,一行代码。导出 STL 和 GLB 需要先转网格。

# 导出 STEP cq.exporters.export(wp, "part.step") # 导出 STL,指定容差 cq.exporters.export(wp, "part.stl", tolerance=0.05, angularTolerance=0.1) # 导出 GLB 需要先转成 trimesh import trimesh mesh = wp.val().tessellate(0.05) tm = trimesh.Trimesh(vertices=mesh[0], faces=mesh[1]) tm.export("part.glb")

导出后必须做精度校验。我的做法是:读取导出的 STL,计算它的包围盒尺寸,和原始模型的包围盒对比,误差超过 0.1 毫米就报警。这一步能抓出网格化参数设错、单位换算错误这类问题。另外,对于带孔的零件,我会检查孔的数量和直径,确保特征没丢。

提示:STL 没有单位信息,导出时一定要在文件名或元数据里标注单位是毫米。我吃过亏,导出的 STL 被切片软件当成英寸,零件直接大了 25 倍。

5. 常见问题与排查技巧实录

5.1 生成失败与代码报错排查

text-to-cad 最常见的失败就是代码执行报错。我把踩过的坑整理成一张速查表,基本覆盖了九成以上的报错场景。

报错现象根本原因解决方法
AttributeError: Workplane has no attribute模型记错了 API 方法名用模板填充代替自由生成
孔位置偏移或超出边界坐标系基准理解错误在提示词里强制基准约定
布尔运算失败特征之间干涉或相切加最小间隙检查,避免零间隙
网格化超时容差设太小或特征太复杂放宽容差,或分区域网格化
STEP 导出后打不开几何有自交或非流形边导出前做几何有效性检查

其中布尔运算失败是最隐蔽的。CadQuery 做差集运算时,如果两个实体刚好相切(比如孔的边缘和板的边缘重合),OCCT 内核可能算不出结果。我的经验是留 0.01 毫米的余量,让孔稍微超出边界一点,反而能稳定算出来。这个技巧文档里不会写,是实打实试出来的。

5.2 精度与文件体积的平衡技巧

前面提过容差控制,这里补充几个实操技巧。第一,不同特征用不同容差。平面区域可以粗一点,曲面和孔用细一点。CadQuery 支持对特定面单独设容差,但 API 比较绕,我一般整体设一个折中值。

第二,GLB 导出时开 Draco 压缩。Draco 是谷歌的网格压缩算法,能把 GLB 体积压到原来的十分之一,视觉几乎无损。trimesh 支持 Draco,但需要额外装依赖。对于网页展示场景,这个压缩是必须的。

第三,STL 导出用二进制格式。ASCII 格式的 STL 体积是二进制的五倍以上,而且精度还低。CadQuery 默认导出二进制,但如果你手动处理,记得确认格式。

5.3 批量生成时的性能优化

如果你要批量生成几百个零件,单线程跑会很慢。我的优化思路是把生成和执行分离。文本解析和代码生成是 IO 密集(调 API),可以并发;代码执行是 CPU 密集,用多进程池。两者用队列解耦,整体吞吐能提升三到五倍。

另外,CadQuery 的模型对象不要跨进程传递,它底层是 C++ 对象,序列化会出问题。正确做法是在每个工作进程里独立构建模型,只把最终的文件路径传回来。

from multiprocessing import Pool def generate_one(spec): wp = build_from_spec(spec) path = f"output/{spec['id']}.step" cq.exporters.export(wp, path) return path with Pool(processes=4) as pool: results = pool.map(generate_one, all_specs)

注意:多进程下每个进程都会加载一份 OCCT 库,内存占用会翻倍。如果内存紧张,把进程数控制在 CPU 核心数的一半左右。

6. 格式转换与下游对接的实战经验

6.1 STEP 转 STL 的那些坑

很多人以为 STEP 转 STL 就是点一下导出,实际上这里面的坑不少。最常见的问题是单位不一致。STEP 文件内部有单位定义,但有些软件导出时不写单位,或者默认用英寸。转 STL 时如果不做单位换算,零件尺寸会差 25.4 倍。

我的做法是在转换前先读 STEP 的包围盒,和预期尺寸对比。如果差得离谱,就是单位问题。CadQuery 读 STEP 时可以指定单位,但更稳妥的是读进来后统一缩放到毫米。

另一个坑是曲面精度丢失。STEP 里的圆柱面是精确的解析曲面,转 STL 时离散成三角面片,如果容差设太大,圆柱会变成明显的棱柱。对于要 3D 打印的零件,这个影响很大,因为打印出来的圆孔会不圆。我的经验是圆柱特征多的零件,线性偏差压到 0.02 毫米以下。

6.2 GLB 在网页预览中的优化

GLB 主要用于网页 3D 预览。我做过一个在线预览功能,用户生成模型后直接在浏览器里转着看。这里有几个优化点。

第一,减面。CadQuery 生成的网格面数可能上万,网页加载慢。用 trimesh 的simplify_quadric_decimation做减面,减到原来的三成,视觉几乎无差别。

第二,合并材质。GLB 里每个材质是一个 draw call,材质多了渲染卡。把相同颜色的部件合并成一个材质,能显著提升帧率。

第三,加环境光。纯几何的 GLB 在网页里看起来灰扑扑的,加一个 HDR 环境贴图,金属质感立刻就出来了。这个不是必须的,但用户体验差别很大。

6.3 与下游 CAD 软件的兼容性

生成的 STEP 最终要导进各种 CAD 软件。我测过 SolidWorks、中望 CAD、FreeCAD 和 Fusion 360,兼容性整体不错,但有几个细节要注意。

倒角和圆角的表示方式在不同内核间可能有差异。OCCT 生成的倒角,在 SolidWorks 里有时会被识别成样条曲面而不是标准倒角,导致后续编辑困难。如果下游要做大量编辑,建议在生成时尽量用标准特征,少用复杂的变半径倒角。

装配体的处理也是个问题。text-to-cad 目前主要生成单个零件,如果要做装配,需要在中间表示里加装配约束。这块我还在摸索,目前的方案是生成多个零件后,用坐标变换把它们摆到正确位置,再导出成一个 STEP。但这样导出的是"死"装配,没有配合关系,下游改尺寸会散架。

7. 我踩过的那些坑和最后的几句实话

做 text-to-cad 这大半年,最大的体会是:这东西的难点不在 AI,在几何。大模型负责把话听懂,但真正决定成败的是几何内核的稳定性、坐标系的一致性、容差的合理性。我见过太多人把精力全花在调提示词上,结果生成的模型尺寸对不上,白忙一场。

另一个体会是别追求一步到位。我一开始想做一个"什么都能生成"的通用工具,结果什么都不精。后来收缩到只做板类和轴类零件,把这两类的成功率做到九成五以上,反而有了实际价值。text-to-cad 现在的阶段,窄场景做深比宽场景做浅有用得多。

最后分享一个实用技巧:给生成的模型加一个"尺寸标注图"。用 CadQuery 的导出功能,把模型的工程图(带尺寸标注的 2D 视图)也导出来。这样用户拿到模型的同时能看到关键尺寸,方便核对。这个功能实现起来不难,但对用户的信任感提升很大,因为工程上最怕的就是"模型看着对,尺寸是错的"。

如果你也在做类似的东西,我的建议是先把手动建模的流程跑通,再考虑用 AI 替代哪一步。很多时候,一个参数化的模板库加一个简单的表单界面,比硬上大模型更靠谱。AI 是加速器,不是发动机,底层的几何能力才是根本。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询