text-to-cad 实战:自然语言生成三维 CAD 模型的技术拆解与落地
1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个说法是在一个做机械设计的朋友那里。他当时正对着屏幕上一堆草图发愁嘴里念叨着“要是能直接说一句‘给我画一个 80 毫米见方的法兰盘中间开个 30 毫米通孔四角各一个 M6 螺栓孔’软件就能自己把模型建出来那该省多少事。” 这句话其实就点出了 text-to-cad 的核心把自然语言描述直接转换成计算机辅助设计模型跳过繁琐的手工建模步骤。传统 CAD 建模的流程大家都熟悉——打开软件选基准面画草图标尺寸拉伸切除倒角打孔一套下来少说十几分钟复杂零件几个小时也正常。问题在于很多设计需求在初期就是一句话的事比如“一个长宽高 100×60×40 的盒子壁厚 3 毫米顶部开个 20 毫米的圆孔”。这种需求用自然语言表达极其高效但落到 CAD 软件里就得一步步手动操作。text-to-cad 要做的就是在这两者之间架一座桥。这个方向适合谁来关注三类人最应该了解。第一类是机械、工业设计领域的从业者日常有大量简单重复的建模需求想提升效率。第二类是做产品原型、创客、3D 打印的玩家他们往往没有系统的 CAD 训练但需要快速把想法变成可制造的模型。第三类是对 AI 辅助设计感兴趣的开发者想理解自然语言到结构化几何数据的转换逻辑甚至自己动手搭一套流程。需要先明确一点text-to-cad 不是要取代 CAD 工程师它解决的是“从想法到初版模型”这一段。精细的工程标注、公差配合、装配关系仍然需要人来把关。但初版模型生成这一步恰恰是最耗时、最机械的部分。把它自动化价值就出来了。2. 核心技术拆解自然语言怎么变成三维几何2.1 语言理解层从模糊描述到结构化参数自然语言最大的特点是模糊。“一个差不多 10 厘米的方块”和“边长 100 毫米的正方体”在人看来是一个意思但机器需要把前者归一化成后者。这一步通常依赖大语言模型做语义解析把一句话拆解成结构化的参数表。举个例子输入“设计一个外径 120 毫米、内径 80 毫米、厚度 15 毫米的圆环”。语言模型需要识别出几个关键信息形状是圆环外径 120内径 80厚度 15单位是毫米。输出可能是一个 JSON 结构{ shape: ring, outer_diameter: 120, inner_diameter: 80, thickness: 15, unit: mm }这个 JSON 就是后续几何生成的输入。难点在于用户不会总是这么规范地说话。有人会说“做个垫圈外圈 12 公分内圈 8 公分厚 1.5 厘米”单位混用、口语化表达都需要模型做归一化处理。实际项目中通常会在提示词里加入单位换算规则和常见同义词映射表比如“公分厘米cm”“圆环垫圈ring”。注意单位处理是 text-to-cad 最容易翻车的地方。我见过一个案例用户说“直径 10”模型默认按毫米处理结果生成一个 10 毫米的小零件而用户实际想要的是 10 厘米。后来在提示词里强制要求如果用户没有明确单位必须追问确认不能自行假设。2.2 几何生成层参数化建模与直接建模的取舍拿到结构化参数后下一步是生成三维几何。这里有两条技术路线。第一条是参数化建模也就是用代码调用 CAD 内核的 API按步骤执行建模操作。比如用 Python 的 CadQuery 库写几行代码就能生成一个法兰盘import cadquery as cq result ( cq.Workplane(XY) .circle(60) .circle(40) .extrude(15) .faces(Z) .workplane() .hole(30) )这种方式的优势是模型可编辑、可参数化生成的模型带有特征树后续修改方便。缺点是只能处理预定义好的形状模板遇到复杂自由曲面就力不从心。第二条是直接生成网格模型比如用深度学习模型直接输出 STL 或 OBJ 格式的三角网格。这种方式理论上能生成任意形状但模型没有特征信息修改起来很麻烦而且生成质量不稳定容易出现破面、自交等问题。实际落地时大多数项目采用混合策略常见标准件法兰、齿轮、支架、盒子用参数化模板生成保证质量和可编辑性自由曲面类需求则降级处理或者提示用户当前不支持。这个取舍很现实——与其追求全能但不可靠不如先把高频场景做扎实。2.3 反馈与修正层多轮对话式建模一次生成就完全符合预期的情况很少。用户看到模型后往往会说“孔再大一点”“厚度减半”“加个倒角”。这就要求系统支持多轮对话式修正。实现方式通常是在会话中维护一个参数状态表。第一轮生成后参数表里记录了当前所有尺寸。用户说“孔再大一点”语言模型需要理解这是对哪个参数的修改以及修改的方向和幅度。这里有个坑 “大一点”到底是多大比较稳妥的做法是设定一个默认调整幅度比如每次调整 10%同时给用户反馈“已将孔径从 30 毫米调整为 33 毫米是否合适”{ shape: flange, outer_diameter: 120, inner_diameter: 33, thickness: 15, bolt_holes: 4, bolt_hole_diameter: 6 }这种增量式修改的体验比每次重新描述一遍要自然得多。技术上需要在会话历史中保留完整的参数快照每次修改只更新变化的字段。3. 实操落地从零搭一套可用的 text-to-cad 流程3.1 工具选型与环境准备如果你想自己动手验证 text-to-cad 的可行性不需要从零训练模型。比较务实的方案是用现成的大语言模型做语义解析用 CadQuery 或 OpenSCAD 做几何生成中间用 Python 脚本串联。具体依赖如下组件推荐选择作用语言模型支持结构化输出的通用大模型解析自然语言为 JSON 参数几何内核CadQuery 2.x参数化生成 B-Rep 模型运行环境Python 3.10串联各环节输出格式STEP / STLSTEP 可编辑STL 可打印交互界面命令行或简单 Web 表单输入描述、查看结果安装 CadQuery 用 conda 最省事conda create -n text2cad python3.10 conda activate text2cad conda install -c conda-forge cadquery提示CadQuery 依赖 OCCT 几何内核在 Windows 上直接用 pip 安装容易缺 DLL。用 conda 安装能自动解决依赖问题省去大量排查时间。3.2 提示词设计与参数映射语言模型能不能稳定输出结构化参数关键在提示词。我试过好几版最后稳定下来的模板大致是这样的你是一个 CAD 参数解析器。用户会用自然语言描述一个零件。 你需要输出一个 JSON 对象包含以下字段 - shape: 形状类型可选值有 box, cylinder, ring, flange, plate - dimensions: 一个对象包含该形状所需的尺寸参数单位统一为毫米 - features: 一个数组描述附加特征如孔、倒角、圆角 规则 1. 如果用户没有指定单位默认按毫米处理但在输出中标注 unit_assumed: true 2. 如果描述模糊无法确定具体数值在 ambiguity 字段中列出需要追问的问题 3. 不要输出任何解释性文字只输出 JSON 用户描述设计一个 100×60×40 的盒子壁厚 3 毫米顶部中心开一个直径 20 的孔。模型输出{ shape: box, dimensions: { length: 100, width: 60, height: 40, wall_thickness: 3 }, features: [ { type: hole, position: top_center, diameter: 20 } ], unit_assumed: false, ambiguity: [] }这个 JSON 直接喂给 CadQuery 脚本就能生成模型。实测下来对于标准形状解析准确率能到八成以上。剩下的两成主要是单位混用和位置描述模糊比如“孔开在中间偏左一点”这种就需要追问具体坐标。3.3 几何生成脚本的编写要点拿到 JSON 后生成几何的脚本需要处理几种常见形状。以盒子为例import cadquery as cq import json def build_box(params): dims params[dimensions] length dims[length] width dims[width] height dims[height] wall dims.get(wall_thickness, 0) if wall 0: # 空心盒子外形减去内腔 outer cq.Workplane(XY).box(length, width, height) inner ( cq.Workplane(XY) .box(length - 2*wall, width - 2*wall, height) .translate((0, 0, wall)) ) result outer.cut(inner) else: result cq.Workplane(XY).box(length, width, height) # 处理附加特征 for feat in params.get(features, []): if feat[type] hole and feat[position] top_center: result ( result.faces(Z).workplane() .hole(feat[diameter]) ) return result # 导出 model build_box(json.loads(input_json)) cq.exporters.export(model, output.step) cq.exporters.export(model, output.stl)这段代码有几个细节值得注意。第一空心盒子的内腔需要向上平移一个壁厚的距离否则底面会穿透。第二打孔时选择Z面也就是朝上的那个面确保孔的方向正确。第三同时导出 STEP 和 STLSTEP 用于后续编辑STL 用于 3D 打印。实操心得CadQuery 的hole()方法默认是通孔如果要打盲孔需要用cboreHole()或手动做布尔减运算。我一开始没注意打出来的全是通孔后来查文档才发现这个区别。3.4 多轮修改的状态管理支持多轮修改的关键是维护一个会话状态。每次用户输入新描述时把历史参数和当前输入一起送给语言模型让它输出更新后的完整参数表。class CadSession: def __init__(self): self.params None self.history [] def update(self, user_input): prompt f 当前参数{json.dumps(self.params, ensure_asciiFalse)} 用户新输入{user_input} 请输出更新后的完整参数 JSON只输出 JSON。 new_params call_llm(prompt) self.params json.loads(new_params) self.history.append(user_input) return self.params这样用户说“厚度改成 20”模型会保留其他参数不变只更新厚度字段。实测下来这种增量更新的方式比每次重新解析要稳定得多因为大部分参数保持不变模型只需要关注变化的部分。4. 踩坑记录与常见问题排查4.1 单位与数值的坑前面提过单位问题这里再展开说。除了“公分”和“毫米”混用还有一个隐蔽的坑小数点。用户说“直径 0.5”模型可能理解成 0.5 毫米但用户实际想要的是 0.5 厘米也就是 5 毫米。这种在提示词里很难完全规避比较稳妥的做法是在输出中显式标注单位让用户确认。另一个坑是数值范围。有人输入“直径 1000”如果单位是毫米那就是一米对于大多数桌面级 3D 打印来说太大了。系统可以设置一个合理范围检查超出范围时提示用户确认。问题现象可能原因排查方法模型尺寸明显偏小单位被默认成毫米用户实际用厘米检查输出中的 unit_assumed 字段孔打穿了不该穿的面通孔与盲孔混淆确认 hole() 与 cboreHole() 的使用模型导出后无法打开STEP 文件损坏或内核版本不兼容换用 STL 格式验证或升级 CadQuery多轮修改后参数丢失会话状态未正确合并检查每次更新是否输出完整参数表复杂形状生成失败超出模板支持范围降级提示用户当前不支持该形状4.2 几何有效性问题参数化生成的模型大多数时候是有效的但有些边界情况会出问题。比如壁厚大于盒子宽度的一半内腔就会变成负尺寸布尔运算直接报错。再比如孔径大于法兰盘外径孔会把整个零件吃掉。这类问题需要在生成前做参数校验。我的做法是在脚本里加一层检查def validate(params): dims params[dimensions] if params[shape] box: wall dims.get(wall_thickness, 0) if wall 0 and wall * 2 min(dims[length], dims[width]): raise ValueError(壁厚过大内腔尺寸为负) if params[shape] flange: if dims[inner_diameter] dims[outer_diameter]: raise ValueError(内径不能大于等于外径)校验不通过时返回明确的错误信息给用户而不是让几何内核抛出一堆看不懂的异常。用户体验会好很多。4.3 语言模型的幻觉问题大语言模型有时候会“自作主张”添加用户没说的特征。比如用户只说“一个方块”模型可能输出一个带倒角的方块理由是“倒角更美观”。这在设计场景里是不可接受的因为每个特征都影响加工和装配。解决办法是在提示词里明确禁止添加未指定的特征并且在输出 JSON 中增加一个features数组如果用户没提这个数组必须为空。同时可以在后处理阶段检查如果 features 非空但用户输入中没有任何相关关键词就丢弃这些特征并记录日志。注意不要完全信任语言模型的输出。即使提示词写得很严格仍然会有小概率出现意外字段。在解析 JSON 后加一层 schema 校验只提取你认识的字段忽略多余的。5. 应用场景与扩展方向5.1 快速原型与 3D 打印这是 text-to-cad 最直接的应用场景。做 3D 打印的人经常需要一些简单的功能性零件——支架、垫块、外壳、连接件。这些零件形状规整用自然语言描述非常高效。比如“一个 L 形支架长边 80 毫米短边 50 毫米宽度 20 毫米厚度 5 毫米长边上两个 M4 孔”一句话就能生成可打印的 STL 文件。我实测过整个流程从输入描述到拿到 STL熟练之后不到一分钟。相比打开 CAD 软件手动建模效率提升非常明显。当然前提是零件形状在模板覆盖范围内。5.2 教学与设计沟通在工程制图或机械设计教学中text-to-cad 可以作为一个辅助工具。学生用自然语言描述一个零件系统生成三维模型然后对照模型检查自己的描述是否准确。这个过程反过来训练了学生的空间想象能力和工程语言表达能力。在设计沟通场景中非专业人士可以用自然语言描述需求系统生成初版模型设计师在此基础上修改。减少了“鸡同鸭讲”的沟通成本。5.3 与现有 CAD 工作流的集成text-to-cad 生成的 STEP 文件可以直接导入主流 CAD 软件作为设计起点。参数化生成的特征树在导入后通常会被压缩成一个实体但尺寸和形状是准确的后续可以在上面继续添加特征。更进一步的集成方式是做成 CAD 软件的插件在软件内部调用语言模型和几何生成脚本生成后直接插入当前装配体。不过这需要针对具体 CAD 软件的 API 做开发工作量不小。5.4 当前局限与务实预期必须承认text-to-cad 目前只能处理相对简单的规则形状。自由曲面、复杂装配、工程图标注这些还远远做不到。如果你的需求是“设计一个汽车变速箱壳体”那还是老老实实找工程师。比较务实的预期是它能帮你快速搞定标准件和简单非标件节省下来的时间用在真正需要创造力的地方。把它当成一个高效的草图工具而不是全能的设计师。6. 几个提升成功率的实用技巧第一描述尽量结构化。与其说“做个盒子”不如说“长方体长 100宽 60高 40单位毫米”。信息越完整解析越准确。第二一次只改一个参数。多轮修改时如果一句话里同时改尺寸又加特征模型容易顾此失彼。分开说先改尺寸确认后再加特征。第三善用追问功能。如果系统提示“请确认单位”或“请指定孔的位置”不要嫌麻烦认真回答。这些追问恰恰是保证结果准确的关键。第四保留中间结果。每次生成的 STEP 文件都存下来万一后面改坏了可以回退到之前的版本。我习惯用日期加序号命名比如flange_20250101_v3.step找起来方便。第五不要指望一次完美。把 text-to-cad 当成一个需要调教的助手前几次可能需要多轮对话才能得到想要的结果。用熟了之后描述方式会越来越精准成功率自然就上去了。最后分享一个我常用的调试方法当生成结果不符合预期时先把语言模型输出的 JSON 打印出来看。十有八九是参数解析错了而不是几何生成的问题。定位到具体是哪个字段理解错了下次描述时换个说法就能避开。这个排查思路帮我省了很多时间。