☰
text-to-cad 实战:从自然语言到 STEP 模型的自动化链路搭建
2026/10/8 21:37:18 网站建设 项目流程

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

第一次听到 “text-to-cad” 这个词,很多人脑子里蹦出来的画面大概是:对着电脑说一句“给我画个法兰盘”,屏幕上就自动出现一个带螺栓孔的 STEP 模型。这个想象方向没错,但真正落地的时候,它解决的问题比“省几下鼠标”要深得多。

text-to-cad 本质上是一条从自然语言描述到 CAD 几何文件的自动化链路。你输入一段文字,比如“一个 80mm × 60mm × 5mm 的矩形底板,四角各有一个直径 6mm 的通孔,孔中心距边缘 10mm”,系统输出一个可以被 CAD 软件打开的模型文件,常见格式包括STEP、GLB、STL。这三个格式分别对应不同的下游用途:STEP 用于精确的工程制造和后续参数化编辑,GLB 用于可视化展示和 Web 端渲染,STL 用于 3D 打印和网格处理。

这件事的价值在哪里?我举个实际场景。做非标设备的朋友应该都有体会,项目前期经常要出几十个简单的安装板、连接件、支架的方案。这些零件结构不复杂,但一个个在 CAD 里拉伸、打孔、倒角,重复劳动量极大。如果能把“描述”直接变成“模型”,哪怕只是初版,也能把大量时间从画图转移到真正的结构设计上。另一个场景是 3D 打印爱好者,很多人并不熟练 CAD 操作,但脑子里有明确的想法,text-to-cad 就是他们和制造之间的翻译器。

适合看这篇内容的人有三类:一是想了解 AI 辅助设计到底能做到什么程度的工程师;二是想自己搭一套 text-to-cad 流程的开发者;三是做机械、建筑、工业设计相关工作的从业者,想判断这个方向值不值得投入时间。我不会只讲概念,重点会放在这条链路怎么搭、每一步为什么这么选、实际跑起来会遇到什么坑。

需要先说明一点:text-to-cad 目前不是一个开箱即用的成熟软件,它更像是一种技术组合思路。核心环节包括语言理解、几何参数提取、CAD 脚本生成、格式转换四个部分。下面我按实际搭建的顺序,把每个环节拆开讲。

2. 整体方案怎么搭:四种主流路线的取舍分析

2.1 路线一:大模型直接生成 CAD 脚本

这是目前最直观的思路。让大语言模型读取你的文字描述,直接输出一段 CAD 软件的脚本代码,比如 FreeCAD 的 Python 脚本、OpenSCAD 的代码,或者 AutoCAD 的 AutoLISP。脚本执行后生成三维模型,再导出成 STEP 或 STL。

这条路线最大的优势是灵活。只要模型能写出脚本,理论上就能生成。OpenSCAD 尤其适合这种玩法,因为它本身就是“代码即模型”的范式,一个立方体就是cube([80,60,5]),一个圆柱孔就是cylinder(d=6,h=5),大模型对这类结构化代码的生成能力相当不错。

但问题也很明显。大模型生成脚本的几何正确性无法保证。它可能把孔的位置算错,可能把布尔运算的顺序写反,也可能生成语法正确但几何上自相交的模型。我实测下来,简单零件(十个特征以内)的一次成功率大概在六成左右,复杂零件基本都要人工修正。所以这条路线适合快速出草稿,不适合直接用于生产。

2.2 路线二:自然语言转参数表,再驱动模板

这条路线更工程化。先让模型把文字描述解析成一张结构化的参数表,比如 JSON 格式,包含长宽高、孔位坐标、孔径、圆角半径等字段。然后用这张参数表去填充一个预先写好的 CAD 模板脚本。

{ "type": "plate", "length": 80, "width": 60, "thickness": 5, "holes": [ {"x": 10, "y": 10, "d": 6}, {"x": 70, "y": 10, "d": 6}, {"x": 10, "y": 50, "d": 6}, {"x": 70, "y": 50, "d": 6} ] }

这样做的好处是可控性极强。模板是你自己写的,几何逻辑经过验证,模型只负责填参数,出错概率大幅降低。缺点是覆盖面有限,模板没覆盖的零件类型就处理不了。适合产品线相对固定的场景,比如专门做钣金件、专门做型材连接件。

2.3 路线三:调用专业 CAD 的 API

FreeCAD、Fusion 360、SolidWorks 都提供了 API 接口。你可以让大模型生成 API 调用代码,直接操作 CAD 内核建模。FreeCAD 的 Python API 是开源方案里最成熟的选择,Part.makeBox、Part.makeCylinder、Part.cut这些方法可以完成大部分基础建模操作。

