ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

自然语言驱动CAD建模:从文字需求到参数化模型实践

自然语言驱动CAD建模:从文字需求到参数化模型实践 1. 先搞清楚text-to-cad是干什么的需求翻译器不是设计终结者最近我花了不少时间折腾text-to-cad方向的实践越跑越觉得这个领域被很多人误解了。如果你以为text-to-cad就是对着屏幕说一句“给我画个零件”电脑就直接吐出一个能开模的完整模型那大概率会失望。但换个角度理解——把产品需求快速转译成可编辑的三维参数模型——它现在就已经能在概念设计阶段帮我省掉大量重复劳动。我身边有做结构设计的朋友听到text-to-cad的第一反应是“CAD要完蛋了”。我每次都直接泼冷水恰恰相反它最合理的定位是给CAD打工。一个真实的场景是工厂客户发来一段文字需求说“需要一块安装板八十乘四十厚两毫米四角打孔中间开个大孔左上角加个定位凸台”。这种描述在机械设计里太常见了以前你得手动建工作平面、拉伸、定位孔位没有三五分钟下不来。如果需求改三版你就得跟着改三遍模型。text-to-cad真正解决的正是这种“从自然语言到几何语义”的翻译成本。1.1 概念设计与“给需求做个形状”之间的断层我们不妨拆开看设计师拿到一段需求文字时脑子里发生的事情并不只有“画一个形状”。先要做语义解析——哪些词是尺寸哪些词是特征哪些词是位置关系然后要做坐标规划——底板中心放在哪孔距边缘留多少接着要做特征顺序——先拉伸主体再打孔再添加凸台最后还要考虑加工合理性——孔不能太小、壁厚不能过薄。传统CAD把人变成了翻译器你要把脑子里的几何规划一步步转成软件能懂的建模命令。text-to-cad的意义在于把这一层交给大语言模型加参数化内核去完成。注意这里不是“替代设计师”而是把设计师从重复的拉伸-挖孔-倒角中解放出来放到更高层的结构规划和方案评估上。就像你不必自己写每一行SQL才能查数据库但你还是得知道自己要查什么数据。1.2 谁最需要text-to-cad谁不需要它从我自己的实践来看下面几类人最值得关心这个方向机械结构工程师经常处理标准件、钣金支架、安装板、外壳开孔这类“特征规律明显”的零件把文字需求变成STEP文件是刚需。非专业建模人员比如项目经理、采购、供应商他们需要一种方式来快速表达自己的需求让建模的人拿到一个“能看的初稿”而不是只靠语言空对空地描述。自动化设计与批量生成场景一套产品参数有成百上千个变体你对每个变体手动建模会崩溃但写一个模板、让text-to-cad按参数生成效率是量级提升。反过来如果你天天处理的是自由曲面、汽车A级曲面、复杂装配体之间的运动约束那text-to-cad目前基本帮不上忙。它不是设计终结者而是重复建模环节的自动化助手。把预期摆正了后面踩坑就少一半。1.3 别用它当CAD的替代品能做什么不能做什么我见过最典型的错误用法是让模型生成一个“漂亮的雕塑造型”然后希望拿去3D打印。结果不是结构自相交就是壁厚不均匀打印出来一碰就碎。text-to-cad擅长的是“参数清晰、特征明确、规则性强”的工程零件不擅长“玄学造型”。同样是生成一个零件你说“直径为20的轴开一个5毫米的键槽两端倒角”它生成出来的东西基本一次就能用你说“设计一个有机形态的灯具外壳”它大概率给你一堆没法制造的网格你还不如用细分建模软件自己拉。所以我总结它的能力边界就一句话把有约束、有尺寸、有特征的文字需求变成有参数语义、可继续编辑的实体模型。这篇文章后面所有内容都是围绕这一句话展开的。2. 从一句话到三维实体这条技术链路为什么非要走代码中间层很多人以为text-to-cad是“文本直接变成3D模型”实际链路并不是一步到位的。我在本地搭过完整流程它的本质是文本 → 中间代码 → CAD内核求值 → 实体模型。中间代码这一步看起来多绕了一道但恰恰是整个方案可控性的关键。2.1 为什么不让大模型直接生成网格文件听到“生成三维模型”很多人第一反应是让模型输出一个.stl网格。但你去查一下就明白网格由成千上万个三角形顶点组成大语言模型本质上是在做概率化的符号序列生成让它逐个顶点去猜坐标生成的网格基本不可用。更重要的是就算你运气好生成了一堆还算封闭的三角面这个模型也没有“语义”——它是直径20的孔还是直径19.8的孔孔心距多少壁厚多少这些信息全部丢失了。网格模型最大的问题还不是精度而是不可编辑、不可参数化。你想把孔从20改成25如果拿到的是STL网格你得重新挖一遍或者整个重新生成。CAD世界里真正值钱的从来不是那堆三角形而是尺寸、约束、特征树、参数关系。这也是为什么工程向的text-to-cad产品不约而同选择了代码中间层。2.2 CadQuery与OpenSCAD作为中间语言的合理性代码中间层里我接触最多的两个是CadQuery和OpenSCAD。CadQuery基于OpenCASCADEOCCT内核属于B-Rep边界表示法建模生成的模型是工业标准的实体能导出STEP格式后续放进FreeCAD、SolidWorks、Onshape都能继续编辑这对我来说是最重要的。OpenSCAD则走CSG构造实体几何路线用布尔运算组合基本体它的语法更接近声明式描述对大模型来说更容易生成。为什么选代码而不是JSON或者某种专门的建模指令集因为代码本身就是可执行的参数化描述。比如cq.Workplane(XY).box(80, 40, 2)这一行不只是生成一个80×40×2的长方体它还保留了“长度80、宽度40、高度2”这些参数。你在代码里把box(80, 40, 2)改成box(90, 40, 2)整个模型重新求值就变了这是任何网格文件都做不到的。2.3 完整链路里每个环节各自负责什么我把自己搭建的链路拆成四段每一段只有一个职责出了问题也容易定位大语言模型负责语义理解与代码生成。输入一段自然语言输出符合CadQuery语法、能在受限环境里直接执行的Python代码。这步的质量决定了后面的一切。代码解析与安全校验负责过滤LLM输出中的意外内容。去掉Markdown标记、检查Python语法、限制可调用的模块避免模型偶然生成一个爆炸性的文件操作指令。CAD内核求值CadQuery把生成的代码翻译成真正的B-Rep实体执行拉伸、打孔、倒角、布尔运算得到一个可以量测体积、检查包围盒的几何对象。导出与后处理把实体导出成STEP或STL喂给本地查看器预览或者直接丢进下游制造流程。这四条链路里第二步是我自己写的最重要的一环。LLM天然是个“概率世界模拟器”它经常会给你看起来完全正确、但一运行就崩的代码。做好拦截和兜底是text-to-cad能不能落地的分水岭。下一章我会把市面上的工具挨个聊一遍再讲我为什么最终选择自建链路而不是直接用现成产品。3. 现有工具实测印象Zoo.dev、BlenderGPT、Spline AI与开源路线网上搜text-to-cad能搜到一大堆产品但真正动手试过之后你会发现它们的目标用户、输出格式、工程可用性差异非常大。我花了两周时间把几条主流路线都跑了一遍这里直接说实测印象。3.1 Zoo.dev Text-to-CAD工程向的代码转STEP路线Zoo.dev的Text-to-CAD是市面上最接近“工程师可用”的方案之一。它的思路是把LLM生成的CadQuery代码放到云端执行然后返回一个可以在浏览器里预览的模型同时提供STEP下载。我实际跑下来对简单机械件——比如带孔安装板、轴承座、法兰盘——生成成功率比较高而且因为输出是CadQuery代码你可以拿到代码再看一遍确认孔位、尺寸有没有跑偏。它的优势是交互层做得省心在线编辑器里可以反复修改提示词重新生成也保留了代码查看和手工微调的能力。不过它毕竟是一个托管服务我对它最大的顾虑是代码执行环境是封闭的遇到想改内核参数、想挂自己的后处理脚本时灵活性不够。如果你是个人工程师想快速验证text-to-cad是不是靠谱我建议先拿Zoo.dev跑几个零件试试找一找“文字转工程模型”的感觉再决定要不要自建。3.2 BlenderGPT与Spline AI更偏可视化表达而非制造BlenderGPT的思路是用LLM生成Blender Python脚本直接在Blender里构建场景和网格。这套方案对3D视觉设计师来说很友好因为Blender的脚本API能控制材质、灯光、动画生成结果的呈现效果很直观。但Blender毕竟不是CAD软件它生成的模型本质上是多边形网格没有参数化特征树也没有工业级公差概念。我试过让它生成一个简单的齿轮看起来像个齿轮但你没法知道模数是多少、压力角是多少更别提导出STEP继续做装配分析了。Spline AI又是另一个方向它面向的是UI设计师和交互原型制作者能在网页端生成可交互的三维场景拖拽一下就改形态上手门槛很低。但这套生态离工程制造更远生成的模型基本没法用来做结构仿真或机加工。我个人的结论是这两个工具适合做“视觉表达”和“快速原型展示”不适合做“制造意图表达”如果你需要的是能开模、能装配、能仿真的模型还是得走CadQuery/OpenSCAD这类参数化路线。3.3 开源路线怎么选LLM的差异比工具差异更大我最终选择自建本质原因是想跑一批批量生成的实验——几百个不同尺寸的钣金支架每个还要按规格命名、按目录归档。现成产品做不到这种批量自动化而自建一条“LLM CadQuery”的管线可以完全按自己的需求定制。在开源的LLM选择上我建议你根据硬件和精度要求来取舍。我比较过几档参数小于7B的小模型生成的CadQuery代码基本只能处理最简单的box加hole稍微复杂一点就出语法错14B到32B级别的模型能处理中等复杂度的零件偶尔需要人工修正如果精度优先、不差那点接口费用直接调用大厂API模型成功率会明显高一截。不要神化某一个小模型也不要以为API模型是万能的——我后面会专门讲代码解析层做得好不好有时候比模型选哪个影响更大。4. 自己搭一个最小可用的text-to-cad服务从提示词到STEP文件下面这部分是我自己一直在用的那套最小链路。跟着做一遍你就能在自己电脑上把一段中文需求变成一个STEP文件。这里我默认你熟悉Python基础并且本机已经装好了Python 3.11。4.1 环境与选型依据本地小模型和云端大模型怎么权衡我先说选型。我跑通的最小链路用的是Ollama加本地模型原因有两个一是本地执行不需要考虑数据外发适合处理一些内部图纸相关的描述二是批量生成几十上百个零件时接口费用会是个不可忽视的成本本地模型只要跑得动生成多少次都不花钱。本地模型我目前推荐从qwen2.5-coder:7b或者llama3.1:8b开始试。它们生成CadQuery代码的能力在我测过的几个开源模型里属于比较稳的但如果你手头有32B的显存优先上32B版本复杂提示词的生成成功率会明显上升。云端API模型我推荐用成熟的多模态大模型它们在指令跟随和格式控制上好很多。如果你不是硬性要求数据不出内网我建议第一版就直接用API模型先把整条链路调通再回来调本地模型。安装Ollama后拉取模型ollama pull qwen2.5-coder:7b确认CadQuery能正常导入pip install cadquery用FastAPI做服务层方便后续通过HTTP调用也方便接内部工具。4.2 提示词模板把约束说全比把需求说满更重要这是我最想强调的一点。给LLM的提示词关键不在于把需求描述得多“像人话”而在于把输出格式和约束规则钉死。我实测下来如果不加约束模型会给你返回一段带解释的代码块甚至返回一个print调试语句写死了也可以把执行环境炸掉。我长期在用的系统提示词长这样你是一个专业的CAD脚本生成器。你只输出CadQuery 2.x版本的Python代码不输出解释、不输出markdown代码块标记。 规则 1. 单位一律是毫米。 2. 使用import cadquery as cq通过result cq.Workplane(XY).xxx().yyy()构建模型最后只输出result变量。 3. 特征顺序先建主体再用hole()开孔、cutBlind()切除、box()添加凸台。 4. 当需求中有冲突比如尺寸自相矛盾、孔径大于板宽时在代码第一行注释中说明冲突点并按“先保证几何不自交、再保证语义正确”的优先级执行。 5. 执行环境里预置了cq但你仍然要显式import。这套提示词的思路是与其期望模型“理解”业务不如强制它“遵守契约”。让它把冲突写进注释而不是自作主张瞎编这个细节能救你很多次。很多冲突模型其实知道但它一旦按自己的理解偷偷改掉你看着输出的模型不对还要从头排查反而更费时间。4.3 后端解析与校验代码授权它出错但拦住它乱跑模型返回的代码不能直接exec。我写了一个很小的解析层先过滤掉Markdown标记用ast做语法检查再放进一个白名单命名空间里执行。注意__builtins__那里一定要限制否则模型哪次突然生成一个os.remove你的文件夹就安静了。import ast from pathlib import Path import cadquery as cq from cadquery import exporters def extract_python(raw: str) - str: text raw.strip() if text.startswith(): parts text.split() for part in parts: if part.startswith(python\n) or part.startswith(python): return part.replace(python, , 1).strip() raise ValueError(没有找到python代码块) return text def safe_build(raw: str, work_dir: Path): code extract_python(raw) tree ast.parse(code) # 语法检查能拦住一半问题 namespace {cq: cq, Workplane: cq.Workplane, __builtins__: {}} exec(compile(tree, generated, exec), namespace) result namespace[result] if not isinstance(result, cq.Workplane): raise TypeError(LLM没有输出Workplane对象实际类型是 str(type(result))) # 自动校验包围盒和需求尺寸对照 bb result.val().BoundingBox() print(f包围盒: {bb.xlen:.2f} x {bb.ylen:.2f} x {bb.zlen:.2f} mm) exporters.export(result, str(work_dir / output.step)) exporters.export(result, str(work_dir / output.stl)) return result执行完之后再算一个包围盒这一步非常重要。比如你要的是80×40×2的板代码执行完算出包围盒是800×40×2说明模型很可能是把单位理解错了直接就能发现不用等拿到STEP再量。4.4 用curl跑一个真实例子安装板带孔与凸台我用一个最常见的例子测全流程。输入这段中文生成一个80×40×2mm的安装板四角有直径4.2mm通孔中心有直径20mm通孔左上角有一个10×10×5mm的定位凸台。在我本地的7B模型下生成出来的代码大致是这个样子import cadquery as cq result ( cq.Workplane(XY) .box(80, 40, 2) .faces(Z).workplane() .rect(64, 24, forConstructionTrue) .vertices() .hole(4.2) .faces(Z).workplane() .center(0, 0) .hole(20) .faces(Z).workplane() .moveTo(-35, 15) .box(10, 10, 5) )这段代码我解释一下。box(80, 40, 2)建立主体坐标系默认在中心faces(Z).workplane()把工作平面移到顶面rect(64, 24, forConstructionTrue)建立辅助矩形四角和板边缘留出8毫米边距.vertices().hole(4.2)在四个角点打出直径4.2的孔。中点那个hole(20)就是中心通孔。最后moveTo(-35, 15)把坐标移到左上角放一个10×10×5的凸台。代码不算复杂但它能稳定输出一个可编辑STEP这就是最基础的价值。不过一个小模型一次就成功不代表次次成功我给API模型同样一段描述偶尔会出现把凸台生成在四个角、或者把通孔画成盲孔的情况。这就说明后面校验环节不能省。4.5 接入FastAPI把能力暴露成服务本地脚本调试通过之后我顺手包了一层FastAPI。这个不是炫技是因为批量生成的时候你不可能手工跑一遍脚本得让上游的工单系统直接调接口。from fastapi import FastAPI, HTTPException from pydantic import BaseModel import ollama app FastAPI() class CadRequest(BaseModel): prompt: str def llm_complete(prompt: str) - str: response ollama.chat( modelqwen2.5-coder:7b, messages[ {role: system, content: TEXT_TO_CAD_SYSTEM_PROMPT}, {role: user, content: prompt}, ], ) return response[message][content] app.post(/generate) def generate_text_to_cad(req: CadRequest): from pathlib import Path raw llm_complete(req.prompt) work_dir Path(/tmp/text2cad) work_dir.mkdir(exist_okTrue) try: result safe_build(raw, work_dir) except Exception as e: raise HTTPException(status_code400, detailstr(e)) return {status: ok, step: str(work_dir / output.step), stl: str(work_dir / output.stl)}然后一条curl就能调curl -X POST http://localhost:8000/generate \ -H Content-Type: application/json \ -d {prompt:生成一个80×40×2mm的安装板四角有直径4.2mm通孔中心有直径20mm通孔左上角有一个10×10×5mm的定位凸台}到我写这篇文章的时候这套服务在我本地已经稳定跑了三个多月中间也给同事的内部小工具提供过接口。它不算什么大工程但“文本到STEP”这个最核心的闭环算是打通了。5. 跑通不代表能用几何校验、单位陷阱与代码生成翻车清单如果你以为上面那段代码能跑起来就万事大吉那后面这些坑迟早会找上你。我用三个月的时间把这些坑基本踩了一遍下面按“危害程度”排序。5.1 单位混乱看起来微小翻车最狠这是我一上来就栽的坑。提示词里写“直径20mm”模型可能生成circle(20)在CadQuery里hole(20)确实代表直径20但circle(20)在某些语境下代表半径20。更常见的是模型会把“2毫米”理解成2英寸生成一个接近51毫米的厚板你光看渲染图根本看不出比例问题只有量包围盒时才发现差了25.4倍。我建议在提示词第1条强制固定“单位一律是毫米”然后在后端校验里加一句对包围盒的数值范围做合理性检查。比如你要求最大尺寸在100毫米以内生成结果超过1000毫米直接判定为失败。单位错误是结构性错误不是改个参数就能蒙混过关的。5.2 布尔运算和拓扑自交CAD内核帮你兜底但有限CadQuery底层是OpenCASCADE内核布尔运算比大多数网格软件可靠得多。但你拿到的需求经常不像它想的那么简单一个典型的失败案例是模型在同一个面上连续执行多次cutBlind切的深度公差稍微不对结果生成了自相交面或者非流形边。流形是三维模型能被制造的基础要求非流形模型在切片软件里就是一出戏。我的经验是让LLM尽量用hole()而不是手动cut再rect。hole()在CadQuery里会自动沿着法向打通处理厚板的时候特别省心。只要提示词里定义了“主体建好后再统一打孔”的特征顺序就能避开一大批自相交问题。5.3 生成代码的“优雅无效输出”问题这是最磨人的一种失败模型输出的代码语法完全正确也能跑通但生成出来的不是你想要的东西。比如“四个角各打一个孔”被理解成“在四个角各加一根柱子”“中心开孔”被理解成“中心画个圆不切除”。CadQuery的:faces(Z).workplane().circle(20)画出来的只是一个线框圆不cut也不hole模型看代码觉得没问题但导出STL之后你才发现多了一根线。根治方案只有一个加一个语义检查的中间层。我目前的做法是让模型输出JSON格式的“特征清单”里面有特征类型、位置、尺寸后端先校验这个清单是否符合需求再执行代码。如果你的量没有大到要写完整校验器那至少让提示词要求“每个hole旁边注明直径每个box旁边注明长宽高”人工拿到STEP后还能快速对照。5.4 输出质量的自动检查体积、包围盒与特征数我批量跑模型时把自动检查做成了强制门槛。每次生成结束后后端至少要做三件事用BoundingBox()量包围盒和需求尺寸做比例比较误差超过5%直接标红。用val().Volume()算体积和理论体积做对比。比如一个80×40×2的板理论体积是6400立方毫米加上孔洞和凸台会有偏差但偏差范围应该在一个量级以内。检查特征数量比如需求里写了4个孔就在代码里数hole出现的次数不一致就拒绝。这三关都过了模型才会进到导出环节。批量生成几百个零件时这种自动检查能挡住80%以上的低级错误。5.5 需求描述里的隐性冲突怎么处理文字需求经常自带冲突比如“板宽40毫米但四角孔之间距离要60毫米”这种需求物理上就不成立。一开始我让LLM直接忽略矛盾后来发现不行——它可能悄悄把板宽改成60你自己没发现到装配阶段就出大问题。现在我的提示词明确要求遇到冲突必须修改需求而是在代码第一行写注释说明。后端看到注释就会在返回结果里挂一个warning由流程上游的人做决策。这个细节的价值是让每一个错误都可追溯。几分钟的“试探性建模”不怕错怕的是错了你不知道错在哪。6. 三个月的实际工作流变化以及这个方向真正卡住的地方跑了三个月text-to-cad之后我最大的变化是工作效率和心态。以前接到一个“带孔安装板加定位凸台”这种需求我要打开CAD软件、建基准面、画草图、加约束、拉伸切除现在只需要复制需求、粘贴到接口、等几秒钟拿到STEP文件进FastCAD再精修。省下来的时间不是用来摸鱼而是用来做结构布局方案的对比——同一个安装空间斜着放支架和横着放支架散热和走线完全不一样我现在有精力把这类问题想得更细。6.1 从玩具到草稿生成器我给它重新定位了很多人把text-to-cad当“自动化设计工具”觉得生成完就能直接投到车间。我三个月用下来更愿意叫它“草稿生成器”。它负责在你脑子里还没有完整几何的时候先把一个看得见摸得着的实体摆到屏幕上。这个草稿带了尺寸、带了特征树、带了解释你改起参数来也方便。比如我最近做一个设备外壳的安装接口板客户提了一堆关于开孔位置的要求我先把文字丢给text-to-cad生成了三版方案分别对应不同的走线方向。每个方案都是一个完整的STEP文件导进FreeCAD里测了一下螺丝干涉最后选出最合适的一版继续细化。这在以前是不可能的以前我只会因为嫌麻烦而只做一版“看起来差不多”的方案。6.2 目前真正卡住的三个问题瓶颈一装配体与约束语义。单个零件没问题但你说“让这根轴和那个轴承座装配轴端留2毫米间隙”模型就抓瞎了。它连“装配”这个动作要转换成什么代码都不知道。瓶颈二自由曲面和高级造型。text-to-cad目前能做的事情基本集中在平面、拉伸、旋转、打孔、倒角对A级曲面、样条曲面、自由造型束手无策。别指望它给你生成一个鼠标外壳或者汽车翼子板。瓶颈三生成结果的可逆修正。“孔往右移3毫米”人类设计师改一个标注就完成了text-to-cad得重新生成一次而且重新生成可能把之前正确的特征一起改歪。解决这个问题需要引入“编辑意图”的概念让模型基于已有代码做增量修改而不是从零写一遍。6.3 基于这个思路下一步可以怎么扩展如果你也被text-to-cad勾起了兴趣我建议从两条线往下走。一条是往“领域模板”方向走把你所在行业最常见的二十种零件特征做成模板库让提示词直接引用模板名而不是每次描述全部几何细节。另一条是往“参数化批量生成”方向走用一段JSON定义一批零部件的参数循环调用接口把生成结果自动归档成带编号的零件库。这两件事我都已经在做了效果比通用提示词好很多。我现在的体会是text-to-cad最有价值的地方不是省掉了建模这个操作而是省掉了把口头需求转译成几何语义的这个过程。它未必能帮你设计出一个惊世骇俗的产品但它能帮你把一万个重复的“换个尺寸再来一次”变得不那么反人类。如果你也恰好被这类重复劳动折磨过不妨照着上面这套链路先搭一个最简陋的版本跑几个零件试试。第一批结果大概率粗糙但你会发现从“说清楚”到“看到模型”之间的距离从来没有这么短过。
返回列表