第一次接触到 text-to-cad 这个概念时我正被一批杂七杂八的机械零件建模需求搞得焦头烂额——一个连接头要改法兰尺寸一个支架要换螺栓孔位电话里对方描述得眉飞色舞我却得一句句猜着画。后来我开始尝试让程序直接听懂文字把“描述”变成“模型”。折腾了大半年我算是把 text-to-cad 的几条主要路径摸了个大概。这篇文章不吹不黑只聊我实际跑通、并且能落地的方案以及踩过的坑。先说结论现阶段指望对着软件说一句“给我生成一个减速器”就能得到可直接加工的总成还不太现实。但如果你把任务缩小到一个零件、一个特征明确的单体模型text-to-cad 已经能大幅缩短建模时间。我目前的日常流程是用大模型解析自然语言把几何约束翻译成参数化代码再用 OpenSCAD 或 CadQuery 生成可编辑的实体模型。这个流程不算酷但很稳我也从里面拿到了一批真实用在手工打样和 3D 打印上的零件。1. 别被“一键生成”带偏text-to-cad 的三条真实技术路线text-to-cad 的概念本身不复杂人类用自然语言描述一个三维物体程序输出一个 CAD 模型。但“CAD 模型”这四个字藏着很多坑。它可能指一个纯显示的三角网格 STL也可能指带特征树、可参数化修改的 STEP 或原生工程图。不同输出对技术路线的要求完全不一样。1.1 端到端式的“黑盒”生成听起来很美这是很多文章最喜欢提的方向训练一个神经网络输入一句话“一把带纹理的椅子”直接输出一段 SDF符号距离场或者体素网格再通过后处理变成网格模型。这类方法的 demo 通常很有视觉冲击力因为 AI 可以生成非常复杂的曲面和拓扑结构。但落到工程实践中问题一串生成的网格经常有空洞、非流形边、法向错乱修都修不干净模型没有参数化特征你没法回去改一个孔的直径或一块板的厚度输出通常是 OBJ/GLTF 而不是 STEP加工端根本不愿意接收。所以我把这条路线定性为“参考和灵感阶段”拿来看造型完全可以拿来出工程图基本没戏。除非你的目标只是做游戏资产或单纯可视化否则别把它当成 text-to-cad 的主流答案。1.2 代码生成式的“白盒”路径我真正推荐的方向另一种做法是让大模型写代码。这里说的代码不是 C 或者 JavaScript而是建模专用脚本——OpenSCAD 的 .scad 文件或者 CadQuery、PythonOCC 这类基于 Python 的程序化建模代码。大模型本身并不直接“画”模型它生成的是构建模型的三维布尔运算和拉伸、扫掠命令。你运行脚本得到的是带特征历史feature history的实体改一个参数就能重新生成。这条路径是目前工程价值最高的。一方面脚本天然可复现你随时能 diff 两版代码看哪里变了另一方面模型自带参数块后期改尺寸比传统 CAD 还要快。更重要的是大模型对这类结构性语言的掌握效果出奇地好——OpenSCAD 语法简单、规则明确GPT 类的模型很少写到大错CadQuery 稍微复杂些但只要给出良好示例它也能稳定输出可用代码。1.3 混合路线自然语言调用参数化模板补一条我自己经常用的“半成品”方案事先在代码库里准备一批参数化模板——类似法兰、支架、齿轮、外壳这些常用件把尺寸、孔数、圆角半径全部写成变量。再让大模型把自然语言映射到模板参数上例如“四个孔直径 6法兰外径 70”对应到flange_template(d_out70, hole_d6, hole_count4)。这不算严格意义的“生成”但胜在可靠。对团队而言这种方案能在需求量集中时快速交付而且不需要 AI 理解太深的几何语义。在这三条路线里我后面讲到的实践集中在第二条中间偶尔会用第三条兜底。因为它们都保留了“代码”这个中间层出了问题能检查、能修正不会让你面对一个无法解释的黑盒。2. 我的主战装备让大模型写 OpenSCAD 和 CadQuery工欲善其事必先利其器。在 text-to-cad 这场实验里我最早尝试的是让大模型直接输出 STL 文件——它压根做不到输出格式一塌糊涂。后来我把目标改成生成脚本一下就通了。现在我的工具链以两个库为核心OpenSCAD 和 CadQuery。2.1 为什么是 OpenSCAD 而不是“更专业”的 CAD 二次开发很多人觉得 OpenSCAD 太玩具不够“工业级”。我的看法相反正是因为 OpenSCAD 的语义简单、不依赖鼠标交互、所有东西都是纯代码它才最适合当 text-to-cad 的“接口语言”。你让模型写 AutoLISP 或者 Revit API它会因上下文过长而遗忘很多相关 API写出来的代码经常调用了不存在的函数。而 OpenSCAD 的核心命令就那几个cylinder、cube、translate、rotate、difference、union、hull。大模型训练语料里这类代码太多了生成质量稳定调试也快。另一个关键点是 OpenSCAD 天然是参数化建模。你可以在文件头部定义flange_d 80;pipe_d 34;之类变量后文的几何全部引用这些变量。大模型非常擅长维护这种依赖关系这让用户后续改尺寸变得非常轻松。实际上我很多零件是先让模型生成一个粗糙版本再用修改变量的方式手工微调不需要重新描述整个需求。2.2 CadQuery应付需要加工语义的复杂零件OpenSCAD 擅长实体造型但遇到需要复杂圆角过渡、倒角、抽壳、或者要求输出 STEP 带精确 B-Rep 边界的时候就力不从心了。这时我把脚本生成目标切到 CadQuery。CadQuery 本质上是 Python 库底层依赖 OpenCascade 内核生成的是真正的 BREP 实体能输出 STEP、IGES也可以直接进入 CAM 软件做刀路。CadQuery 的编写模式比 OpenSCAD 更接近“特征建模”思维先在二维平面画草图然后用extrude、cut、fillet这些特征操作生成三维实体。这种结构非常适合大模型理解因为每一步都有一个明确情感的中文描述“在顶面上开一个直径 10 的孔”“对底面进行 2mm 倒角”。我试过让大模型写 CadQuery 代码来还原一个工业传感器支架它居然能自己处理好cq.Workplane的层级关系虽然首次运行报了一点错但整体结构没偏。2.3 两套工具的选择标准我大致按这个规则切分简单钣金件、外壳、结构支架用 OpenSCAD因为代码短、生成快、视觉直观需要出图纸、做圆角过渡、要转 STEP 给加工方的零件用 CadQuery。如果两者都搞不定那就退回参数化模板。这里要提醒一个小问题不要同时让模型在两种语言之间自由穿梭。我在早期没有指定输出语言结果模型一会儿生成 Python 代码一会儿生成 OpenSCAD 代码我只能手忙脚乱地开两个环境。现在我会在 system prompt 里明确“你只能用 CadQuery 生成 Python 脚本”终结混乱。这个习惯建议你一开始就养成。3. 实战一句“带法兰的管道接头”变成可编辑模型的完整过程理论说了一堆现在来点真格的。我拿一个真实需求走一遍完整流程朋友要做气动管路需要一个带法兰的管道接头法兰上四个螺栓孔中间主通道通 24mm 内径的气管。他用微信语音描述完我把语音转成文字直接丢给 text-to-cad 流程。下面是全过程。3.1 需求拆解与提示词模板原始描述是“一个带法兰的管道接头法兰外径 80厚度 10法兰四周均匀四个直径 9 的安装孔中心圆孔通径 24主管道外径 34长度 60整体圆角过渡自然一点。”这段文字已经有明确几何参数。但真实情况往往更模糊比如“法兰外径 80”可能换成“差不多拳头大小”这时我会先让大模型反向提问——它问我是不是毫米单位我确认后再补充缺失的约束。我发现一个有效做法把提示词模板固定下来让模型养成“先解构、再输出”的习惯。模板大约长这样你是一个机械CAD建模专家。根据下面的描述生成OpenSCAD代码。 要求 - 使用毫米为单位 - 所有关键尺寸定义为参数变量放到文件头部 - 必须使用实体布尔运算构建模型 - 不要输出STL不要输出截图只输出.scad脚本 - 如果描述存在歧义先列出你的假设再生成代码。这段提示词的前三句是核心单位约定避免把英寸毫米混用参数变量保证后期可改布尔运算给出建模意图。后面两句是兜底让大模型遇到“圆角自然一点”这种模糊词时至少会用$fn和圆角半径给出默认值而不是束手无策。3.2 第一次生成的代码和解读大模型给回来的 OpenSCAD 代码大约长这样$fn 64; flange_d 80; flange_t 10; hole_d 9; hole_radius 31; pipe_d 34; pipe_len 60; bore_d 24; module flange_pipe() { difference() { union() { // 法兰盘 cylinder(h flange_t, d flange_d); // 主管道 translate([0, 0, flange_t]) cylinder(h pipe_len - flange_t, d pipe_d); } // 四个安装孔 for (angle [0:90:270]) { rotate([0, 0, angle]) translate([hole_radius, 0, 0]) cylinder(h flange_t 1, d hole_d); } // 中心通孔 translate([0, 0, -1]) cylinder(h pipe_len 2, d bore_d); } } flange_pipe();第一眼看上去结构是合理的法兰盘和管道先合并再减去安装孔和中心通孔。不过细看问题不少——四个安装孔是从 0 度开始均匀分布的这个没问题但hole_radius 31是怎么来的想象一下法兰外径 80螺栓孔中心圆外径大约要在法兰半径 40 之内留 9mm 边距31 是合理的。这里模型其实是自己做了几何推理而不是抄了一个固定数字。这个细节让我挺意外。3.3 从能渲染到能出加工图试错与修正我把脚本丢进 OpenSCAD按 F5 预览模型外观看着正常但按 F6 完整渲染后我发现了问题中心通孔和安装孔都伸过了法兰底部底面上会留下孔洞边缘的脏面。为什么因为安装孔用一个很长的圆柱做布尔减却只把法兰部分穿透了底面的“开口”是自然的这不影响加工但如果你想要台阶孔或者沉头孔就必须额外操作。真正让我恼火的是第二个问题模型没有标注倒角而原描述中“圆角过渡自然一点”被大模型直接忽略了。我重新带上提示词“在所有外露锐边加 1.5mm 倒角用$fn32控制圆弧精细度。”第二次生成的代码里加了好几个chamfer相关操作但 OpenSCAD 原生其实没有 chamfer 命令它只能靠旋转扫掠一个多边形来模拟代码变得很长且容易出错。这时候我做了个决定把这个零件切换到 CadQuery 重写。因为 CadQuery 内置.edges().chamfer()和.fillet()方法处理倒角干净利落。生成的 CadQuery 代码大概是这样import cadquery as cq flange_d 80 flange_t 10 hole_d 9 hole_radius 31 pipe_d 34 pipe_len 60 bore_d 24 result ( cq.Workplane(XY) .circle(flange_d / 2) .extrude(flange_t) .faces(Z).workplane() .circle(pipe_d / 2) .extrude(pipe_len - flange_t) .faces(Z).workplane() .hole(bore_d, heightpipe_len) .faces(Z).workplane() .pushPoints([(hole_radius, 0), (0, hole_radius), (-hole_radius, 0), (0, -hole_radius)]) .hole(hole_d, heightflange_t 1) .faces(Z).edges().fillet(1.5) .faces(Z).workplane().edges().chamfer(1.0) )这段代码一次跑通。CadQuery 的优势在这里体现得很明显.hole()直接生成穿通孔.faces(Z).edges()可以准确选中顶部边缘做倒角。大模型对 CadQuery 的 API 记忆有时候会出现“幻觉”——会编出不存在的方法名。但只要你把示例代码和当前版本号写进提示词稳定性会好很多。我也是在那个时刻真正意识到text-to-cad 的价值不只是“生成一个看起来像的模型”而是让你能用几十行代码把几何语义准确表达出来还为后续修改留下极大的空间。4. 让模型输出从“看着像”变成“能加工”必须处理的六个细节demo 阶段没人关心模型质量但一落到实际加工很多坑就冒出来了。我总结了自己反复踩过的六个细节逐个列出来每一条背后都有真实教训。4.1 单位与坐标系别看小错一次就完蛋我接到的第一个 text-to-cad 任务是生成一个 80mm 的固定座。大模型默认把“80”当成英寸生成结果是 2032mm。幸运的是我在切片软件里发现了尺寸离谱否则打出来直接浪费几卷料。你需要确保每一版提示词里都有“使用毫米、Z 轴向上、原点在底面中心”这三个约定。对 CadQuery 来说默认的坐标平面是 XY挤出方向是 Z 正半轴。OpenSCAD 的默认坐标系同样是右手系Z 向上。如果模型输出的是 DXF 草图还要额外确认是 XY 平面还是 XZ 平面。4.2 水密性与法向网格检查不能跳过哪怕你用的代码生成路线最终导出 STL 时依然可能踩到非流形网格。常见原因包括两个圆柱表面刚好相切导致布尔运算产生退化边小圆角与平面相交处出现自交面大模型生成的布尔差集顺序不合理留下一层零厚度的薄壁。每次导出后我会用 MeshLab 做一次“检查流形、修复法向”的操作。虽然不能 100% 解决但能提前暴露绝大多数问题。如果问题反复出现更好的办法是直接在 CadQuery 里检查result.val().isValid()——这个方法会检查实体是否符合 B-Rep 有效性比事后修网格靠谱得多。4.3 布尔运算和相交几何别让模型“创意发挥”大模型特别喜欢自由地给圆角、倒角、或者斜切加一些你根本没要求的东西原因在于它的训练数据中那些机械零件的图片和模型常常有美观的过渡。但在加工中随意添加圆角会导致后续开孔位置偏离或者使得两段几何产生非预期相交。比如我试过让模型生成“一个带U型槽的底座”它自己给槽底部加了一个 R3 圆角结果原本打算用端铣刀直接一刀过的工艺变成了需要球头刀的额外工序。所以我的经验是在第一轮生成时明确“禁止添加任何未指定的圆角或倒角除非描述中明确要求”把变量留给后续手工调整。4.4 最小特征尺寸要匹配加工方式与模型对话时大多数人不会意识到加工工艺带来的尺寸下限。3D 打印的最小壁厚通常 0.8mmCNC 铣削的内圆角受刀具半径限制激光切割的缝隙不小于板厚。大模型不一定知道你的工艺条件有时会生成 0.3mm 的壁厚打印出来就是一层纱。我会在提示词里主动加上“壁厚不小于 2mm孔直径不小于 3mm圆角半径不小于 1mm”并用后续参数变量去控制。如果直接生成 STL 网格这一步几乎没法救所以这也是我坚持使用参数化脚本的另一个原因——可以把最小尺寸当成约束写进代码里。4.5 特征命名和可维护性好的 text-to-cad 输出不只是一段能跑的代码它应该具备可读性。我给自己定了个规矩要求大模型给每个关键特征单独建一个 moduleOpenSCAD或方法CadQuery并给核心尺寸起有意义的名字。比如上面的管道接头代码里用flange_t而不是t1、pipe_len而不是h2。这样做有两个好处第一后续跟同事协作时别人能快速看懂模型里哪个变量控制哪段几何第二大模型自己读回去的时候也能准确理解方便迭代修改。这个习惯帮了大忙有次我拿到三个月前生成的脚本看着变量名就能想起当初的设计意图。4.6 参数化档位从“生成一次”到“复用一百次”做 text-to-cad 时不少人的目标是“生成一个模型”但我更看重“能不能衍生一族模型”。一个法兰接头只要改几个变量就能变成不同管径的系列规格。每次生成后我会把变量提取到文件头部用表格列出默认值。下次再遇到类似需求我先让大模型参考旧代码生成新版本而不是从零再来。这不是偷懒而是实际工程中大量零件都是系列化、规格化的机械设计参数化模型让“文字改一版”变得像填表一样容易。5. 搭建属于自己的 text-to-cad 工作流自动化与更多思路当模型生成质量稳定后我开始琢磨怎么把这套东西从“手工复制粘贴”升级成“一键自动化”。目前我搭建的流程是一个 Python 脚本加三个子模块跑一个命令就能完成从文本到最终模型导出。5.1 用 Python 把 LLM 调用、代码生成和预览渲染串起来我写了一个text2cad.py流程大致是读取一个.txt文件里的需求描述。把固定的 system prompt 拼上用户描述调用大模型 API。从返回的字符串里提取第一个代码块保存为.scad或.py。如果是 OpenSCAD用命令行渲染出 PNG 预览图和 STL如果是 CadQuery直接执行 Python 脚本并导出 STEP。把预览图发到企业 IM 群里等人工确认后再进入下一步。关键点在于第 3 步的代码块提取——大模型偶尔会啰嗦在代码前后加上解释文本所以必须用正则或简单字符串匹配找到第一个 标记之间的内容。我一开始图省事直接全员拼接结果把说明文字也拼进代码里OpenSCAD 直接报语法错误。后来换了一个库做代码块截取问题就解决了。import re def extract_code(response: str) - str: match re.search(r(?:openscad|python)?\n(.*?), response, re.DOTALL) if not match: raise ValueError(No code block found) return match.group(1).strip()这个函数看起来简单但救了我无数次。如果你的模型 API 返回的是 JSON记得先把转义字符还原再走正则。不然一个小反斜杠就会让\n变成真换行严重破坏代码缩进。5.2 提示词工程里我踩过的最深的坑我用的第一个提示词很朴素就一句话“用 OpenSCAD 画一个带孔的板子。”结果模型生成了一堆飘在空中的圆环或者左一块右一块的碎片。后来我意识到问题在于模型缺少“空间参考”——它不知道板子应该平行于哪个平面、孔应该垂直于哪个面。解决办法是给模型一个“几何锚点”约定所有模型在建模空间里底面放在 XY 平面上主特征沿 Z 轴方向构建。这个约定对 OpenSCAD 和 CadQuery 都有效。我把这句话写死在 system prompt 里生成模型的可制造性立刻提升一个档次。更神奇的是当大模型遵循这个约定后后续加尺寸约束时它很少跑偏因为所有特征都有了统一的坐标基准。另一个坑是大模型对“内孔直径”和“螺栓孔径”的称呼很容易混淆。比如“直径 9 的孔”它可能生成d9/2当成了半径我检查过好几次才发现出图尺寸差了一倍。这个问题的根因是 OpenSCAD 的参数名用d表示直径用r表示半径CadQuery 的circle()默认接受半径。我在提示词里明确写明“如果描述尺寸为直径使用参数d...所有circle函数传入半径时注释中标注// r d/2”之后这类错误大幅减少。5.3 从“单件生成”到“装配体协作”的探索text-to-cad 做到单件可靠之后我开始尝试多零件装配。目前思路是先把整机拆成一系列零件描述逐一生成再用一个 Python 脚本布置装配位置输出一个带有装配约束信息的 JSON。CadQuery 本身支持多实体也能用cq.Assembly把零件拼在一起。但老实说这一步还不够成熟——大模型很难一次理解多个零件之间的配合关系比如轴和孔的过盈/间隙它经常算错直径差。我的替代方案是先用 text-to-cad 生成每个零件的毛坯再人工在 CadQuery 里加配合尺寸。这样做已经能省掉一半的初始建模时间。如果你也想尝试多零件生成建议把“零件 A 的孔径比零件 B 的轴径大 0.05mm”这类间隙关系直接写进描述不要留给模型自由发挥。5.4 免费工具链的搭配推荐最后给你一份我在用的免费工具链清单全部可本地运行不需要关注任何商业账号或者线上服务。用途工具说明代码生成任意大模型 API 或本地模型推荐系统提示词固定不要频繁切换模型版本OpenSCAD 渲染OpenSCAD 命令行openscad -o out.png -p out.json可做参数化批处理CadQuery 建模cadquery Python 库需要 Python 3.9安装 OpenCascade 内核网格检查MeshLab检查流形、法向、修复细小瑕疵快速测量FreeCAD打开 STEP 做简单测量与截面分析这套组合的成本为零但覆盖了我 90% 的日常需求。如果你有条件也可以添一个付费的在线审图工具但并不是必须。实际用下来的感受是text-to-cad 不会取代 CAD 工程师但它能把工程师从重复的“描述-画图-改尺寸”循环里解放出来。我目前最爽的用法是把常用件模板交给大模型然后用自然语言直接修改参数“把法兰厚度改成 12四孔改成六孔均匀分布。”这种对话式迭代比在传统 CAD 里点十几次鼠标爽太多。不过你也别指望模型一次就给你完美结果给自己留一个“代码审查”环节才是让这套流程真正落地的前提。最后分享一个实用小技巧如果你在提示词里写“请先列出 3 条关于这个模型的假设然后再生成代码”模型的输出质量会明显上升因为它被迫先审视自己有没有理解错需求。这个技巧我屡试不爽推荐给你。
阅读完成 · 觉得有帮助?