☰
text-to-cad 实战:从自然语言到 STEP 模型的完整链路
2026/10/7 21:10:31 网站建设 项目流程

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

第一次听到 text-to-cad 这个词,很多人脑子里浮现的画面大概是:对着电脑敲一句“给我画一个带四个轮子的小车底盘”,然后屏幕上就自动生成一个可以旋转、可以导出、可以拿去打印的模型。这个想象不算离谱,但也不完全准确。text-to-cad 本质上是一类把自然语言描述转换成 CAD 可识别几何模型的技术方案集合,它的输出通常不是某个私有格式的图纸,而是 STEP、URDF、G-code 这类通用性更强的中间产物。换句话说,它做的不是“替你画图”,而是“替你把意图翻译成机器能读的几何语言”。

我接触这个方向是从一个很具体的需求开始的:手头有一批参数化的支架零件,每次改尺寸都要在 CAD 软件里手动拉伸、打孔、倒角,重复劳动太多。后来想,能不能用一段文字描述直接生成模型,再导出 STEP 丢给下游做仿真。试了几套方案之后发现,text-to-cad 并不是一个单一工具,而是一条链路:自然语言理解、几何参数抽取、建模内核调用、格式导出,每一环都有坑。它适合谁?适合那些需要快速验证结构想法的人、需要批量生成参数化零件的人、以及想把大模型能力和传统 CAD 工作流接起来的人。如果你只是偶尔画一张二维图纸,那它对你的价值有限;但如果你面对的是重复性建模任务,这套东西能省下大量时间。

需要先说明的是,当前 text-to-cad 的成熟度还处在“能用但不够稳”的阶段。它擅长生成结构相对规整、参数明确的零件,比如法兰、支架、齿轮毛坯、简单装配体;对于自由曲面、复杂倒角、装配约束关系,它往往力不从心。所以我在实际使用中会把它的定位放在“初稿生成器”和“批量参数化工具”上,而不是“替代 CAD 工程师”。这个定位很重要,决定了你后面怎么选工具、怎么设计流程、怎么验收结果。

2. 核心链路拆解:一句话是怎么变成 STEP 文件的

2.1 自然语言到结构化参数的转换逻辑

text-to-cad 的第一步,是把“一个长 80 宽 60 厚 5 的板,四角各打一个直径 6 的孔”这种描述,拆成机器能处理的键值对。这一步看起来简单,实际上是最容易出问题的地方。因为自然语言里充满了省略、指代和隐含约束,比如“四角各打一个孔”,机器需要知道“四角”指的是矩形四个顶点附近,“各”意味着对称分布,“直径 6”是孔径而不是半径。

我试过几种不同的解析策略。一种是纯规则匹配,用正则去抓数字和单位,优点是可控、可预测,缺点是稍微换个说法就失效。另一种是调用大模型做意图识别,让它输出 JSON 格式的参数表,优点是灵活,缺点是偶尔会编造不存在的参数。实际比较稳的做法是两者结合:先用大模型把句子转成结构化描述,再用规则校验数值范围和单位,最后交给建模内核。

这里有个关键细节:单位。CAD 领域里毫米和米混用是家常便饭,STEP 文件本身不强制单位,但下游软件读取时会按自己的默认值解释。我踩过一次坑,生成的模型在 FreeCAD 里看是 80 毫米,导入另一个软件变成 80 米,整个装配体直接飞出视野。后来我在参数抽取阶段就强制把所有长度统一成毫米,并在导出时显式写入单位信息。

2.2 几何内核的选择与调用方式

参数有了,接下来要真正“画”出几何体。这一步依赖几何内核,常见的有 OpenCASCADE、CGAL、以及一些商业内核的 Python 绑定。OpenCASCADE 是我用得最多的,因为它是开源的,Python 绑定相对成熟,能处理实体建模、布尔运算、倒角、抽壳这些常规操作。

调用方式上,我倾向于用 CadQuery 或 build123d 这类声明式建模库。它们的好处是把建模操作抽象成链式调用,代码读起来接近自然语言。比如画一个带孔的板,代码大概是这样:

import cadquery as cq result = ( cq.Workplane("XY") .box(80, 60, 5) .faces(">Z") .workplane() .rect(60, 40, forConstruction=True) .vertices() .hole(6) )

这段代码的意思是:在 XY 平面上建一个 80x60x5 的盒子,选顶面,在顶面上画一个 60x40 的构造矩形,取它的四个顶点,各打一个直径 6 的孔。你看,这跟自然语言描述的对应关系非常直接。text-to-cad 要做的,就是把前面抽取出来的参数,映射成这样的建模脚本。

