前几天客户丢过来一句话需求:“做一个M8的六角头螺栓,总长50,螺纹长30,表面发黑。”搁以前,我第一反应是打开CAD软件,拉伸、旋转、倒角、切螺纹,一套操作下来少说十几分钟,要是再碰上规格改来改去,半小时就没了。最近大半年我一直在折腾text-to-cad这个方向,说白了就是让一句自然语言直接变成CAD建模结果。现在再遇上这种需求,我的工作流已经变成了:先让AI根据文字描述生成建模脚本,我再坐下来检查尺寸和结构逻辑,改改参数,最后丢进渲染器导出STL。人从“亲手建模”变成了“审核AI干的活”,效率提升不是一星半点。
这篇不是论文解读,也不是软件广告,是我实际跑通的一条本地工作流。适合想搞自动化建模的机械工程师、产品设计师、CAD二次开发的人,也适合那些天天被“按这个规格出个图”这种需求折磨的朋友看。我会把技术原理、方案横评、完整搭建步骤和踩过的坑都摊开讲,尽量说人话。
1. text-to-cad的本质:它做的不是“生成模型”,而是“生成建模指令”
我刚接触这个概念时跟大多数人想的一样:输入“一个带法兰的圆管”,屏幕前就应该“啪”地弹出一个完整的实体模型。真去试了一圈才发现,理想很丰满,现实是——大多数成熟的text-to-cad方案,本质上是让AI写代码,而不是让AI凭空捏几何体。
1.1 为什么绕不开“建模语言”这个中间层
目前主流的技术路线大致有三条:
- 大模型直接生成参数化脚本:让LLM输出OpenSCAD、CadQuery、FreeCAD Python这类文本化建模语言的代码。渲染器拿到脚本后执行,生成实体。
- 专用生成模型直接输出几何数据:训练一个类似图像生成模型的神经网络,输入文本,输出B-rep或者网格数据。Zoo的text-to-cad模型走的就是这条路线。
- 大模型调用CAD软件的API:把AutoCAD、SolidWorks的API暴露给LLM,让它像人一样调用命令去建图。这条路最贴近传统操作习惯,但受制于CAD软件本身的API能力和授权模式。
我一开始觉得第二条路线最酷,后来发现工程上最靠谱的反而是第一条。为什么?因为“建模指令”这个中间层太关键了。
拿请厨师做菜打比方。你光说“来一盘鱼香肉丝”,厨房可以给你端出千奇百怪的结果;但你要的是让厨师先写一份菜谱:肉切丝多粗、配料比例多少、下锅顺序如何——这份菜谱才是可复现、可调整、可批量执行的东西。LLM直接吐模型,就像让厨师盲做菜,好则好矣,不可控;LLM生成建模脚本,相当于先出菜谱,后厨照着炒,哪个环节不对改哪里,清清楚楚。
就我个人的落地经验来看,脚本中间层带来了四个其他方案都给不了的好处:
- 每一笔几何都有据可查。模型出错了,翻开脚本就能定位到是哪一行坐标算错了,而不是对着一坨网格发愁。
- 天然参数化。一个螺栓写成module,长度和直径都变成变量,改规格只需改参数,不用重新建模。
- 能进版本管理。脚本是纯文本,丢进Git里随便diff,图纸版本迭代再也不靠文件名后缀“最终版”“最终版2”。
- 批量友好。一个脚本循环执行一千次,就是一千个不同规格的零件,这条后面专门展开讲。
所以我的基本判断是:现阶段搞text-to-cad,别盯着“从文字直接变实体”的科幻效果,踏踏实实让模型写脚本,才是能落地的路。
1.2 一个容易被忽略的前提:文字描述必须“工程化”
还要泼一盆冷水:LLM不是神仙,你给“做一个好看的支架”这种描述,它只能还你一个没尺寸、没约束、没法加工的“装饰品”。text-to-cad能干活的前提是,你的文字描述要按工程语言来——有类型、有尺寸、有相对位置、有表面要求。
比如“M8六角头螺栓,总长50,螺纹长30”,这就是合格的需求描述。单位、规格、关键尺寸全有了。反过来,“帮我做一个类似法兰盘的零件”这种话,我建议你先花两分钟把内径、外径、厚度、孔数和孔距写在纸上,再丢给AI。这不是让你迁就AI,而是任何一份合格的加工图纸本来就应该包含这些信息。你给的信息质量,直接决定生成结果的可用性。
2. 主流方案横评:OpenAI论文、Zoo专用模型、自建LLM流程
text-to-cad这个方向最近一年热度很高,几股力量都在往里面冲。我把实际接触过的方案分成三类,各自什么套路、什么坑,掰开揉碎说。
2.1 三类方案的对比
先看一张表,后面逐条解释。
| 方案 | 核心原理 | 适合场景 | 上手门槛 | 主要短板 |
|---|---|---|---|---|
| OpenAI text-to-cad论文方案 | GPT-4生成CadQuery脚本 | 学术验证、标准化零件库 | 中 | 依赖API,CadQuery学习曲线陡 |
| Zoo/KittyCAD text-to-cad | 专用ML模型直接输出参数化描述和几何 | 快速概念探索、非标生成 | 低 | 生成结果可编辑性弱,偏黑盒 |
| 自建LLM + OpenSCAD | 通用大模型生成OpenSCAD脚本 | 本地批处理、定制流程 | 中低 | OpenSCAD表达复杂曲面较吃力 |
| 商业CAD内置AI助手 | 厂商闭源方案,绑定自家软件 | 日常辅助建图 | 低 | 生态锁定,流程定制空间小 |
2.2 OpenAI论文方案:思路值得抄,但别指望开箱即用
OpenAI那篇text-to-cad的工作流我完整复现过。它的想法很聪明:不训专用模型,直接把GPT-4跟CadQuery绑定,让大模型调用CadQuery的Python API来建模。论文里展示的零件效果确实惊艳,复杂程度远超我当时自建的方案。
但真在本地复现时,我被CadQuery的语法劝退过一轮。CadQuery是Python库,建模逻辑基于“从2D轮廓扫掠”的思维,跟传统CAD软件里“画草图-拉伸”的操作习惯差异很大。我让LLM写了几次,表面上看代码结构像模像样,一执行就报错,不是坐标系引用错了,就是solid没有正确闭合。调通一个简单零件,我花的时间比自己手动建还长。
这方案适合谁?适合愿意啃CadQuery文档、并且有API预算的团队。它的上限高,能生成带复杂倒角、开孔阵列的零件,但代价是你要先跟CadQuery本身混熟,否则你都没法判断是LLM写错了还是API用错了。
2.3 Zoo的专用模型:快是真快,黑盒是真黑
Zoo推出的text-to-cad模型走的是另一条路——它不写代码,而是直接预测几何。输入一句话,返回一个可以预览、可以下载的模型文件,速度极快。我拿它试过生成一些有机曲面造型的壳体、支架,效果确实让人眼前一亮。
但工程上这方案有个绕不开的痛点:生成的是结果,不是过程。模型文件拿到手,我想改一个孔的直径,对不起,回到原始文本描述里改一句话然后重新生成。这跟“参数化建模”的核心理念是对着干的。在探索阶段拿它找找造型灵感没问题,真到了要出加工图、要跟其他零件配合装配的阶段,这种黑盒输出就有点使不上劲了。
2.4 自建LLM + OpenSCAD:我最终的选择
折腾了一圈,我最后是回到了“通用LLM + OpenSCAD”的方案,而且一用就是大半年。原因很朴素:OpenSCAD的建模语言足够简单,LLM不容易写错;语法本身就是参数化表达,跟text-to-cad的目标天然契合;命令行接口齐全,适合塞进自动化流水线。后面几章我细讲这条路怎么搭。
3. 本地部署一套最小可用的LLM+OpenSCAD管线
接下来是干货时间。这套管线的目标很明确:你在本地输入一句带尺寸的零件描述,脚本自动生成OpenSCAD代码、渲染模型、导出STL,全程不用打开传统CAD界面。
3.1 环境准备:别再纠结那些“安装包”问题了
网上搜CAD相关的东西,满屏都是“cad下载”“cad安装教程”“cad如何彻底卸载不影响二次安装”。这套流程里,这些烦恼统统不存在,因为核心软件全是免费开源的。
需要装的东西就三样:
- OpenSCAD:官网直接下压缩包,解压就能跑,不写注册表、不装服务、不弹激活页面。版本选最新稳定版即可。
- Python 3.9+:用来做批量调度、文本处理和命令行调起OpenSCAD。
- 本地大模型运行时或云端API:本地推荐用ollama跑qwen2.5-coder这类代码模型,好处是无隐私顾虑、免费无限量;云端API则更稳。两者接口差别不大,下面代码以ollama为例。
如果你之前被“安装cad一直出现c++2005cpi错误”这种破事折磨过,用这套环境你会感受到什么叫清爽。OpenSCAD本质上是个绿色软件,删掉文件夹就是彻底卸载,不存在残留问题。
3.2 为什么是OpenSCAD,而不是FreeCAD或CadQuery
选OpenSCAD当中间语言,我纠结过一阵子。FreeCAD有完整的Python API,能建模也能出工程图,功能覆盖更全;CadQuery精度高,适合复杂机械件。但最终OpenSCAD胜出,靠的是三条:
- 语法极简。圆柱是cylinder,立方体是cube,平移是translate,旋转是rotate,一晚上就能学会。LLM写这种简单DSL犯错的概率,远低于写CadQuery那种库调用。
- 纯文本即文件。OpenSCAD的.scad文件就是普通文本,天然适配Git。公司的图纸想溯源到具体某个AI生成版本,一句话命令就能搞定。
- 命令行完备。开个终端就能渲染导出,跟Python脚本无缝衔接。FreeCAD虽然也有命令行模式,但各种后台警告、环境变量问题,实属折腾。
当然OpenSCAD的短板也要认:复杂曲面、自由造型它表达起来很吃力,mesh布尔运算偶尔会翻车。但考虑到text-to-cad目前主要解决的是“标准件、板件、规则几何体”的需求,这点短板可以接受。
3.3 提示词工程:把建模规则焊死在系统提示里
LLM写代码翻车,一半原因是提示词太“自由”。你要让AI按你的规矩干活,就得把纪律写在开头。这个系统提示词我迭代了无数版,目前长这样:
你是一名资深CAD建模工程师。根据用户的自然语言描述,生成OpenSCAD代码。 硬性规则: 1. 只输出OpenSCAD代码,不要有任何解释文字。 2. 所有尺寸单位统一为毫米。 3. 所有关键尺寸必须定义为变量,放在文件顶部,变量名用下划线命名法。 4. 必须使用module封装每个独立零件。 5. 若描述存在歧义,禁止编造尺寸,在代码注释处以"待确认:"开头标出问题。 6. 渲染结果必须确保是闭合实体,禁止出现退化几何。 7. 螺纹等细节在概念验证阶段允许省略,但必须在注释中说明省略原因。这段提示词里,第1条治“AI废话”,第3、4条治“可维护性”,第5条治“尺寸幻觉”,第6条治“渲染报错”,第7条治“过度设计”。每一条都是拿真实翻车经历换来的,后面避坑章节我会解释为什么。
3.4 实战:从一句话到STL文件
环境就绪、提示词就位,下面走一遍完整流程。需求是开篇那个:M8六角头螺栓,总长50,螺纹长30。
用户输入的描述:
M8六角头螺栓,总长50mm,螺纹长度30mm,头部对边13mm,头部高度6mm,螺杆直径8mm。经ollama调用qwen2.5-coder生成的OpenSCAD代码,长这样:
$fn = 64; // 全局参数 bolt_diameter = 8; // 螺杆直径 head_across_flat = 13; // 六角头对边距离 head_height = 6; // 头部高度 shank_length = 30; // 螺纹/螺杆长度 total_length = 50; // 总长 module hex_head() { cylinder(h = head_height, d = head_across_flat, $fn = 6); } module shank() { translate([0, 0, head_height]) cylinder(h = shank_length, d = bolt_diameter); } module bolt() { hex_head(); shank(); } bolt();注意,这里LLM很诚实——它知道螺纹的几何建模会让脚本复杂到一个概念验证不该背的包袱,所以直接在注释里说明了省去螺纹。这种行为正是提示词第7条想要的:不装懂、不硬编、留了接口。
把代码存成m8_bolt.scad,终端一条命令渲染:
openscad -o m8_bolt.stl m8_bolt.scad再执行一条,直接导出2D投影轮廓,方便后面快速出图:
openscad -o m8_bolt.dxf --projection=xy m8_bolt.scadSTL文件拿一个免费的CAD看图软件打开,转两圈看看形状对不对。这里顺手解决很多新手的疑问:文件怎么看?FreeCAD、MeshLab、Windows自带的3D查看器都行,根本不用装那些大块头商业软件。
4. 批量生产场景:用Python把“一句需求”变成一整批CAD文件
单件跑通只是及格线。text-to-cad真正让人上头的场景,是批量——几十种规格的零件,描述文字结构化地躺在CSV里,Python脚本一口气全给生成出来。
4.1 需求长什么样
我最近接的一个实际活儿就是这种:给一套管道系统配垫片,规格多得让人头皮发麻——内径从16到200毫米,外径跟着法兰走,厚度有1.5、2、3毫米三档,材质分石棉橡胶和聚四氟乙烯两种。按传统做法,要么找标准件库挨个导,要么手动建几十个模型。用text-to-cad的思路,这活可以拆成三件事:
- 把规格整理成一张CSV表。
- 把“垫片描述”模板化成一句话。
- 写个Python脚本循环调用LLM,批量生成scad和stl。
4.2 模板化描述:批量场景的命门
批量生成的第一要务,是让每一句话需求都稳定、一致。我不建议每次现编描述,而是固定一个模板:
{类型}垫片,内径{内径}mm,外径{外径}mm,厚度{厚度}mm,材质{材质}。有了模板,CSV里每一行数据灌进去,就是一条标准需求。这个模板化动作看着简单,实际决定了批量成功率——自由发挥的描述会产生五花八门的歧义,模板化能把LLM的理解成本降到最低。
4.3 批量调用脚本
下面是核心的Python调度代码。这里用ollama的Python包做示范,换成OpenAI API只需改几行:
import ollama import subprocess import csv from pathlib import Path MODEL = "qwen2.5-coder:7b" SYSTEM_PROMPT = """你是一名资深CAD建模工程师...(就是上面那段,此处省略)""" def build_user_prompt(row: dict) -> str: return ( f"{row['type']}垫片,内径{row['inner_d']}mm," f"外径{row['outer_d']}mm,厚度{row['thickness']}mm," f"材质{row['material']}。" ) def extract_scad(raw_response: str) -> str: # 从模型回复里抠出代码块,兼容“只输出代码”失效的情况 if "```scad" in raw_response: return raw_response.split("```scad")[1].split("```")[0] return raw_response.strip() def main(): rows = list(csv.DictReader(open("gaskets.csv", encoding="utf-8"))) for idx, row in enumerate(rows): # 1. 生成描述 user_prompt = build_user_prompt(row) # 2. 调用本地模型 resp = ollama.chat( model=MODEL, messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_prompt}, ], ) # 3. 提取代码并落盘 scad_code = extract_scad(resp["message"]["content"]) scad_path = Path(f"output/{row['type']}_{row['inner_d']}x{row['outer_d']}.scad") scad_path.write_text(scad_code, encoding="utf-8") # 4. 命令行渲染STL stl_path = scad_path.with_suffix(".stl") subprocess.run( ["openscad", "-o", str(stl_path), str(scad_path)], check=True, capture_output=True, ) print(f"[{idx + 1}/{len(rows)}] {scad_path.name} -> OK") if __name__ == "__main__": main()这段代码没什么高深的,就是把前面单件的流程循环化。关键细节在第3步:extract_scad函数里做了代码块兼容,因为本地模型偶尔不听话,会往代码外面包解释文字。这种防御性处理在批量跑几百个文件时特别重要——裸奔的状态下,哪怕1%的不合规,都会让整个流水线卡死。
4.4 从STL到工程图、从单文件到图纸合并
批量生成STL只是前半场,工程上最后还是要出图交付。我的经验是:STL进FreeCAD,用它的工程图工作台塞进模板,导出PDF,一气呵成。这一步对应很多人搜的“cad转pdf”,其实FreeCAD加上Python脚本可以全自动,但那是另一个话题了。
还有个场景值得提——图纸合并。几十个垫片如果出成几十个零散图纸,甲方看着都头大。我的做法是:用OpenSCAD的投影功能配合Python,把每个零件投影成DXF轮廓,然后用dxfwrite这类库把所有轮廓按网格排到一张图上,导出合并版图纸。这就是把“cad图纸合并”这件事程序化,不再靠手动粘贴排列。
批量生成加上批量出图,这条流水线能在几分钟内交付以前要干两三天的活。当然,前提是你的需求确实是模板化的标准件——一旦混进非标结构,还是得回到单件精调模式。
5. 生成结果校验与常见翻车现场
AI写的代码,翻车是常态,不翻车才是运气。这一章我把半年里踩过最多的坑拿出来晒,每一个都配了判断方法和补救手段。
5.1 高发错误清单
| 错误类型 | 具体表现 | 判断方法 | 补救手段 |
|---|---|---|---|
| 单位错乱 | 模型整体大了一圈或小了一圈 | 对比模型包围盒尺寸 | 提示词里强制“所有尺寸单位毫米” |
| 几何不闭合 | 渲染报错或导出STL破面 | 用MeshLab看边界边 | 提示词强调闭合实体,检查module内布尔运算 |
| 坐标偏移 | 孔位不在预期位置 | 对比原始参数与孔心坐标 | 让LLM在注释里写出数学计算过程 |
| API幻觉 | 用了不存在的OpenSCAD函数 | 一执行就报unknown function | 提供OpenSCAD官方手册片段作为参考 |
| 尺寸约束缺失 | 相邻特征错位、悬空 | 旋转视角一眼可见 | 要求所有尺寸走变量,禁止硬编码常数 |
5.2 最坑的“尺寸幻觉”
LLM最大的问题是“一本正经地编尺寸”。你问它内径16的垫片外径多少,它不查手册,直接推断一个看似合理的数字。这在标准件场景是致命的——垫片外径要跟法兰匹配,编错一个数,整套管道密封就完蛋了。
所以我的提示词里专门加了第5条:歧义时不许编造,必须标“待确认”。实测下来,这条规则能拦住八成幻觉。剩下的两成,靠人工审核脚本时扫一眼参数变量值也能拦住。棱镜我自己的流程是强制要求:所有关键尺寸必须出现在文件顶部的变量区,审核时我只看变量值,不看中间代码。
5.3 排查思路:别对着结果猜,先还原过程
有次批量生成,我发现几个零件倒了角,其他没倒。对着渲染结果猜半天原因,浪费了半小时。后来换个思路,直接看LLM输出的脚本差异——原来是其中一个需求描述里出现了“圆角”二字,LLM就自己加了个minkowski操作。这就是排查text-to-cad问题的正确姿势:不要对着几何图猜,要对着生成脚本查。哪个零件不对,就diff哪个零件的脚本,差异里通常藏着答案。
这个思路其实跟传统CAD排错是相通的。网上总有“cad里面f命令用不了”“cad里面bl命令在cass里面怎么怎么样”这类问题,我处理这类问题向来三步走:第一步确认命令是不是在当前工作空间里不存在;第二步把图纸环境简化到最小区块试;第三步查自定义配置和依赖插件。应用到text-to-cad上也一样——定位问题永远先最小化变量,要么固定提示词换描述,要么固定描述换模型,别两个一起动,否则永远找不到根因。
对批量生成的STL做几何校验,我用下面这套免费组合拳:MeshLab看网格边界、FreeCAD的Part工作台跑一遍boolean cut验证、numpy-stl算体积包围盒。再配合前面提到的投影切割手法,把实体用projection()切出剖面轮廓,导出DXF后跟原始图纸叠加比对——这个过程很像地形工程里的“cad切地形”,地形模型要剖一刀看地下结构,零件模型也要剖一刀看内部几何是否合理。
5.4 模型输出的“正确但没用”
还有一种翻车值得单独说:AI生成的代码语法完全正确、渲染也漂亮,但完全没有制造可行性。比如把M8螺栓的头部高度设成2毫米,能渲出来,但实际装配时螺栓头一拧就滑丝。这种问题提示词管不住,得靠行业知识补位。我的习惯是在提示词里追加一句:
8. 所有尺寸取值必须参考常见机械设计手册的推荐值,不得随意设置。这句话加上之后,LLM那个“一本正经编数据”的毛病收敛了不少,至少输出越来越像老师傅给的数了。
6. 工程落地建议:什么活适合交给text-to-cad,什么活千万别
最后聊点战略层面的判断。text-to-cad热度再高,它也不是万能钥匙。我用了大半年,心里有一本清清楚楚的账。
6.1 适合干的活
- 标准件变体生成:螺栓、垫片、法兰、轴承座这些参数固定、结构清晰的零件,是text-to-cad的舒适区。规格变来变去,本质就是换参数,完美契合。
- 概念设计的快速草模:客户要个“大概样子的支架”,你不必手工去建精细模型,AI出一个草模,改两版就能拿去谈方案。
- 历史图纸的参数化翻新:老图纸只有硬尺寸没有参数关系,把尺寸表丢给LLM重新生成参数化脚本,以后改规格再也不用从头画一遍。
- 教学和演示场景:让学生直观看到“文字描述变成三维实体”的完整链路,对理解参数化建模帮助巨大。
6.2 千万别干的活
- 精密配合件:轴孔配合公差、表面粗糙度、形位公差,这些是text-to-cad目前的盲区。AI生成的模型连螺纹都懒得画,你指望它给你算H7/g6的配合间隙?省省心,这活留给正经CAD和工程师。
- 带装配关系的部件:两个零件之间的相对位置、运动约束、干涉检查,text-to-cad当前完全管不上。它擅长生成“孤零零的零件”,不擅长“零件之间的关系”。
- 复杂曲面和自由造型:OpenSCAD写贝塞尔曲面能让任何程序员崩溃,非要AI硬生成也可以,但调试成本绝对让你后悔。
- 需要严格合规认证的部件:航空、医疗、压力容器这些领域有法规和标准约束,AI生成的数据没法背书,出了事责任还是你的。
6.3 团队落地路线
如果你所在团队想引入这套流程,我建议按三阶段走:
第一步,先让个别工程师本地试水,就按我第三、四章那套搭起来,专门处理标准件需求,跑一个月看看真实效率。
第二步,沉淀提示词模板和校验规范。把试水期积累的系统提示词、出图模板、审核清单固化成文档,变成团队资产,而不是散落在个人聊天记录里。
第三步,接入PLM/PDM系统。生成的全部脚本、STL、工程图按规范命名归档,跟物料编码挂钩。这一步的意义在于,当AI生成效率起飞时,管理能力得能接得住,否则文件满天飞反而更乱。
我自己实际操作中最大的感受是:text-to-cad目前最稳的用法,不是让它全自动干活,而是把它当作一个“能干但需要盯”的实习生。你给它明确的任务描述、验收标准和禁区清单,然后把关审核。这样既吃到了效率红利,又没把质量命门交给一个黑盒。
最后分享一个小技巧:让LLM在写代码前,先用自然语言列一遍建模步骤,你确认步骤对了再让它写脚本。这个动作能把坐标算错、特征遗漏这类低级错误率再砍掉一大截。毕竟建模思路错了,代码写得再漂亮也是白搭。这就是我大半年捣鼓text-to-cad下来,最值钱的一条经验。