text-to-cad 技术全解析:从自然语言到三维模型的实现路径
1. 从一句话到三维模型:text-to-cad 到底在解决什么问题
第一次听到 text-to-cad 这个词,我的反应是:这不就是把“用嘴画图”这件事往前推了一大步吗。传统 CAD 建模的流程大家都熟——打开软件、选基准面、画草图、加约束、拉伸、倒角、装配,一套下来没个把小时根本出不来一个像样的零件。而 text-to-cad 想做的事情非常直接:你用自然语言描述一个零件,比如“一个 80×60×10 毫米的底板,四角各有一个直径 6 毫米的沉头孔,中心开一个 30 毫米的圆孔”,系统直接给你吐出可编辑的三维模型文件。
这件事的价值不在于“炫技”,而在于它切中了几个真实痛点。第一是建模门槛,大量非机械专业的人(做创客的、做产品原型的、搞教学演示的)需要简单零件,但学 SolidWorks 或 Fusion 360 的时间成本太高。第二是重复劳动,工程师每天要建大量结构相似的零件,参数改一改就是新版本,这种活儿交给语言模型驱动的生成流程效率能翻好几倍。第三是设计意图的早期表达,在概念阶段,用文字描述比直接建模快得多,text-to-cad 让“想法到可视模型”的链路缩短到几秒钟。
这篇文章适合三类人看:一是想自己搭一套 text-to-cad 流程的开发者,二是有批量建模需求但不想写复杂脚本的工程师,三是纯粹好奇“大模型怎么理解三维几何”的技术爱好者。我会把整个技术链路拆开讲——从语言解析、参数提取、几何构造到文件导出,每一步为什么这么设计、坑在哪里、怎么调参,都会给到可直接复现的方案。核心关键词就三个:自然语言解析、参数化建模、CAD 文件生成,全文围绕它们展开。
需要先说明一点:text-to-cad 不是一个单一软件,而是一类技术方案的统称。目前主流实现路径有三条——基于脚本模板的参数填充、基于大模型直接生成 CAD 脚本代码、基于几何内核的 API 调用。这三条路各有适用场景,后面会逐一拆解。
2. 三条技术路线怎么选:方案选型背后的真实考量
2.1 路线一:模板 + 参数填充,最稳但最不灵活
这条路的逻辑特别朴素:预先写好一批参数化模板(比如“带孔底板”“L 型支架”“法兰盘”),语言模型只负责从用户描述里抽取尺寸参数,然后填进模板生成模型。我早期做的一个版本就是这么干的,用 Python 的 CadQuery 写模板,用正则加规则做参数抽取。
它的优势非常明显:输出 100% 可控,不会出现几何错误,生成速度极快(毫秒级),而且模板可以覆盖 80% 的常见零件。但缺点同样致命——用户只要描述一个模板里没有的形状,系统就歇菜了。它本质上是个“自然语言接口的参数化库”,不是真正的生成。
适合场景:企业内部有固定零件库、需要批量出图的产线场景。不适合:开放式创意建模。
2.2 路线二:大模型直接生成 CAD 脚本代码
这是目前最热的方向。核心思路是让大语言模型直接输出 CadQuery、OpenSCAD 或 build123d 的代码,然后执行代码得到模型。比如用户说“做一个壁厚 3 毫米的方形盒子,顶部开口”,模型直接生成类似下面的代码:
import cadquery as cq result = ( cq.Workplane("XY") .box(60, 40, 30) .faces(">Z").shell(-3) .edges("|Z").fillet(2) )这条路的天花板最高,因为代码的表达能力几乎无限。但它的坑也最多,我在实测中踩过的几个典型问题:
- API 幻觉:模型会编造不存在的 CadQuery 方法,比如
.makeHole()这种根本不存在的函数,执行直接报错。 - 坐标系混乱:生成的代码经常在错误的工作平面上操作,导致模型方向完全不对。
- 约束缺失:代码能跑通,但几何是“飘”的,改一个参数整个模型崩掉。
解决这些问题的关键不在于换更强的模型,而在于给模型喂足够的 API 上下文。我的做法是把 CadQuery 的常用 API 整理成一份精简文档(大概 2000 token),作为 system prompt 的一部分固定注入,同时在 prompt 里强制要求“只使用文档中列出的方法”。这一招把 API 幻觉率从 30% 降到了 5% 以下。
2.3 路线三:几何内核 API 直接调用
这条路最硬核,不走代码生成,而是让模型输出结构化的 JSON 指令,再由后端程序调用 OpenCASCADE 或 Parasolid 这类几何内核的 API 直接构造几何。比如模型输出:
{ "operation": "extrude", "sketch": {"type": "rectangle", "width": 80, "height": 60}, "distance": 10, "holes": [ {"type": "counterbore", "x": 10, "y": 10, "diameter": 6, "cb_diameter": 11} ] }后端拿到这个 JSON,逐条翻译成内核调用。这种方式的可控性介于前两者之间——比纯代码生成稳,比模板灵活。代价是你要自己定义一套完整的指令 schema,工作量不小。适合有几何内核开发经验的团队。
2.4 三条路线的对比与选型建议
| 维度 | 模板填充 | 代码生成 | 内核 API |
|---|---|---|---|
| 灵活度 | 低 | 高 | 中高 |
| 稳定性 | 极高 | 中 | 高 |
| 开发成本 | 低 | 中 | 高 |
| 可编辑性 | 中 | 高 | 中 |
| 适合团队 | 产线/小团队 | 独立开发者 | 有内核经验团队 |
我的建议是:先用模板填充跑通最小闭环,再逐步引入代码生成处理长尾需求。不要一上来就追求全自动生成,那样大概率会在调试几何错误上耗掉所有时间。实际生产中,模板覆盖 70% 高频需求、代码生成兜底 30% 长尾,是性价比最高的组合。
3. 核心链路拆解:从一句话到模型文件的完整实现
3.1 第一步:自然语言解析与参数抽取
这一步的目标是把“一个 80×60×10 的底板,四角沉头孔,中心圆孔”这种描述,转成结构化的参数字典。看起来简单,实际坑很多。
首先是单位问题。用户说“80”,是毫米还是厘米?我的处理方式是:在 prompt 里强制要求模型输出时统一转成毫米,并在解析层做二次校验——如果某个尺寸小于 1 或大于 10000,就触发人工确认。实测下来,90% 的用户默认用毫米,但偶尔会遇到用英寸的,这个校验能拦住大部分错误。
其次是隐含参数。用户说“四角沉头孔”,但没说孔径和沉头直径。这时候需要一套默认值规则:M6 沉头孔对应通孔直径 6.6 毫米、沉头直径 11 毫米、沉头深度 3.5 毫米。这些默认值我整理成了一张对照表,模型抽取到“M6 沉头孔”时直接查表填充。这套默认值规则是 text-to-cad 能不能“好用”的关键,因为大部分用户不会把所有参数说全。
第三是空间关系解析。“四角”意味着孔的位置在四个角落,但具体偏移多少?我的默认规则是距边缘 1.5 倍孔径。用户如果说“孔靠近边缘”,偏移就改成 1 倍孔径。这种模糊描述的映射规则,需要根据实际使用反馈不断调整。
参数抽取的 prompt 我一般这么写:
你是一个 CAD 参数抽取器。从用户描述中提取以下字段: - shape_type: 基础形状类型 - dimensions: 长宽高/直径等尺寸(单位统一为毫米) - features: 特征列表(孔、倒角、圆角等) - positions: 特征位置描述 如果某个参数未明确给出,标记为 null,不要猜测。关键在最后一句“不要猜测”——早期我没加这句,模型会自作主张填一堆默认值,导致后面根本分不清哪些是用户说的、哪些是模型编的。
3.2 第二步:几何构造与布尔运算
拿到结构化参数后,就进入真正的建模环节。以 CadQuery 为例,一个带孔底板的构造逻辑是这样的:
import cadquery as cq # 基础底板 base = cq.Workplane("XY").box(80, 60, 10) # 四角沉头孔 hole_positions = [(10, 10), (70, 10), (10, 50), (70, 50)] for x, y in hole_positions: base = ( base.faces(">Z").workplane() .center(x - 40, y - 30) .cboreHole(6.6, 11, 3.5) ) # 中心圆孔 base = base.faces(">Z").workplane().hole(30) cq.exporters.export(base, "base_plate.step")这段代码有几个细节值得说。第一,center(x - 40, y - 30)里的偏移量是因为 CadQuery 的 workplane 原点在中心,而用户描述的坐标通常以左下角为原点,这个转换必须做对,否则孔会全部偏位。第二,cboreHole的参数顺序是(通孔直径,沉头直径,沉头深度),顺序搞反了模型直接废掉。第三,布尔运算的顺序会影响最终几何,先打孔再倒角,和先倒角再打孔,结果可能完全不同——一般原则是先做主体形状,再做减材特征,最后做倒角和圆角。
3.3 第三步:文件导出与格式选择
模型建好后要导出成通用格式。主流选择有三个:
- STEP:最通用的三维交换格式,几乎所有 CAD 软件都能打开,保留精确几何。缺点是文件较大,且不保留特征树。
- STL:三角网格格式,适合 3D 打印,但不适合后续编辑。
- DXF:二维图纸格式,适合钣金和激光切割。
我的默认策略是同时导出 STEP 和 STL——STEP 给需要继续编辑的人,STL 给直接打印的人。导出时有个坑:CadQuery 默认的 STL 精度比较低,曲面会显得很“棱角”,需要手动调公差:
cq.exporters.export(base, "base_plate.stl", tolerance=0.01, angularTolerance=0.1)tolerance控制线性偏差,angularTolerance控制角度偏差,这两个值越小模型越精细,但文件也越大。0.01 毫米和 0.1 弧度是我实测下来精度和体积比较平衡的一组值。
3.4 完整链路的串联与错误处理
把三步串起来,整个流程是:用户输入 → 参数抽取 → 参数校验 → 代码生成 → 代码执行 → 几何校验 → 文件导出。其中几何校验这一步最容易被忽略,但最重要。我的做法是在导出前检查三个指标:模型体积是否大于 0、是否有孤立实体、包围盒尺寸是否与用户描述一致。任何一项不通过就回退到代码生成步骤重试,最多重试 3 次。
这套重试机制把整体成功率从 65% 拉到了 92% 左右。剩下 8% 的失败案例,基本都是用户描述本身有歧义或矛盾,这时候系统会返回一个澄清问题,让用户补充信息。
4. 实操中踩过的坑与排查技巧实录
4.1 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 模型为空 | 布尔运算全部相减 | 检查减材特征是否大于主体 | 调整特征尺寸或运算顺序 |
| 孔位偏移 | 坐标系原点不一致 | 打印 workplane 原点坐标 | 统一用中心原点或左下角原点 |
| 代码执行报错 | API 方法不存在 | 检查方法名是否在文档中 | 注入 API 文档,限制方法范围 |
| 模型尺寸不对 | 单位混淆 | 检查输入是否含单位 | 强制统一为毫米并校验范围 |
| 曲面有棱角 | STL 精度不足 | 查看导出公差参数 | 调小 tolerance 值 |
| 倒角失败 | 倒角半径大于壁厚 | 检查倒角值与相邻尺寸关系 | 限制倒角半径不超过最小壁厚的 1/3 |
4.2 三个我踩得最深的坑
第一个坑:过度信任模型的尺寸推理。早期我让模型自己算“四角孔距边缘 1.5 倍孔径”,结果模型有时候算对有时候算错,而且错的时候毫无规律。后来我把这个计算逻辑从模型里拿出来,改成后端代码硬编码,模型只负责识别“四角孔”这个特征,具体偏移量由程序算。凡是能用确定性代码算的,绝不让模型算,这是我最大的经验教训。
第二个坑:忽略了几何有效性检查。有一次生成的模型在 CadQuery 里能导出,但拿到别的软件里打开直接报错,查了半天发现是布尔运算产生了一个零厚度的面。这种几何在数学上“有效”但在工程上不可用。后来我加了一道检查:用base.val().isValid()做几何有效性验证,不通过就重试。
第三个坑:prompt 里的示例太少。一开始我的 prompt 只写了规则没给例子,模型输出格式五花八门。后来我在 prompt 里塞了 3 个完整的输入输出示例,格式一致性立刻上来了。few-shot 示例对结构化输出任务的效果,比写一堆规则描述强得多。
4.3 提升成功率的几个实操技巧
技巧一:参数抽取和代码生成分两次调用。不要指望一个 prompt 同时完成“理解需求”和“生成代码”两件事,分开做,每步的准确率都会高很多。参数抽取用低温(0.1),代码生成用稍高温(0.3),实测效果最好。
技巧二:给代码生成加“自检”环节。让模型生成代码后,再调用一次模型检查代码是否有明显错误(比如引用了未定义的变量),这个自检步骤能拦掉大概 15% 的低级错误。
技巧三:建立失败案例库。每次生成失败,把输入和错误信息存下来,定期分析。我积累了大概 200 条失败案例后,发现 60% 的失败集中在 5 类问题上,针对性地加规则就解决了。
5. 这套方案能扩展到哪里:应用场景与边界
5.1 已经跑通的场景
目前我实测下来比较稳的场景有三个。一是教学演示,老师用文字描述一个零件,几秒钟出模型,学生能直观看到“文字描述”和“几何形状”的对应关系。二是创客快速原型,做个小盒子、小支架,描述完直接导出 STL 去打印,省掉了学 CAD 的时间。三是参数化零件批量生成,比如一系列不同尺寸的法兰盘,用脚本批量跑,几分钟出几十个模型。
5.2 目前还搞不定的场景
要说清楚边界:复杂装配体、自由曲面、需要精确工程约束的零件,目前 text-to-cad 还做不好。装配体涉及零件间的配合关系,语言描述很难说清楚;自由曲面(比如汽车外形)需要样条曲线控制点,语言根本表达不了;工程约束(比如“这个面必须垂直于那个面”)在代码生成里很容易丢失。这些场景还是得靠传统 CAD 或者更专业的参数化工具。
5.3 后续可以怎么扩展
一个有意思的扩展方向是反向能力——给一个现有模型,让系统用自然语言描述它。这个能力对设计文档自动化很有价值。另一个方向是多轮对话式建模,用户说“把那个孔往左移 5 毫米”,系统在已有模型上做增量修改,而不是每次从头生成。这个方向技术上可行,关键是要维护一个“当前模型状态”的上下文,让模型知道现在改的是哪个特征。
我个人在实际操作中的体会是,text-to-cad 目前最合理的定位不是“替代 CAD 工程师”,而是“把建模的门槛降到会用文字就能表达需求的程度”。它解决的是“从想法到第一个可视模型”这一段,后面的精修、装配、出图,还是得靠专业工具。把这段链路做顺,已经能帮很多人省下大量时间了。