注意:几何内核的布尔运算对模型拓扑很敏感。如果两个实体只是面贴面而没有真正相交,布尔并集可能产生无效实体。我在生成装配体时习惯让零件之间保留 0.1 毫米的过盈,确保布尔运算能正确执行。

2.3 导出格式的差异与选择依据

模型建好之后,导出成什么格式,取决于下游用途。STEP 是最通用的三维交换格式,适合做仿真、CAM 加工、跨软件协作;URDF 是机器人领域描述连杆和关节的格式,适合做运动学仿真;G-code 是数控加工指令,适合直接驱动机床或 3D 打印机。

这三种格式的生成逻辑完全不同。STEP 导出相对简单,几何内核直接支持。URDF 需要额外定义连杆坐标系、关节类型、惯性矩阵,text-to-cad 生成的往往只是视觉几何体,物理属性还得手动补。G-code 更复杂,它需要切片或刀路规划,通常要经过 CAM 软件中转,不是直接从几何体一步到位。

我一般的做法是:text-to-cad 负责生成 STEP,作为几何真值;如果需要 URDF,再写脚本把 STEP 里的实体按命名规则拆成连杆,补上关节定义;如果需要 G-code,把 STEP 导入切片软件或 CAM 工具,用它们的参数模板生成。这样分工明确,每一环都可控。

3. 实操环境搭建:从零把链路跑通

3.1 基础依赖安装与版本匹配

先把环境搭起来。我用的组合是 Python 3.10 + CadQuery 2.4 + OpenCASCADE 7.7。为什么不追最新版?因为 CadQuery 和 OpenCASCADE 的版本耦合比较紧,新版有时候会引入 API 变动,导致旧脚本跑不通。3.10 这个 Python 版本在科学计算和 CAD 生态里兼容性最好,踩坑最少。

安装命令如下:

conda create -n text2cad python=3.10 conda activate text2cad conda install -c conda-forge cadquery=2.4 pip install openai

这里用 conda 而不是 pip 装 CadQuery,是因为 conda-forge 渠道已经把 OpenCASCADE 的二进制依赖打包好了,pip 装的话经常卡在编译环节。我试过在 Windows 上直接用 pip 装,结果 OCCT 的 DLL 找不到,折腾了一下午。conda 一条命令解决。

大模型接口这块,我用的是通用的对话补全接口,把自然语言转成 JSON 参数。你需要准备一个 API key,放在环境变量里,不要硬编码在脚本中。

3.2 参数抽取脚本的编写要点

参数抽取脚本的核心是提示词设计。我试过很多版本,最后稳定下来的提示词结构是这样的:先给模型一个角色设定,再给输出格式的严格约束,最后给几个示例。示例非常重要,它能让模型理解你期望的粒度。

import json import os from openai import OpenAI client = OpenAI(api_key=os.environ["API_KEY"]) PROMPT_TEMPLATE = """ 你是一个 CAD 参数抽取助手。用户会用自然语言描述一个零件, 你需要输出 JSON,包含以下字段: - shape: 基础形状,可选 box, cylinder, plate - dimensions: 尺寸字典,单位统一为毫米 - features: 特征列表,每个特征包含 type 和参数 只输出 JSON,不要输出其他内容。 示例输入:一个长80宽60厚5的板,四角打直径6的孔 示例输出:{"shape":"plate","dimensions":{"length":80,"width":60,"thickness":5},"features":[{"type":"hole","diameter":6,"count":4,"position":"corners"}]} """ def extract_params(text): resp = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": PROMPT_TEMPLATE}, {"role": "user", "content": text} ], temperature=0 ) return json.loads(resp.choices[0].message.content)

温度设成 0 是为了让输出稳定,同样的输入尽量得到同样的参数。实测下来,加了示例之后,参数抽取的准确率从六成提升到九成以上。剩下的错误主要集中在单位缺失和位置描述模糊上,需要靠后处理规则兜底。

3.3 建模脚本的自动生成与执行

拿到 JSON 参数后,下一步是把它翻译成 CadQuery 代码。我写了一个模板函数,根据 shape 字段选择不同的建模分支,再把 dimensions 和 features 填进去。

def build_model(params): shape = params["shape"] dims = params["dimensions"] if shape == "plate": model = cq.Workplane("XY").box( dims["length"], dims["width"], dims["thickness"] ) for feat in params.get("features", []): if feat["type"] == "hole": model = model.faces(">Z").workplane().rect( dims["length"]*0.7, dims["width"]*0.7, forConstruction=True ).vertices().hole(feat["diameter"]) elif shape == "cylinder": model = cq.Workplane("XY").circle( dims["diameter"]/2 ).extrude(dims["height"]) return model

