ARTICLE DETAIL

资讯详情

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

text-to-cad 实战:从自然语言到参数化 CAD 模型的分层架构与落地

text-to-cad 实战:从自然语言到参数化 CAD 模型的分层架构与落地 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个说法我脑子里蹦出来的画面是对着电脑敲一句“给我画一个 80×60×20 的法兰盘中心开直径 30 的通孔四角各一个 M6 沉头孔”然后软件自己把模型建好、把工程图出好、把 STEP 文件丢给我。这个画面放在五年前基本属于科幻但放到今天它已经是一条能跑通的技术链路了。所谓 text-to-cad本质上是把自然语言描述翻译成参数化 CAD 模型再导出成 STEP、GLB、STL 这类通用格式的过程。它要解决的核心痛点很朴素大量重复性的、结构相似的零件建模工作占用了工程师太多时间而这些工作恰恰是最容易被规则化和自动化的。我身边做机械设计、钣金、建筑构件、甚至做 3D 打印摆件的朋友几乎都有同一个抱怨——真正花在“想结构”上的时间可能只占两成剩下八成都在“把想法敲进 CAD 里”。画草图、约束、拉伸、打孔、倒角、改尺寸、再改尺寸一套流程下来一个简单支架能磨掉半小时。text-to-cad 想干的事就是把这八成里的“机械劳动”压缩掉让人只负责描述意图和校验结果。它适合谁适合经常做系列化零件的人、适合做参数化建模的工程师、适合想批量生成模型的 3D 打印玩家也适合做 CAD 二次开发、想把 AI 能力接进自己工具链的程序员。这里要先泼一盆冷水text-to-cad 不是“说一句话就出成品”的魔法。自然语言天生是模糊的而 CAD 要求的是精确到小数点后几位的几何约束。这两者之间的鸿沟就是整个技术方案要填的坑。所以真正能落地的 text-to-cad几乎都不是“端到端一个大模型直接吐 STEP”而是分层拆解 中间表示 参数化重建的组合拳。下面我就按我自己趟过的路子把整套思路、关键细节、实操过程和踩坑记录完整拆一遍。2. 整体方案怎么搭为什么不能一步到位2.1 端到端生成 CAD 的幻想与现实很多人第一反应是现在大模型这么强直接让它输出 STEP 文件不就行了我试过结论是——能出但基本不能用。原因有三个。第一STEP 是边界表示B-rep格式里面是精确的曲面、边、顶点的拓扑关系而语言模型擅长的是 token 序列它对“这个面和那个面共享一条边”这种拓扑约束没有天然的建模能力。第二语言模型输出的数值经常“看起来对”但公差、配合、壁厚这些工程约束它并不真的理解生成的东西能看不能用。第三就算勉强生成了一旦要改一个尺寸整个模型可能就崩了因为它不是参数化的。所以我的判断是端到端直接生成 B-rep 这条路目前只适合做概念草图或者玩具级模型不适合工程交付。真正靠谱的做法是把自然语言先翻译成一种“结构化的中间表示”再由确定性的几何内核去重建模型。这个中间表示可以是 JSON 描述的参数表也可以是一段脚本比如 CadQuery、OpenSCAD、FreeCAD 的 Python 脚本甚至是一棵特征树。2.2 分层架构语言层、参数层、几何层我最终采用的架构分三层这个分层是我踩了很多坑之后定下来的强烈建议你也按这个思路走。语言层负责把用户那句人话解析成结构化的意图。比如“法兰盘、外径 80、厚 20、中心通孔 30、四角 M6 沉头孔”要能抽出实体类型、尺寸参数、特征列表。这一层用大模型做意图识别和槽位填充最合适。参数层把意图转成一份严格的参数 schema做单位统一、默认值填充、合法性校验。这一层是纯代码逻辑不依赖模型保证可复现。几何层拿参数去驱动几何内核生成实体导出 STEP/GLB/STL。这一层用成熟的内核比如 OpenCASCADE通过 CadQuery 或 pythonocc 调用保证几何质量。这么分的好处是语言层可以换模型、可以调 prompt不影响几何几何层可以换内核、换导出格式不影响语言理解。每一层都能单独测试出问题好定位。这就是为什么我说“不能一步到位”——一步到位意味着你没法调试出了错你都不知道是理解错了还是建模错了。2.3 中间表示选 JSON 还是脚本中间表示我两种都用过说说取舍。JSON 参数表的优点是安全、可控、易校验你可以在参数层写一堆规则比如“孔径必须小于外径”“壁厚不能小于 1mm”不满足就直接拒绝。缺点是表达能力有限遇到复杂特征比如阵列、扫掠、放样描述起来很别扭。脚本比如 CadQuery 的 Python 代码的优点是表达能力强几乎能描述任何几何操作而且本身就是可执行的改一个参数就能重跑。缺点是安全性差——让模型直接生成可执行代码万一它写出个死循环或者乱删文件就麻烦了。我的折中方案是简单零件走 JSON复杂零件走脚本但脚本必须跑在沙箱里并且只允许调用白名单内的建模 API。这样既保证了灵活性又控制了风险。下面实操部分我会以 JSON 路线为主因为它最容易复现也最适合新手起步。3. 核心细节拆解从一句话到一份参数表3.1 意图识别怎么让模型听懂“法兰盘”语言层最关键的一步是意图识别。用户说的话千奇百怪有人会说“画个圆盘”有人会说“做个法兰”有人直接甩一句“DN50 的法兰”。你得让模型把这些都归到同一个实体类型上。我的做法是维护一份实体类型词典每个类型下面挂同义词和必填参数。比如法兰盘这个类型同义词有“法兰、圆盘、盘类件”必填参数有外径、厚度、中心孔径。这里有个经验不要让模型自由发挥实体类型要给它一个封闭的候选列表。我一开始让模型自己判断“这是什么零件”结果它经常发明一些不存在的类型后面几何层根本没法处理。改成“从以下类型中选择最匹配的一个”之后准确率立刻上来了。这就是典型的“约束比自由更可靠”。3.2 槽位填充与单位陷阱槽位填充就是把“外径 80”里的 80 抽出来绑定到“外径”这个参数上。听起来简单但单位是个大坑。用户可能说“外径 80”也可能说“外径 8 公分”还可能说“外径 80mm”。如果你不统一单位后面几何层就会把 8 公分当成 8 毫米模型直接小十倍。我的处理方式是在参数层强制统一到毫米并且在 prompt 里明确要求模型输出时带上单位由代码做换算。换算表很简单1 公分 10 毫米1 米 1000 毫米1 英寸 25.4 毫米。别小看这一步我见过太多项目栽在单位上。还有一个隐蔽的坑默认值。用户说“做个法兰”没给厚度你怎么办我的做法是给每个参数设一个合理的工程默认值比如法兰厚度默认 10mm中心孔默认通孔。但默认值必须在结果里明确标注出来让用户知道“这个数是我替你填的”否则他拿到模型会一脸懵。这一点在交互设计上很重要属于“透明化”原则。3.3 参数合法性校验把错误挡在建模之前参数层最容易被忽视、但价值最高的一环是校验。我列几个我实际写进代码的规则校验项规则不通过的后果尺寸为正所有长度参数 0负尺寸会导致内核报错或生成退化实体孔径小于外径中心孔径 外径 - 2×壁厚否则壁厚为负实体自相交壁厚下限壁厚 ≥ 1mm塑料/ ≥ 0.5mm金属太薄会导致 STL 导出后破面孔位不越界孔中心到边缘距离 ≥ 孔径否则孔会切穿外壁沉头孔匹配沉头直径 通孔直径否则沉头特征无法生成这些规则看着琐碎但每一条都是我用真实失败案例换来的。比如“孔位不越界”这条就是因为我生成过一个四角孔直接切到外圆上的法兰导进切片软件一看模型是破的。把校验做在建模之前比建模之后再去修要省事一百倍。4. 实操过程手把手跑通一条 text-to-cad 链路4.1 环境准备与工具选型先说工具链。几何内核我选OpenCASCADE因为它开源、成熟、对 STEP 支持好。上层封装用CadQuery它把 OpenCASCADE 包了一层 Pythonic 的 API写起来像搭积木非常适合做参数化重建。语言层我用一个通用大模型做意图解析输出 JSON。导出格式方面STEP 用于工程交付STL 用于 3D 打印GLB 用于网页预览三个都从同一个实体导出保证几何一致。安装这块CadQuery 官方推荐用 conda 装因为它的依赖尤其是 OpenCASCADE 的二进制用 pip 装容易出问题。我实测下来conda 环境最稳conda create -n text2cad python3.10 conda activate text2cad conda install -c conda-forge cadquery装完之后跑一句import cadquery as cq; print(cq.__version__)能打印版本号就说明环境通了。这里提醒一句CadQuery 对 Python 版本比较挑3.10 是我验证过最稳的3.12 有时候会碰到依赖冲突。别问我怎么知道的重装了三遍。4.2 语言层把一句话变成 JSON语言层我写了一个函数输入是用户那句话输出是一份 JSON。prompt 的核心是给它一个 schema 模板让它照着填。我简化后的 schema 长这样{ part_type: flange, params: { outer_diameter: {value: 80, unit: mm}, thickness: {value: 20, unit: mm}, center_hole: {value: 30, unit: mm}, bolt_holes: { count: 4, diameter: {value: 6, unit: mm}, circle_diameter: {value: 60, unit: mm}, type: counterbore } } }prompt 里我会明确写“只输出 JSON不要解释单位统一用 mm缺失的参数不要瞎编留空即可。” 实测下来加了“不要瞎编”这句之后模型乱填参数的情况明显减少。这就是 prompt 工程里的“负向约束”有时候比正向描述还管用。4.3 参数层校验、补默认值、算派生量拿到 JSON 之后参数层做三件事。第一单位换算把所有值统一到毫米。第二补默认值比如用户没给沉头深度我按通孔直径的 0.6 倍估算。第三算派生量比如螺栓孔的中心圆半径 中心圆直径 / 2孔位的 x、y 坐标 半径 × cos/sin(角度)。这些派生量不交给模型算全部用代码算因为三角函数这种确定性计算代码比模型可靠得多。这里分享一个计算细节四孔均布时角度间隔是 360/4 90 度起始角我习惯从 45 度开始这样四个孔落在对角线上视觉上更对称。孔位坐标就是import math r circle_diameter / 2 for i in range(count): angle math.radians(45 i * 360 / count) x r * math.cos(angle) y r * math.sin(angle)这段代码简单但它是整个链路里最不该出错的地方因为孔位错了整个零件就废了。所以我给它单独写了单元测试输入已知参数断言输出坐标在预期范围内。4.4 几何层用 CadQuery 重建实体几何层是重头戏。以法兰盘为例CadQuery 的建模逻辑非常直观基本就是“画圆、拉伸、挖孔、阵列”import cadquery as cq result ( cq.Workplane(XY) .circle(outer_diameter / 2) .extrude(thickness) .faces(Z) .workplane() .hole(center_hole) ) # 螺栓孔阵列 result ( result.faces(Z) .workplane() .pushPoints(bolt_positions) .cboreHole(bolt_diameter, cbore_diameter, cbore_depth) ) cq.exporters.export(result, flange.step) cq.exporters.export(result, flange.stl) cq.exporters.export(result, flange.glb)这段代码里cboreHole是沉头孔参数依次是通孔直径、沉头直径、沉头深度。pushPoints接收一个坐标列表把孔打到指定位置。导出三个格式各一行STEP 给下游 CADSTL 给打印GLB 给预览。实测下来一个法兰盘从解析到导出全程不到两秒比手动画快太多了。4.5 导出格式怎么选STEP、GLB、STL 的适用场景这三个格式经常被混用我按实际经验说清楚它们的区别避免你导错格式返工。格式本质适用场景注意事项STEP精确 B-rep工程交付、下游 CAD 编辑、CNC 加工保留精确曲面和拓扑文件较大STL三角网格3D 打印、快速预览只有网格丢失精确曲面精度靠细分控制GLB三角网格 材质网页预览、AR/VR、可视化支持颜色材质适合展示不适合加工我的建议是只要涉及后续编辑或加工一律以 STEP 为准STL 和 GLB 都是从 STEP 派生出来的展示副本。千万别拿 STL 去反推工程图网格转 B-rep 是个逆问题精度损失不可逆。热词里那个“sw 中 stl 转 stp”就是这个痛点转出来的面全是碎三角面根本没法做特征编辑。5. 常见问题与排查技巧实录5.1 模型导出后破面、切片软件报错这是最高频的问题。表现是 STL 导进切片软件后模型显示为破面、有孔洞、或者切片直接失败。原因通常有三个一是壁厚太薄网格细分时相邻面重叠二是实体本身自相交比如孔切穿了外壁三是导出精度设置太低。排查顺序我一般是先看参数校验有没有拦住异常尺寸再把 STL 的线性偏差linear deflection调小CadQuery 里可以这样设cq.exporters.export(result, flange.stl, tolerance0.01, angularTolerance0.1)tolerance是线性偏差越小网格越密默认值有时候偏大。我一般设 0.01mm兼顾精度和文件大小。如果调小之后还是破面那基本就是实体本身有问题回去查参数校验。5.2 单位错乱导致模型尺寸离谱前面提过单位坑这里给个排查技巧在参数层打印一份“归一化后的参数表”每次生成都看一眼。如果发现某个尺寸明显不对比如法兰外径变成 8mm立刻能定位是解析错了还是换算错了。我还会在导出后读一下模型的包围盒尺寸跟预期值比对差太多就报警。这个“包围盒自检”是个很实用的兜底手段几行代码就能加bb result.val().BoundingBox() print(fX: {bb.xlen:.2f}, Y: {bb.ylen:.2f}, Z: {bb.zlen:.2f})5.3 复杂特征描述不清模型生成失败用户说“做个带加强筋的支架”这种描述对模型来说太模糊了。我的处理方式是主动追问而不是硬猜。在参数层发现必填参数缺失或特征描述不完整时返回一个“需要补充信息”的响应列出缺哪些参数。这比生成一个错误模型让用户去改要友好得多。交互设计上这叫“fail fast”快速失败、快速反馈。5.4 常见问题速查表现象可能原因排查动作模型尺寸差十倍单位未统一检查归一化参数表STL 破面壁厚太薄或实体自相交调小 tolerance查参数校验孔位偏移阵列角度算错检查孔位坐标计算逻辑STEP 导入下游软件报错内核版本不兼容换用标准 AP214 协议导出生成速度慢网格细分过密适当放大 tolerance模型无法编辑导出成了 STL改用 STEP 导出5.5 几个我踩过的坑和独家心得第一个坑别用模型算三角函数。我早期偷懒让模型直接输出孔位坐标结果它算的 cos/sin 值精度不够孔位偏了零点几毫米。后来全部改成代码算问题消失。第二个坑prompt 里一定要禁止模型输出注释和解释。它一旦开始“我觉得这个法兰应该……”JSON 就解析失败了。第三个心得给每个实体类型写一个最小可复现样例作为回归测试。每次改 prompt 或改代码先跑一遍样例确认没退化再上线。这个习惯帮我省了无数次返工。6. 这套方案还能怎么扩展跑通基础链路之后我做了几个扩展效果都不错。一个是批量生成把一份 Excel 参数表读进来循环调用整条链路一次生成几百个系列化零件导出 STEP 和 STL。热词里那个“python 批量对 cad 修改”说的就是这个场景只不过传统做法是操作 CAD 的 API而 text-to-cad 是从参数直接重建更干净。另一个扩展是接入预览把 GLB 丢到网页里用 three.js 渲染用户改一个参数就能实时看到模型变化体验比等文件下载好太多。还有一个方向是反向能力给一个已有的 STEP 文件让系统识别出它的参数表然后用户就能用自然语言去改它。这个比从零生成难因为要解析 B-rep 的特征但价值也更大适合做“老图翻新”的场景。我目前只做到简单回转体和拉伸体的识别复杂曲面还在摸索。最后分享一个小技巧把每次生成的参数表和用户原话都存下来攒一段时间就是一份高质量的微调数据集。等你数据够了可以拿它去微调一个专门做意图解析的小模型推理更快、成本更低还不用每次都调大模型。这条路我刚开始走等有结果了再跟大家汇报。
返回列表