这条路线生成的是真正的 B-rep 实体,导出 STEP 后精度和原生 CAD 建模一致,可以直接用于加工。代价是 API 学习曲线陡,而且大模型对 FreeCAD API 的熟悉程度不如对 OpenSCAD 那么高,生成的代码经常需要查文档修正。

2.4 路线四:文本到图像再到三维重建

还有一条偏视觉的路线:先用文生图模型生成零件的多视角渲染图,再用三维重建算法(如多视图立体视觉或神经辐射场)还原出网格模型,最后导出 STL 或 GLB。

这条路线的优点是不依赖 CAD 脚本能力,理论上任何形状都能处理。但缺点致命:重建出来的模型是网格,不是参数化实体,没有精确的尺寸,孔可能不圆,平面可能不平。用于 3D 打印的视觉展示还行,用于工程制造基本不可用。所以我不推荐把它作为 text-to-cad 的主路线,最多作为辅助手段。

路线核心方式输出精度实现难度适用场景
大模型直接生成脚本LLM 输出 OpenSCAD/FreeCAD 代码中低快速草稿、简单零件
参数表驱动模板LLM 解析参数 + 预写模板高中产品线固定的批量零件
调用 CAD APILLM 生成 API 调用代码高高需要精确 STEP 的工程件
文本到图像到三维文生图 + 三维重建低中视觉展示、概念预览

我个人的建议是:以路线二为主,路线一为辅。日常用参数表驱动模板保证稳定性,遇到模板覆盖不了的形状时,退回路线一让模型直接写脚本,人工检查后再用。这样兼顾了效率和可靠性。

3. 核心环节拆解:从文字到 STEP 的每一步

3.1 语言理解与几何参数提取

这一步的目标是把一段人话变成机器能处理的参数。听起来简单,实际是整个链路里最容易出问题的环节。原因在于工程描述里充满了隐含信息。

比如“四角各有一个通孔,孔中心距边缘 10mm”,人一看就懂,但机器需要明确:四个角的坐标分别是多少?如果板子是 80×60,那四个孔的中心坐标就是 (10,10)、(70,10)、(10,50)、(70,50)。这个换算需要模型理解“距边缘”的含义,并且知道坐标系原点在左下角。

再比如“孔要打通”,这意味着孔的深度等于板厚,而不是一个固定值。如果描述里说“沉头孔”,那还需要额外的沉头直径和深度参数。这些工程语义是参数提取的难点。

我的做法是在提示词里给模型一个参数 schema,明确告诉它需要输出哪些字段,每个字段的含义和单位。比如:

请将以下描述解析为 JSON,字段包括: - length, width, thickness:单位 mm - holes:数组,每个元素包含 x, y, d(孔径),可选 counterbore_d(沉头直径) - fillets:圆角半径数组 - material:材料名称(可选)

给了 schema 之后,模型输出的结构化程度会大幅提升。但即便如此,单位换算仍然要小心。有些人说“8 厘米”,有些人说“80mm”,模型有时候会混。我通常会在提示词里强制要求“所有尺寸统一转换为毫米”。

注意:参数提取完成后,一定要做一次范围校验。比如孔径不能大于板宽,孔位不能超出边界,厚度不能为负数。这些校验用几行 Python 就能写,但能挡掉大部分低级错误。

3.2 CAD 脚本生成与几何构建

参数拿到之后,就要生成几何了。以 FreeCAD 为例,一个带孔底板的构建逻辑是这样的:

import FreeCAD as App import Part doc = App.newDocument() plate = Part.makeBox(80, 60, 5) for hole in holes: cylinder = Part.makeCylinder( hole["d"] / 2, 5, App.Vector(hole["x"], hole["y"], 0) ) plate = plate.cut(cylinder) Part.show(plate) doc.saveAs("/path/to/output.FCStd")

这段代码的逻辑很清晰:先建一个长方体,然后对每个孔建一个圆柱,用布尔减运算把圆柱从长方体里挖掉。注意圆柱的起始位置要放在板子的底面,高度要等于板厚,这样才能保证打通。

这里有个容易踩的坑:布尔运算的顺序。如果先挖孔再倒角,倒角可能会把孔的边缘也倒掉,导致孔口变形。正确的顺序通常是先做主体形状,再做倒角,最后挖孔。如果孔需要倒角,那要单独处理。