这段代码里有个细节值得说:打孔时我用了 0.7 倍的构造矩形,而不是直接用零件外轮廓。原因是如果孔位贴着边缘,布尔减运算可能切穿侧面,产生开口。留出余量之后,孔就稳稳落在实体内部。这个比例不是固定的,零件越小余量要越大,我一般按最短边的 15% 来留。

生成模型后,导出 STEP 只需要一行:

cq.exporters.export(model, "output.step")

3.4 批量生成与参数表驱动

单个零件跑通之后,批量生成就简单了。我通常维护一个 CSV 参数表,每行是一个零件的描述,脚本读一行、生成一个 STEP,文件名用零件编号命名。

import csv with open("parts.csv") as f: reader = csv.DictReader(f) for row in reader: params = extract_params(row["description"]) model = build_model(params) cq.exporters.export(model, f"output/{row['id']}.step")

这套流程跑下来,一百个参数化零件大概十几分钟就能全部生成,比手动建模快了一个数量级。而且参数表本身就是文档,改尺寸只需要改表格,不用碰代码。

4. 格式转换与下游对接的实战细节

4.1 STEP 导出时的单位与精度控制

STEP 导出有两个参数经常被忽略:单位和精度。CadQuery 默认导出的 STEP 是毫米,但有些下游软件会按英寸读取。为了保险,我在导出后会用文本编辑器打开 STEP 文件,检查文件头里的单位声明。STEP 是文本格式,开头几行能看到SI_UNIT之类的标记。

精度方面,默认的线性公差是 0.001 毫米,对大多数零件够用。但如果你的模型尺寸很大,比如几米长的结构件,这个公差会导致文件体积膨胀。我一般按模型最大尺寸的百万分之一来设公差,既保证精度又控制体积。

提示:STEP 文件里的实体命名会影响下游识别。CadQuery 默认给实体起名Solid1、Solid2,导入装配软件后很难对应。我习惯在导出前给每个实体设置有意义的名字,比如base_plate、mounting_bracket,这样下游做装配时一目了然。

4.2 URDF 生成:从几何体到机器人模型

URDF 的生成比 STEP 麻烦得多,因为它不只需要几何形状,还需要连杆的坐标系、关节的旋转轴、质量惯性矩。text-to-cad 生成的几何体只是视觉部分,物理部分得补。

我的做法是:在参数抽取阶段就要求模型输出连杆和关节的拓扑关系,比如“底座通过旋转关节连接大臂,大臂通过旋转关节连接小臂”。然后写一个 URDF 模板,把几何体路径、关节原点、旋转轴填进去。

<robot name="arm"> <link name="base"> <visual> <geometry> <mesh filename="base.step"/> </geometry> </visual> </link> <joint name="joint1" type="revolute"> <parent link="base"/> <child link="arm1"/> <origin xyz="0 0 0.05" rpy="0 0 0"/> <axis xyz="0 0 1"/> </joint> </robot>

这里的关键是 origin 的 xyz 偏移,它决定了关节在空间中的位置。如果偏移设错,机器人动起来就会散架。我一般先在 CAD 软件里量好关节中心到连杆原点的距离,再填进 URDF。惯性矩阵如果懒得算,可以用简化公式,把连杆当成圆柱体估算,对运动学仿真影响不大。

4.3 G-code 生成的前置条件与参数设置

G-code 不是 text-to-cad 直接产出的,中间要经过切片或 CAM。以 3D 打印为例,把 STEP 导入切片软件后,需要设置层高、填充率、支撑、温度这些参数。这些参数跟几何形状无关,跟材料和设备有关,所以不适合放在 text-to-cad 阶段。

我通常把 text-to-cad 的产出定位在 STEP,然后针对不同的加工方式准备不同的切片配置模板。比如打印 PLA 用一套参数,打印 PETG 用另一套,切换时只换模板,不动模型。这样职责清晰,模型只管形状,工艺参数管加工。

5. 常见问题排查与避坑经验实录

5.1 模型生成失败的典型原因

跑 text-to-cad 最常遇到的报错是布尔运算失败,提示BRep_API: command not done。这个错误九成以上是因为两个实体没有真正相交,或者相交面存在微小间隙。解决办法是让参与布尔运算的实体有明确的重叠区域,哪怕只有 0.01 毫米。

另一个高频问题是孔位越界。如果参数抽取时把孔的位置算到了零件轮廓外面,打孔操作会失败或者产生开口。我的处理方式是在建模脚本里加一层校验:计算孔中心到最近边缘的距离,如果小于孔径的一半,就自动把孔往内移,并打印一条警告日志。

还有一种情况是模型生成了但导出 STEP 时报错,通常是实体不是闭合的。这时候可以用 CadQuery 的isValid()方法检查,无效的话尝试用clean()修复,或者调整建模顺序,先做布尔运算再做倒角。

