text-to-cad 实战:从自然语言到 STEP/STL 模型生成链路
发布时间:2026/10/26 7:24:08 锦皓数字建站

1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个说法我脑子里蹦出来的画面是对着屏幕敲一句“给我画一个 80×60×10mm、四角带 M4 沉头孔的安装板”然后 CAD 里就自动出现一个可以继续编辑的实体。这个场景放在五年前基本属于科幻但这两年随着大模型在代码生成和结构化输出上的能力暴涨它已经变成了一个能跑通、能落地、甚至能接进生产流程的东西。先把概念说清楚。text-to-cad 指的是用自然语言描述作为输入自动生成 CAD 模型文件的技术方案。它的输出通常不是某一家 CAD 软件的私有格式而是通用的中间格式最常见的就是STEP、STL、GLB这三种。STEP 是精确的边界表示B-rep格式能被 SolidWorks、中望 CAD、Fusion 360 这类软件直接打开并继续做特征编辑STL 是三角网格主要给 3D 打印切片软件用GLB 是 glTF 的二进制版本主打 Web 端和实时渲染预览。这三个格式基本覆盖了“后续要加工”“后续要打印”“后续要展示”三条主流路径。那它到底解决了什么问题我自己的感受是三个层面。第一是建模门槛。大量非机械专业的人——做硬件的、做机器人的、做创客项目的——他们脑子里有明确的结构需求但不会用草图约束、不会做参数化建模卡在软件操作上。第二是重复劳动。像标准安装板、法兰、支架、外壳这类结构形状高度模式化每次都要手动拉伸打孔纯属浪费时间。第三是快速验证。产品早期讨论时与其用嘴描述“大概是个 L 形、带两个耳朵”不如直接生成一个模型丢进渲染器或者打印出来看比例。适合看这篇内容的人我大致分三类一类是想给自己项目加一个“文字生成模型”能力的开发者你需要知道技术链路怎么搭、格式怎么选一类是机械/硬件工程师你想知道这东西生成的模型能不能直接进你的工作流精度和可编辑性到底行不行还有一类是刚入门 CAD 的学习者你可以借这个思路理解参数化建模的底层逻辑反而比死记命令更快。需要提前打个预防针text-to-cad 目前不是“一句话生成任意复杂装配体”的魔法。它对结构清晰、参数明确、以规则几何为主的零件效果最好对自由曲面、有机形态、复杂装配约束仍然力不从心。理解它的能力边界比盲目吹捧或者一棒子打死都重要。2. 整体方案设计与技术选型思路2.1 为什么主流方案都绕不开“代码化建模”要理解 text-to-cad 的实现先得接受一个前提大模型不擅长直接输出三维几何但它非常擅长输出代码。三维几何的本质是一堆坐标、向量、拓扑关系让模型直接吐这些数据格式稍微复杂一点就会错漏百出。但如果让模型输出一段“建模脚本”由脚本去驱动几何内核生成模型成功率会高出一个量级。这就是为什么现在绝大多数 text-to-cad 方案底层都依赖代码化建模Code CAD。代表性的工具有 OpenSCAD、CadQuery、build123d以及基于它们封装的几何内核。它们的共同点是你用代码描述“画一个长方体、在顶面打四个孔、做圆角”代码执行后得到精确的实体模型再导出成 STEP 或 STL。我拿 CadQuery 举个例子它的语法接近 Python可读性很好import cadquery as cq result ( cq.Workplane(XY) .box(80, 60, 10) # 底板 80x60x10 .faces(Z).workplane() .rect(60, 40, forConstructionTrue) .vertices() .hole(4.5) # 四角打直径 4.5mm 通孔 .edges(|Z).fillet(2) # 竖直边倒 R2 圆角 ) cq.exporters.export(result, mount_plate.step) cq.exporters.export(result, mount_plate.stl)这段代码干的事情用自然语言描述就是“一块 80×60×10 的板四角打 M4 通孔竖边倒 R2 圆角”。text-to-cad 的核心工作就是把这句话翻译成上面这段代码然后执行、导出。2.2 三种输出格式的取舍逻辑选 STEP、STL 还是 GLB不是随便定的取决于你下游要干什么。我把实际项目里的判断标准整理成一张表格式几何类型典型用途优点局限STEPB-rep 精确实体二次编辑、CNC 加工、装配精度高、可参数化修改文件较大、需要 CAD 软件打开STL三角网格3D 打印、网格仿真通用性极强、切片软件都认无拓扑信息、不可精确编辑GLB三角网格材质Web 预览、AR、渲染体积小、浏览器原生支持精度低、不适合加工我的经验是如果这个模型后续还要改一定优先出 STEP。STL 一旦生成你想把孔位挪 2mm基本等于重做。而 STEP 进 SolidWorks 或者中望 CAD 之后特征树虽然不一定完整但至少面、边、圆角都是精确的可以继续做布尔运算和尺寸修改。GLB 则纯粹是给“看一眼”用的比如嵌到网页里让客户旋转查看别指望拿它去加工。2.3 大模型在链路里的角色定位很多人误以为 text-to-cad 是“大模型直接生成模型”其实更准确的描述是大模型负责语义理解和代码生成几何内核负责真正的建模计算。这个分工非常关键它决定了系统的稳定性和可控性。大模型这一层要做的事情包括解析用户描述里的尺寸、特征、约束关系判断该用哪种建模原语拉伸、旋转、扫掠、布尔生成符合目标库语法的代码必要时做单位换算和参数校验。几何内核这一层则是确定性的同样的代码永远得到同样的模型不会“幻觉”。这种架构的好处是可验证、可调试。如果生成的模型不对你可以直接看代码哪一行写错了而不是面对一个黑盒干瞪眼。我在实际调试时经常是先把模型生成的代码打印出来人工扫一眼就能定位问题效率比纯端到端方案高太多。提示如果你的项目对精度有硬性要求务必在代码生成后加一道“参数校验”环节比如检查所有尺寸是否为正数、孔径是否小于板厚、圆角半径是否超过相邻边长度的一半。这些校验能挡掉相当一部分几何非法导致的建模失败。3. 核心细节解析与实操要点3.1 自然语言到建模参数的映射规则text-to-cad 最容易翻车的地方就是自然语言里的模糊表达。用户说“打几个孔”到底是几个“稍微倒个角”倒多大所以一套靠谱的系统必须在提示词层面就约定好参数提取规则。我在设计提示词时通常要求模型按固定结构输出比如先输出一个 JSON 描述再输出代码{ shape: rectangular_plate, dimensions: {length: 80, width: 60, thickness: 10, unit: mm}, features: [ {type: hole, diameter: 4.5, count: 4, position: corners, inset: 8}, {type: fillet, radius: 2, target: vertical_edges} ] }这样做的好处是结构化的中间表示可以被程序校验。比如 count 是 4、position 是 corners程序就能算出四个孔的具体坐标而不是让模型自己去猜。我试过直接让模型出代码出错率明显高于“先出 JSON 再出代码”的两段式方案。多一步稳很多。关于单位这是个高频坑。国内工程语境默认毫米但英文描述里 inch 也很常见。我的做法是在系统提示里强制声明默认单位为毫米并要求用户显式写单位时才做换算。曾经有个案例用户说“3 英寸的板”模型没换算直接按 3mm 生成了结果模型小了 25 倍这种错误在预览阶段很难肉眼发现。3.2 几何内核的选择与踩坑记录几何内核这块开源方案里 CadQuery基于 OCCT和 OpenSCAD 是两大主流。我两个都用过说说真实感受。OpenSCAD 的优势是语法极简、学习成本低它的 CSG构造实体几何思路很直观就是不断做加法和减法。但它的短板也明显不支持真正的圆角、倒角操作只能靠 minkowski 之类的技巧模拟效果和性能都一般。而且它导出的 STEP 质量不如 OCCT 系。CadQuery 基于 OpenCASCADEOCCT这是工业级的几何内核圆角、倒角、扫掠、放样这些操作都是原生支持导出的 STEP 质量很高能直接被主流 CAD 软件识别。代价是依赖较重部署时 OCCT 的库文件不小Docker 镜像动辄几个 G。我踩过的一个坑是圆角失败。CadQuery 里对一个边做 fillet如果这个边的相邻面夹角太小或者圆角半径超过了相邻面的尺寸内核会直接抛异常。解决办法是加 try-except失败时降级为不倒角或者自动把半径缩小到安全值。这个逻辑必须写进生成流程里否则用户一句“倒个圆角”就可能让整个任务崩掉。还有一个坑是孔位与边距的冲突。用户说“四角打孔”如果 inset 设得比孔径还小孔就会切到板边生成一个破口的模型。我的处理方式是自动校验inset 必须大于孔径的一半加一个安全余量不满足就自动调整并给出提示。3.3 提示词工程里的几个关键约束写 text-to-cad 的系统提示词和写普通对话提示词完全不是一个思路。普通对话追求自然流畅这里追求的是确定性、可解析、可执行。我总结了几个必须写进提示词的硬约束。第一禁止模型自由发挥。必须明确告诉它“只使用我提供的建模原语不要引入未定义的函数”。否则模型可能生成一段看起来合理、但调用了不存在 API 的代码执行直接报错。第二强制输出可执行代码块。要求代码不带任何解释性文字直接能被 exec 或者子进程执行。我一般会约定用 python 包裹方便程序提取。第三尺寸必须显式。不允许出现“适当大小”“合理厚度”这类词所有数值必须来自用户输入或者明确的默认值。默认值我会在提示词里列一张表比如板厚默认 5mm、孔径默认 4mm、圆角默认 1mm。第四要求模型自检。让它在生成代码后自己检查一遍“所有尺寸是否为正、孔是否在板内、圆角是否合法”把检查结果作为注释附在代码后面。这个自检步骤能过滤掉一部分低级错误实测有效。注意提示词里千万不要写“尽量”“大概”“如果可能”这类模糊词模型会把它理解成可以偷懒的信号。所有约束都要用“必须”“禁止”“只能”这种强语气。4. 完整实操流程与关键环节实现4.1 环境搭建从零跑通一条生成链路我把整套流程拆成可复现的步骤你照着做基本能跑通一个最小可用版本。环境用 Python 3.10 以上核心依赖是 CadQuery 和大模型的 API 客户端。# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装核心依赖 pip install cadquery pip install openai # 或其他兼容接口的客户端 pip install trimesh # 用于 STL/GLB 处理CadQuery 的安装在不同平台上体验差异较大。Linux 上一般很顺Windows 上偶尔会遇到 OCCT 相关的编译问题建议直接用 conda 安装省心很多conda install -c conda-forge cadquery装完之后跑一句import cadquery不报错环境就算通了。这一步看着简单但我见过不少人卡在依赖冲突上尤其是机器上已经装了多个 Python 版本的情况。强烈建议用干净的虚拟环境别在系统 Python 里折腾。4.2 生成流程的四个阶段拆解整套 text-to-cad 流程我习惯拆成四个阶段每个阶段职责清晰方便单独调试。第一阶段语义解析。把用户输入的自然语言通过大模型转成结构化 JSON。这一步的提示词要包含建模原语清单和参数默认值表。输出后做一次 JSON 合法性校验解析失败就重试最多三次。第二阶段代码生成。拿着 JSON再让模型生成 CadQuery 代码。这一步可以给模型几个 few-shot 示例让它模仿格式。代码生成后先做静态检查比如用ast.parse确认语法正确再检查是否只调用了白名单里的 API。第三阶段执行与导出。在沙箱环境里执行代码生成模型对象然后分别导出 STEP、STL、GLB。执行要设超时比如 30 秒防止死循环或者复杂几何卡死。导出路径按任务 ID 组织方便后续查找。第四阶段校验与反馈。检查导出文件是否存在、体积是否合理比如 STEP 小于 50MB、STL 小于 100MB必要时用 trimesh 加载 STL 确认网格有效。任何一步失败都要把错误信息回传给用户而不是静默失败。import subprocess, json, os def run_generation(user_input, task_id): # 阶段一语义解析 spec llm_parse(user_input) # 阶段二代码生成 code llm_generate_code(spec) # 阶段三执行导出 script_path f/tmp/{task_id}.py with open(script_path, w) as f: f.write(code) result subprocess.run( [python, script_path], capture_outputTrue, textTrue, timeout30 ) if result.returncode ! 0: return {status: failed, error: result.stderr} # 阶段四校验 outputs {} for fmt in [step, stl, glb]: path f/tmp/{task_id}.{fmt} if os.path.exists(path): outputs[fmt] os.path.getsize(path) return {status: ok, files: outputs}这段代码是骨架实际项目里还要加日志、重试、并发控制。但核心逻辑就是这么直白解析、生成、执行、校验四步走。4.3 参数计算一个真实零件的完整推导光说流程太虚我拿一个真实需求走一遍。用户输入是“做一个 100×80×6 的底板四角打 M5 沉头孔孔中心距边 10mm竖边倒 R3 圆角。”先做参数提取。M5 沉头孔标准沉头直径约 10mm通孔直径 5.5mm沉头深度约 2.5mm具体看标准这里取常见值。孔中心距边 10mm意味着孔中心坐标是 (10, 10)、(90, 10)、(10, 70)、(90, 70)。校验一下孔径 5.5mm半径 2.75mm孔中心距边 10mm边距远大于半径安全。沉头直径 10mm半径 5mm同样小于 10mm 边距安全。圆角 R3板厚 6mm竖边高度 6mmR3 小于板厚一半安全。所有参数校验通过可以生成。对应的 CadQuery 代码大致是这样import cadquery as cq L, W, T 100, 80, 6 hole_d, csk_d, csk_depth 5.5, 10, 2.5 inset, fillet_r 10, 3 result cq.Workplane(XY).box(L, W, T) # 四角沉头孔 positions [ (-L/2 inset, -W/2 inset), ( L/2 - inset, -W/2 inset), (-L/2 inset, W/2 - inset), ( L/2 - inset, W/2 - inset), ] for x, y in positions: result ( result.faces(Z).workplane() .center(x, y) .cboreHole(hole_d, csk_d, csk_depth) ) # 竖边倒圆角 result result.edges(|Z).fillet(fillet_r) cq.exporters.export(result, base_plate.step) cq.exporters.export(result, base_plate.stl)这里用cboreHole而不是hole因为沉头孔需要两个直径参数。edges(|Z)是选择所有平行于 Z 轴的边也就是四条竖边。这套选择器语法是 CadQuery 的精髓用熟了效率极高。4.4 导出环节的格式细节处理导出这一步看着简单其实有不少细节。STEP 导出时CadQuery 默认用的是 AP214 协议兼容性最好。如果你需要带颜色或者装配信息可以指定其他协议但一般加工场景用默认的就够。STL 导出要关注网格精度。默认的线性偏差和角度偏差如果太粗圆孔会变成多边形打印出来手感很差。我一般会显式设置cq.exporters.export( result, base_plate.stl, tolerance0.01, # 线性偏差 0.01mm angularTolerance0.1 # 角度偏差 0.1 弧度 )tolerance 越小网格越密文件越大。0.01mm 对大多数 3D 打印场景足够了再小就是浪费。GLB 导出则需要先把模型转成网格再走 trimesh 或者 pygltflib 处理CadQuery 本身不直接支持 GLB这一步要额外接一个转换环节。提示STL 和 GLB 都是网格格式导出前建议先做一次网格有效性检查确认没有非流形边和翻转法线。trimesh 的is_watertight属性可以快速判断不通过就说明模型有问题别急着往下游送。5. 常见问题与排查技巧实录5.1 生成失败的高频原因速查我把实际项目里遇到过的失败案例整理成一张表方便你对照排查。这些问题覆盖了八成以上的报错场景。现象可能原因排查方向解决方式代码执行报错API 调用不存在检查生成代码的函数名提示词加 API 白名单模型为空布尔运算全减没了检查尺寸是否互相抵消加几何合法性校验圆角失败半径超过相邻面尺寸检查 fillet 半径与板厚关系自动降级或缩小半径孔切到板边inset 小于孔径检查孔位与边距自动调整 insetSTEP 打不开导出协议不兼容换 AP214 协议显式指定协议STL 圆孔变多边形网格精度太粗检查 tolerance调小到 0.01单位错误英寸毫米混淆检查输入单位声明强制默认毫米这张表我建议直接贴到项目文档里新人上手能少走很多弯路。尤其是“模型为空”这个第一次遇到会一脸懵其实就是几个布尔减法把整个实体减没了加个体积检查就能提前发现。5.2 精度与性能的平衡技巧text-to-cad 有个绕不开的矛盾精度越高生成越慢文件越大。STEP 本身是精确几何不存在精度损失但 STL 和 GLB 的网格密度直接决定文件体积和后续处理速度。我的经验值是预览用 GLB 控制在 5MB 以内打印用 STL 控制在 50MB 以内加工用 STEP 不设上限但尽量精简特征。如果模型特别复杂比如带大量孔阵列可以考虑分区域导出或者用实例化减少重复几何。另一个性能点是代码执行时间。CadQuery 做复杂布尔运算时可能很慢尤其是大量圆角叠加。我遇到过一个大阵列模型执行了将近两分钟。解决办法是把圆角操作放到最后统一做而不是每个特征做完就倒角这样内核的计算量会小很多。5.3 让生成结果更可控的三个实战心得第一个心得给模型喂示例比讲道理管用。与其在提示词里长篇大论解释 CadQuery 语法不如直接给两三个完整的输入输出示例。模型模仿能力很强看到示例就知道该输出什么格式。我一般会准备“简单板件”“带孔阵列”“带圆角外壳”三个示例覆盖大部分场景。第二个心得失败重试要带上下文。第一次生成失败后重试时把错误信息一起塞回给模型让它针对性修正。比如“上次执行报错 fillet radius too large请调整”模型往往能自己改对。盲目重试同样的提示词成功率很低。第三个心得保留人工干预入口。再好的自动化也有翻车的时候所以系统一定要允许用户手动修改生成的 JSON 或代码然后重新执行。我在项目里加了一个“编辑参数”的界面用户改完尺寸直接重新生成比重新描述一遍快得多。这个功能看着不起眼实际使用频率非常高。6. 能力边界与后续扩展方向6.1 当前方案的适用边界用了这么久我对 text-to-cad 的能力边界有了比较清醒的认识。它最擅长的是规则几何的单一零件板件、支架、法兰、简单外壳、连接件。这类结构特征明确、参数有限、几何关系简单生成成功率和质量都很高。它不擅长的是自由曲面和复杂装配。比如一个有机形态的产品外壳或者一个包含几十个零件、有运动约束的装配体目前的方案基本无能为力。自由曲面需要 NURBS 建模能力代码化建模在这方面很弱复杂装配则涉及配合关系和运动学远超单次生成的能力范围。还有一个边界是工程语义。用户说“这个孔要能过 M5 螺丝”模型知道要打 5.5mm 的孔但它不知道这个孔需要配合公差、需要标注、需要符合某个标准。这些工程知识目前还得靠人补。所以我的定位一直是text-to-cad 是加速器不是替代品它把重复劳动干掉把工程师解放出来做真正需要判断的部分。6.2 可以继续叠加的几个方向如果你已经把基础链路跑通了有几个方向可以继续往下做价值都不小。方向一参数化模板库。把常见零件类型做成模板用户只需要填参数不用每次重新生成代码。比如“安装板”模板参数就是长宽厚、孔径、孔位、圆角。这样生成速度和稳定性都会大幅提升本质上是把 text-to-cad 和传统参数化建模结合起来。方向二多轮迭代修改。支持用户在已有模型基础上继续用自然语言修改比如“把孔位往内挪 5mm”“厚度加到 8mm”。这需要维护一个模型状态每次修改只更新变化的参数而不是从头生成。实现难度中等但体验提升明显。方向三工程图输出。模型生成后自动投影出三视图和尺寸标注导出成 PDF 或者 DXF。这个对加工场景很实用省去了手动出图的时间。CadQuery 本身有投影功能配合一些标注库可以做出可用的工程图。方向四批量生成与变体管理。一次输入多个参数组合批量生成一系列模型比如不同尺寸的同一款支架。这在产品系列化开发时特别有用配合参数表格可以一键出全套模型。6.3 一个容易被忽略的合规细节最后说一个很多人不注意的点生成模型的版权和标准符合性。如果模型里用到了某个标准件的尺寸比如 ISO 或 GB 的螺栓沉头尺寸要确认这些数据来源可靠。另外如果生成流程里调用了第三方几何库要注意其许可证是否允许你的使用场景。这些细节平时不起眼但真到产品化阶段就是硬门槛。我自己在实际项目里的体会是text-to-cad 这套东西技术链路本身不算特别难难的是把工程细节打磨到位。参数校验、错误处理、格式兼容、精度控制每一项都是琐碎的活但正是这些琐碎决定了它能不能真正用起来。别指望一次生成就完美把重试、校验、人工干预这些环节做扎实它才能从玩具变成工具。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。