另一个坑是坐标系。FreeCAD 的默认坐标系原点在 (0,0,0),makeBox生成的长方体是从原点向正方向延伸的。如果你的描述里孔位是相对于板子中心定义的,那就要做坐标平移。我一般会在参数提取阶段就统一约定“原点在板子左下角,Z 轴向上”,避免后续混乱。

3.3 格式导出:STEP、GLB、STL 怎么选

模型建好之后,导出格式的选择取决于下游用途。这三个格式的差异很大,选错了会直接影响后续工作。

STEP是精确的 B-rep 实体格式,保留了完整的几何拓扑信息,可以被 SolidWorks、UG、CATIA 等主流 CAD 软件打开并继续编辑。如果你生成的模型要用于加工制造,STEP 是唯一正确的选择。FreeCAD 导出 STEP 的命令是:

plate.exportStep("/path/to/output.step")

STL是三角网格格式,只保留表面几何,没有参数化信息。它的优点是通用性极强,几乎所有 3D 打印切片软件都支持。缺点是精度受网格密度影响,曲面会被离散成小三角面。导出 STL 时需要设置网格偏差参数,偏差越小精度越高,但文件也越大。FreeCAD 里可以这样控制:

import Mesh mesh = Mesh.Mesh(plate.tessellate(0.1)) mesh.write("/path/to/output.stl")

这里的0.1是线性偏差,单位是 mm。对于大多数 3D 打印场景,0.1mm 已经足够。如果零件有精细曲面,可以调到 0.05mm。

GLB是 glTF 的二进制版本,主要用于 Web 端和实时渲染。它支持材质、颜色、光照信息,文件体积小,加载快。如果你要把模型展示在网页上或者做 AR 预览,GLB 是最佳选择。FreeCAD 本身不直接支持 GLB 导出,通常的做法是先导出 STL 或 OBJ,再用 Blender 或 trimesh 库转换成 GLB。

import trimesh mesh = trimesh.load("/path/to/output.stl") mesh.export("/path/to/output.glb")
格式类型精度可编辑性典型用途
STEPB-rep 实体精确高工程制造、CAD 编辑
STL三角网格受网格密度影响低3D 打印、快速原型
GLB三角网格 + 材质受网格密度影响低Web 展示、AR/VR

提示:如果同一个模型要同时用于展示和制造,建议导出两份:STEP 给工程,GLB 给展示。不要试图用一个格式通吃。

3.4 自动化流水线的串联

把上面几步串起来,一条完整的 text-to-cad 流水线大概是这样的:

  1. 接收自然语言输入
  2. 调用大模型提取参数,输出 JSON
  3. 校验参数范围和单位
  4. 用参数填充 CAD 脚本模板
  5. 执行脚本生成模型
  6. 导出 STEP / STL / GLB
  7. 返回文件路径或下载链接

这条流水线可以用 Python 写成一个命令行工具,也可以包成 Web 服务。如果做成 Web 服务,前端收文字,后端跑流水线,用户点一下就能下载模型。我实测下来,一个简单零件的全流程耗时在 10 到 30 秒之间,主要时间花在大模型推理上,几何构建和导出基本是秒级。

4. 实操过程:手把手搭一个最小可用版本

4.1 环境准备与依赖安装

先说明一下,这套流程对硬件要求不高,普通笔记本就能跑。核心依赖是 Python 和 FreeCAD。FreeCAD 的安装是个老生常谈的问题,Windows 上直接下安装包就行,Linux 上可以用包管理器或者 AppImage。

# Ubuntu 下安装 FreeCAD sudo apt install freecad # 安装 Python 依赖 pip install openai trimesh numpy

这里有个坑:FreeCAD 的 Python 模块和系统 Python 有时候不兼容。如果你在系统 Python 里import FreeCAD报错,大概率是路径问题。解决办法是用 FreeCAD 自带的 Python 解释器,或者在脚本里手动把 FreeCAD 的 lib 路径加到sys.path。

import sys sys.path.append("/usr/lib/freecad/lib") import FreeCAD

Windows 下的路径类似,通常是C:\Program Files\FreeCAD 0.21\lib。具体版本号根据你装的版本调整。

4.2 参数提取的提示词设计

提示词的质量直接决定参数提取的准确率。我试过很多版本,最后稳定下来的结构是这样的:

你是一个 CAD 参数提取助手。请将用户的自然语言描述转换为 JSON 格式的几何参数。 规则: 1. 所有尺寸单位统一为毫米(mm) 2. 坐标系原点位于零件底面左下角,Z 轴向上 3. 孔位坐标 (x, y) 指孔中心在底面上的投影 4. 如果描述中缺少必要参数,使用合理默认值并在 warnings 字段中说明 5. 输出必须是合法的 JSON,不要包含任何其他文字 输出格式: { "type": "plate | box | cylinder | bracket", "length": number, "width": number, "thickness": number, "holes": [{"x": number, "y": number, "d": number}], "fillets": [number], "warnings": [string] } 用户描述: """ {user_input} """