5.2 参数抽取偏差的修正策略

大模型抽取参数偶尔会犯低级错误,比如把“直径 6”理解成“半径 6”,或者把“厚 5”当成“高 5”。我总结了几条修正规则:孔径和轴径默认按直径处理,除非描述里明确说“半径”;板类零件的厚度对应最小维度;圆柱的高度对应轴向尺寸。

如果描述里出现“大约”“左右”这类模糊词,我会在参数表里加一个容差字段,默认正负 5%。下游使用时可以按容差做公差分析,而不是当成精确值。

5.3 下游软件导入时的兼容性问题

STEP 导入不同软件时,最常见的兼容性问题是曲面缝合。有些软件对曲面的连续性要求高,如果模型里有微小缝隙,导入后会变成片体而不是实体。我一般导出前用sew操作把相邻面缝合成实体,再导出。

URDF 导入机器人仿真环境时,常见问题是 mesh 路径找不到。URDF 里的 mesh 路径可以是相对路径也可以是绝对路径,我建议用相对路径,并把 STEP 转成 STL 或 DAE 格式,因为有些仿真环境不直接支持 STEP。

问题现象可能原因排查方法解决手段
布尔运算失败实体未相交或间隙过大检查实体包围盒是否重叠增加过盈量至 0.01mm
孔位越界参数抽取位置错误计算孔心到边缘距离自动内移并告警
STEP 导入变片体曲面未缝合用isValid()检查导出前执行sew
URDF mesh 丢失路径错误或格式不支持检查路径和格式用相对路径并转 STL
单位错乱单位未统一检查 STEP 文件头强制毫米并显式声明

5.4 性能优化:批量生成时的资源控制

批量生成几百个零件时,内存和 CPU 会成为瓶颈。OpenCASCADE 的布尔运算比较吃资源,如果串行执行,速度慢且容易内存泄漏。我的做法是用多进程池,每个进程独立处理一个零件,跑完就释放。进程数设成 CPU 核心数的一半,留出余量给系统。

from multiprocessing import Pool def process_part(row): params = extract_params(row["description"]) model = build_model(params) cq.exporters.export(model, f"output/{row['id']}.step") with Pool(4) as p: p.map(process_part, rows)

另外,大模型接口调用有速率限制,批量抽取参数时最好加一个重试机制和间隔。我一般设 0.5 秒间隔,失败重试三次,基本能稳定跑完。

6. 能力边界与扩展方向

6.1 当前方案的局限性

text-to-cad 目前最明显的短板是复杂曲面和自由造型。你让它生成一个流线型外壳或者一个有机形态的支架,它基本无能为力,因为参数抽取阶段就无法用简单的键值对描述这类形状。另一个短板是装配约束,它能生成多个零件,但零件之间的配合关系、运动副定义还得手动补。

还有一个隐性问题是可解释性。大模型抽取参数的过程是个黑盒,同样的描述跑两次可能得到略有差异的结果。对精度要求高的场景,这不可接受。我的应对方式是把大模型输出当成初稿,关键尺寸人工复核,或者用规则引擎做二次校验。

6.2 与现有 CAD 工作流的融合方式

我不建议把 text-to-cad 当成独立工具用,而是把它嵌到现有工作流里。比如在参数化设计阶段用它快速生成候选方案,选定后再导入传统 CAD 软件做精细调整。或者在批量出图阶段用它生成标准件库,减少重复劳动。

跟传统 CAD 的接口就是 STEP。STEP 是通用格式,几乎所有 CAD 软件都能读。生成 STEP 后,在 SolidWorks、Fusion 360、中望 CAD 里打开,继续做装配、出工程图、标注尺寸。这样既享受了自动化的效率,又保留了传统工具的精细控制能力。

6.3 后续可以尝试的改进点

我接下来想试的一个方向是把 text-to-cad 和参数优化结合起来。比如给定一个受力条件,让脚本自动调整筋板厚度和位置,生成多个方案,再用有限元分析筛选。这样就从“描述生成”进化到“目标驱动生成”。

另一个方向是支持更多输入模态。现在只支持文字,如果能支持草图或者点云,适用范围会大很多。比如拍一张手绘草图,自动识别轮廓和尺寸,生成三维模型。这个方向已经有了一些研究,但离实用还有距离。

最后再分享一个小技巧:如果你要生成一批相似的零件,不要每个都从头抽取参数,而是先生成一个基准模型,然后用参数表驱动尺寸变化。这样一致性更好,也更容易做版本管理。我在做系列化支架时就是这么干的,基准模型只建一次,后面改尺寸全靠表格,效率提升非常明显。

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

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

立即咨询