这个提示词的关键点在于:明确坐标系、强制单位、要求 warnings 字段。warnings 字段特别有用,当用户描述模糊时,模型会在这里说明它做了什么假设,方便人工复核。

4.3 模板脚本的编写要点

模板脚本是整个流程的骨架。我建议把模板写成函数,接收参数字典,返回生成的模型对象。这样不同的零件类型对应不同的函数,调用时根据type字段分发。

def build_plate(params): length = params["length"] width = params["width"] thickness = params["thickness"] plate = Part.makeBox(length, width, thickness) for hole in params.get("holes", []): cylinder = Part.makeCylinder( hole["d"] / 2, thickness, App.Vector(hole["x"], hole["y"], 0) ) plate = plate.cut(cylinder) return plate

写模板时有几个细节要注意。第一,孔的圆柱高度要等于板厚,不能多也不能少,多了会切到其他零件,少了打不通。第二,布尔运算要用 cut 而不是 fuse,cut 是减法,fuse 是加法。第三,每次布尔运算后要检查结果是否有效,FreeCAD 偶尔会生成空形状或无效形状,可以用plate.isValid()检查。

4.4 完整流程的串联与测试

把参数提取和模板构建串起来,主流程大概是这样:

import json from openai import OpenAI client = OpenAI() def text_to_cad(user_input): # 第一步:提取参数 response = client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_input} ] ) params = json.loads(response.choices[0].message.content) # 第二步:校验参数 validate_params(params) # 第三步:构建模型 if params["type"] == "plate": model = build_plate(params) else: raise ValueError(f"不支持的零件类型: {params['type']}") # 第四步:导出 model.exportStep("/tmp/output.step") mesh = Mesh.Mesh(model.tessellate(0.1)) mesh.write("/tmp/output.stl") return "/tmp/output.step", "/tmp/output.stl"

测试的时候,我建议从最简单的描述开始,比如“一个 50×50×5 的方块”,确认流程能跑通,再逐步增加复杂度。每增加一个特征(孔、圆角、倒角),都要单独测试,确保模板能正确处理。

4.5 参数校验的实操细节

参数校验这一步很多人会跳过,但它是保证输出质量的关键。我一般会检查以下几项:

  • 尺寸为正数:长宽厚都不能是负数或零
  • 孔位在边界内:孔的边缘不能超出板子边缘,即x - d/2 >= 0且x + d/2 <= length
  • 孔径合理:孔径不能大于板子最小边的一半
  • 孔不重叠:两个孔的中心距要大于两孔半径之和

这些校验用简单的 Python 条件判断就能实现。如果校验失败,不要直接报错退出,而是把问题反馈给大模型,让它重新提取参数。我实测下来,加上一轮重试之后,参数准确率能从七成提升到九成以上。

def validate_params(params): errors = [] if params["length"] <= 0 or params["width"] <= 0: errors.append("尺寸必须为正数") for hole in params.get("holes", []): if hole["x"] - hole["d"]/2 < 0: errors.append(f"孔 {hole} 超出左边界") if hole["x"] + hole["d"]/2 > params["length"]: errors.append(f"孔 {hole} 超出右边界") if errors: raise ValueError("; ".join(errors))

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

5.1 模型生成失败或形状为空

这是最常见的问题。表现是脚本执行没报错,但导出的文件是空的,或者模型只有一个点。原因通常有三种:一是布尔运算把整个形状切没了,比如孔的直径比板子还大;二是坐标系搞错了,圆柱建在了板子外面;三是 FreeCAD 的形状有效性检查没通过。

排查方法:在每次布尔运算后打印形状的体积,如果体积变成 0 或者负数,说明运算出了问题。另外可以用Part.show()把中间结果显示出来,肉眼确认形状是否正确。

实操心得:我习惯在模板里加一个assert plate.Volume > 0的检查,一旦体积异常就立即报错,避免生成一堆无效文件。

5.2 导出的 STEP 在 CAD 软件里打不开

STEP 文件打不开,通常是导出时模型本身有问题。FreeCAD 导出的 STEP 对形状有效性有要求,如果模型有自相交、零厚度面、重复顶点等问题,导出的文件可能损坏。

解决办法是在导出前做一次形状修复。FreeCAD 提供了shape.fix()方法,可以修复大部分常见问题。另外,导出时可以用Part.export([plate], path)代替plate.exportStep(path),前者对形状的容错性更好。

5.3 STL 文件太大或太小

STL 的文件大小和网格密度直接相关。偏差设得太小,文件可能几百 MB,切片软件打开都费劲;偏差设得太大,曲面变成多边形,打印出来有明显的棱角。

我的经验值是:普通零件用 0.1mm 偏差,精细零件用 0.05mm,概念预览用 0.2mm。如果零件尺寸特别大(超过 200mm),偏差可以适当放大到 0.15mm,因为大尺寸下的绝对误差容忍度更高。

5.4 大模型输出的 JSON 格式错误

大模型有时候会在 JSON 外面包一层 markdown 代码块,或者加一些解释性文字,导致json.loads失败。解决办法是在解析前先做一次清洗,把代码块标记去掉。

import re def clean_json(text): text = re.sub(r"```json\s*", "", text) text = re.sub(r"```\s*", "", text) return text.strip()

另外,可以在提示词里明确要求“只输出 JSON,不要包含任何其他文字”,这样能减少大部分格式问题。

5.5 孔位计算错误的排查

孔位算错是最隐蔽的问题,因为模型看起来是对的,但尺寸不对。常见原因是坐标系约定不一致。比如用户说“孔在板子中心”,模型可能理解成 (length/2, width/2),也可能理解成 (0, 0)。

排查方法是在参数提取后打印孔位坐标,和预期值对比。如果发现偏差,检查提示词里的坐标系定义是否清晰。我通常会在提示词里加一个示例,明确说明“80×60 的板子,中心孔坐标是 (40, 30)”,这样模型就不容易搞错。

问题现象可能原因排查方法解决方案
模型为空布尔运算切没了打印体积检查孔径和板厚
STEP 打不开形状无效用 FreeCAD 打开检查导出前 fix 形状
STL 太大网格偏差太小查看文件大小调大偏差值
JSON 解析失败格式不纯打印原始输出清洗代码块标记
孔位错误坐标系不一致打印坐标对比提示词加示例

5.6 性能优化的几个技巧

当零件特征数量增加时,布尔运算会变慢。我试过 50 个孔的板子,FreeCAD 的 cut 操作要跑十几秒。优化方法有两个:一是批量布尔运算,把所有圆柱合并成一个复合形状,再一次性 cut;二是用多线程,但 FreeCAD 的 Python API 对多线程支持不好,容易崩溃,所以还是推荐第一种。

# 批量布尔运算 cylinders = [] for hole in holes: cylinders.append(Part.makeCylinder(...)) compound = Part.makeCompound(cylinders) plate = plate.cut(compound)

这样比逐个 cut 快三到五倍。另外,如果只是预览用途,可以先用低精度网格导出 STL,确认形状无误后再生成高精度版本。

6. 这条链路还能怎么扩展

text-to-cad 目前能做到的是规则形状的快速生成,但工程实际中的零件往往更复杂。下一步可以扩展的方向有几个。

一是装配体支持。现在的流程只能生成单个零件,如果能让模型理解“一个底板加四个立柱,立柱安装在底板四角”,就能生成装配体。这需要参数 schema 支持零件之间的位置约束关系。

二是工程图输出。生成三维模型之后,自动投影出三视图和尺寸标注,导出 PDF 或 DXF。FreeCAD 的 TechDraw 模块可以做这件事,但自动化程度还需要打磨。

三是与制造工艺结合。比如识别出零件是钣金件后,自动展开成平面图,加上折弯线和折弯角度。这对钣金加工场景非常实用。

四是多轮对话修改。用户看到生成的模型后说“把孔改成 M6 螺纹孔”,系统能理解这是对上一个模型的修改,而不是重新生成。这需要维护一个对话状态和模型版本。

我自己在实际使用中体会最深的一点是:text-to-cad 的价值不在于完全替代 CAD 操作,而在于把重复性的建模工作自动化。它最适合的场景是那些结构相似、参数不同的零件族。对于全新的、复杂的结构设计,人工建模仍然不可替代。把 text-to-cad 当成一个高效的草稿工具和批量生成工具,而不是万能的设计师,心态就对了。

最后分享一个小技巧:如果你经常生成同一类零件,可以把常用的模板和提示词存下来,做成一个配置文件。下次直接调用,连提示词都不用重新写。我自己的配置里存了十几种常用零件模板,从简单的垫片到带加强筋的支架都有,日常使用基本够用。

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

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

立即咨询