news 2026/10/20 21:19:09

text-to-cad实战:用自然语言和代码生成三维模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
text-to-cad实战:用自然语言和代码生成三维模型

1. 从一句话到三维模型:text-to-cad 到底在解决什么问题

第一次听到 text-to-cad 这个词,我的反应是:这不就是把“用嘴画图”这件事往前推了一大步吗。传统建模流程里,不管是做机械零件、建筑构件还是简单的产品外壳,你都得先打开软件,然后一根线一根线地画草图、拉伸、倒角、打孔。一个熟练的工程师画一个带孔法兰盘可能只要五分钟,但一个不会建模的人,哪怕脑子里已经把形状想得很清楚了,面对那些密密麻麻的工具栏还是会直接懵掉。text-to-cad 要干的事情,就是把这层操作门槛直接抹掉——你用自然语言描述你想要的东西,系统帮你生成对应的三维模型文件。

这个方向最近热度上来的原因其实很实在。大语言模型对文本的理解能力已经足够强了,强到可以把“一个边长 50 毫米、中心有个直径 10 毫米通孔的立方体”这种描述拆解成结构化的参数。而另一边,CAD 领域本身有一套非常成熟的参数化建模逻辑,像 OpenSCAD、CadQuery 这类基于代码的建模工具,天生就适合被程序调用。两边一对接,text-to-cad 的雏形就出来了。它解决的核心问题不是“让设计师失业”,而是让那些有想法但不具备建模技能的人,能够快速把脑子里的东西变成一个可以看、可以改、可以导出的三维文件。

适合关注这个方向的人其实比想象中多。做硬件创业的,早期需要快速验证外观和结构,不可能每个想法都找结构工程师画一遍;做教育或者科普的,想让学生直观理解几何关系,用文字生成模型比手把手教软件快得多;还有一类是做自动化脚本的开发者,他们需要批量生成一些标准件模型,比如不同尺寸的螺丝、垫片、支架,用 text-to-cad 的思路可以写个循环直接批量出图。我自己最开始接触这个方向,就是因为要做一个模拟项目,需要生成几十个不同规格的简单零件模型,手动画实在受不了,才想着能不能用代码加自然语言的方式来解决。

需要提前说清楚的是,text-to-cad 目前的能力边界还比较清晰。它擅长的是那些可以用参数和简单几何操作描述清楚的模型,比如方块、圆柱、孔、槽、倒角这些。你要是让它生成一个复杂的曲面汽车外壳或者带精细纹理的艺术品,那基本不现实。所以这篇文章讨论的范围,也集中在参数化、规则化的三维模型生成上,这也是目前最实用、最容易落地的场景。

2. 整体设计思路:为什么是“文本解析 + 代码建模”这条路线

2.1 核心架构的选型逻辑

把 text-to-cad 拆开来看,它本质上是一条流水线:输入是自然语言,输出是三维模型文件,中间需要经过“理解”和“执行”两个大阶段。理解阶段负责把一句话变成结构化的建模指令,执行阶段负责把指令变成实际的几何体。这两个阶段的技术选型,直接决定了整个系统好不好用、稳不稳定。

我试过几种不同的组合方式,最后发现最靠谱的还是“大语言模型解析 + 代码化建模工具执行”这条路线。为什么不用端到端的深度学习直接生成模型呢?因为那样生成的结果不可控,你没法保证它生成的孔真的在中心,也没法保证尺寸真的按你要求的来。而用代码建模工具,比如 OpenSCAD 或者 CadQuery,每一个几何操作都是确定性的,你给它参数,它就给你精确的结果。大语言模型在这里的角色更像一个翻译官,把人类模糊的语言翻译成精确的代码,而不是直接去画图。

这个选型还有一个好处是调试方便。如果生成的模型不对,你可以直接看中间生成的代码,一眼就能看出是哪个参数理解错了,还是哪个操作顺序有问题。端到端模型你只能看到最终结果不对,但不知道错在哪,改都没法改。对于实际项目来说,可调试性比炫技重要得多。

2.2 为什么选择代码化建模而不是直接操作 CAD 软件

有人可能会想,为什么不直接让程序去操作 SolidWorks 或者 AutoCAD 的界面呢?技术上不是不行,但稳定性太差。图形界面软件本来就不是为程序自动化设计的,你模拟鼠标点击、菜单选择,稍微换个版本或者换个分辨率就可能失效。而且这类软件通常很重,启动一次就要几十秒,批量生成的时候效率极低。

代码化建模工具就轻量多了。OpenSCAD 本身就是一个命令行工具,给它一个脚本文件,它几秒钟就能输出一个 STL 或者 DXF 文件。CadQuery 基于 Python,可以直接在脚本里做循环、条件判断,生成参数化模型特别方便。这些工具的设计初衷就是“用代码描述几何”,和 text-to-cad 的需求天然匹配。我实测下来,用 OpenSCAD 生成一个中等复杂度的零件,从解析文本到输出文件,整个流程可以控制在一分钟以内,这个速度对于交互式使用来说已经足够了。

2.3 文本解析层的设计要点

文本解析是整个流程里最不确定的一环,因为自然语言本身就有歧义。用户说“一个圆盘”,直径是多少?厚度是多少?中间有没有孔?这些信息如果缺失,系统就得做合理的默认假设,或者主动追问。我的做法是在解析层设计一套“参数槽位”机制,把常见的建模要素提前定义好,比如形状类型、尺寸参数、位置关系、布尔操作等。大语言模型的任务就是把这些槽位填上,填不上的就用默认值。

举个例子,用户输入“一个直径 80 毫米、厚度 5 毫米的圆盘,中心有个直径 20 毫米的孔”。解析层会输出类似这样的结构化数据:形状是圆柱,外径 80,高度 5,中心有一个圆柱形孔,孔径 20,贯穿。这个结构化数据再交给代码生成层,转换成 OpenSCAD 的 difference 操作。整个过程里,大语言模型不需要知道 OpenSCAD 的语法,它只需要把参数提取出来就行。这样做的好处是,即使以后换一个建模工具,解析层的逻辑不用大改,只需要换代码生成层的模板。

注意:解析层一定要做参数校验。用户可能说“直径 80 毫米的孔”,但忘了说圆盘多大,这时候如果直接生成,孔可能比圆盘还大。我的做法是加一层合理性检查,比如孔的外径不能超过圆盘外径的 80%,厚度不能为负数等等。这些检查规则看起来简单,但能挡掉大部分低级错误。

3. 核心细节拆解:从一句话到可用的三维模型

3.1 自然语言到结构化参数的映射规则

这一步是整个系统里最需要打磨的地方。大语言模型虽然聪明,但如果不给它明确的指令,它输出的格式会非常随意。今天给你返回 JSON,明天给你返回一段描述性文字,后天可能直接给你一段 Python 代码。所以必须用严格的提示词来约束它的输出格式。

我的做法是定义一个固定的 JSON Schema,里面包含几个核心字段:shape_type(形状类型,比如 box、cylinder、sphere)、dimensions(尺寸参数,用键值对表示)、operations(布尔操作列表,比如 difference、union)、position(位置偏移)。然后给大语言模型几个示例,让它照着格式输出。实测下来,只要示例给得够清楚,模型输出的稳定性可以做到 95% 以上。

这里有个细节值得展开说:尺寸参数的单位处理。用户可能说“5 厘米”,也可能说“50 毫米”,还可能说“大概两寸”。前两种可以直接换算成统一的毫米单位,最后一种就需要做模糊匹配。我的处理方式是维护一个常用单位的换算表,遇到“寸”这种模糊单位,默认按英寸处理,同时在返回结果里标注“单位已按英寸换算,如有偏差请手动调整”。这样既保证了自动化,又给了用户修正的机会。

3.2 代码生成层的模板设计

结构化参数拿到之后,下一步就是生成实际的建模代码。这一步的核心是模板。以 OpenSCAD 为例,一个带孔圆盘的模板大概长这样:

difference() { cylinder(h = {height}, d = {outer_diameter}, center = true); cylinder(h = {height} + 2, d = {hole_diameter}, center = true); }

模板里的{height}、{outer_diameter}这些占位符,会被解析层输出的实际数值替换掉。这样做的好处是,代码生成逻辑和具体的几何操作是分离的。你要加一个新的形状类型,只需要写一个新的模板,不用改解析层的逻辑。

模板设计有几个经验性的原则。第一,所有尺寸参数都要有默认值,防止某个参数缺失导致代码报错。第二,布尔操作的顺序要固定,比如先做 union 再做 difference,避免因为顺序不同导致结果不一致。第三,生成的代码里要加注释,标明每个参数对应的是用户描述里的哪一部分,方便后续排查问题。

3.3 参数计算与单位换算的实操细节

单位换算是很多人容易忽略但实际很关键的一步。我踩过的坑是:用户说“一个 2 英寸的立方体”,解析层直接提取了数字 2,但忘了单位是英寸,结果生成了一个 2 毫米的立方体,小了 25 倍多。后来我在解析层加了一个单位识别模块,专门处理这类问题。

具体的换算逻辑是这样的:首先识别用户输入里的单位词,常见的包括毫米、厘米、米、英寸、英尺。然后根据单位词确定换算系数,比如 1 英寸等于 25.4 毫米,1 厘米等于 10 毫米。最后把所有尺寸统一换算成毫米,再传给代码生成层。如果用户没有明确说单位,默认按毫米处理,同时在输出结果里提示“未检测到单位,已按毫米处理”。

还有一个细节是尺寸的合理性检查。比如用户说“一个直径 10 毫米、高度 500 毫米的圆柱”,这个比例明显不正常,更像是一根细杆而不是圆柱。我的做法是加一个长径比检查,如果高度和直径的比值超过 20,就提示用户确认是否输入有误。这个检查不一定会拦住所有错误,但至少能让用户意识到可能有问题。

3.4 输出格式的选择与转换

生成的模型最终要输出成什么格式,取决于用户拿来干什么。如果是要 3D 打印,STL 是最通用的选择。如果是要做进一步的结构分析,可能需要 STEP 或者 IGES 格式。如果只是想在网页上预览,那 OBJ 或者 GLTF 更合适。

我的做法是默认输出 STL,因为它的兼容性最好,几乎所有的 3D 打印切片软件和模型查看器都支持。同时提供一个选项,让用户可以选择输出其他格式。OpenSCAD 本身支持直接导出 STL 和 DXF,如果要输出 STEP,就需要借助 FreeCAD 的命令行工具做一次转换。这个转换过程会稍微慢一点,大概多花十几秒,但对于需要精确几何信息的场景来说是值得的。

提示:STL 文件本质上是一堆三角面片,它不包含参数化信息。也就是说,一旦导出成 STL,你就没法再回去改尺寸了,只能重新生成。所以如果用户可能需要反复调整,建议同时保留生成的脚本文件,方便后续修改。

4. 完整实操流程:从零搭建一个可用的生成管道

4.1 环境准备与工具安装

先说一下我用的工具组合。核心是三个东西:一个能调用大语言模型的接口、OpenSCAD 的命令行版本、以及一个用来串联流程的 Python 脚本。大语言模型我用的是通用的文本生成接口,不绑定特定厂商,这样换起来方便。OpenSCAD 直接从官网下载安装包,安装完之后把可执行文件路径加到系统环境变量里,这样在命令行里直接敲openscad就能调用。

Python 环境需要装几个库:requests用来调接口,json用来处理结构化数据,subprocess用来调用 OpenSCAD 命令行。如果你用的是 CadQuery 路线,那就需要额外装 CadQuery 库,它依赖比较多,建议用 conda 来管理环境,省得折腾依赖冲突。

安装完成之后,先做个简单的验证。在命令行里执行openscad --version,如果能正常输出版本号,说明环境没问题。然后写一个最简单的 OpenSCAD 脚本,比如就一个立方体,用命令行跑一下,确认能生成 STL 文件。这一步看起来简单,但能挡掉很多环境配置的问题。

4.2 解析层的实现与调试

解析层的代码结构大概是这样:先定义一个提示词模板,把用户输入和输出格式要求拼在一起,发给大语言模型。然后接收返回的 JSON,做一轮格式校验和参数补全。最后输出一个标准化的参数字典。

提示词的设计很关键。我试过几种不同的写法,最后发现最有效的是“角色设定 + 任务描述 + 输出格式 + 示例”这个结构。角色设定让模型知道自己是一个 CAD 参数解析器,任务描述告诉它要提取哪些信息,输出格式用 JSON Schema 来约束,示例给两三个覆盖不同形状类型的案例。这样写下来,模型输出的稳定性明显提高。

调试的时候,我建议先把解析层单独跑通,不要急着接代码生成。找十几个不同复杂度的描述,从最简单的“一个立方体”到稍微复杂的“一个带四个安装孔的矩形板”,逐个测试解析结果。把解析出来的参数和你的预期做对比,看看哪里理解错了,然后针对性地调整提示词。这个过程可能要反复几轮,但磨刀不误砍柴工,解析层稳了,后面的流程才靠谱。

4.3 代码生成与模型输出的完整链路

解析层输出参数字典之后,代码生成层的工作就相对机械了。根据shape_type找到对应的模板,把参数填进去,生成 OpenSCAD 脚本。然后调用命令行执行这个脚本,输出 STL 文件。

这里有个实操细节:OpenSCAD 的命令行调用格式是openscad -o output.stl input.scad。-o指定输出文件,后面跟输入脚本。如果脚本里有错误,OpenSCAD 会在命令行里输出错误信息,但不会生成文件。所以调用完之后要检查一下输出文件是否存在,不存在就说明生成失败了,需要把错误信息抓出来给用户看。

我一般会在生成脚本之后先做一个语法检查,用openscad -o /dev/null input.scad跑一遍,确认没有语法错误再正式生成。这样能提前发现大部分问题,避免生成到一半失败。整个链路跑通之后,从用户输入到拿到 STL 文件,大概需要 30 秒到 1 分钟,主要时间花在大语言模型的推理上。

4.4 一个完整案例:生成带安装孔的矩形板

拿一个实际例子走一遍完整流程。用户输入:“一块 100 毫米长、60 毫米宽、5 毫米厚的矩形板,四个角各有一个直径 6 毫米的安装孔,孔中心距离板边 10 毫米。”

解析层输出的结构化参数是:形状类型为矩形板,长 100,宽 60,厚 5,操作列表里有一个“打孔”操作,孔的数量是 4,孔径 6,位置是四个角,边距 10。代码生成层拿到这些参数,生成对应的 OpenSCAD 脚本。脚本里先用cube生成矩形板,然后用四个cylinder做差集运算,每个圆柱的位置根据边距计算出来。

这里有个计算细节:孔的中心坐标。矩形板如果以中心为原点,那么四个角的孔中心坐标分别是(50-10, 30-10)、(50-10, -(30-10))、(-(50-10), 30-10)、(-(50-10), -(30-10))。这个计算逻辑要写在代码生成层里,不能指望大语言模型去算,因为它算数容易出错。我的做法是让解析层只输出“边距 10”这个参数,具体的坐标计算由代码生成层的 Python 脚本来完成,这样更可靠。

生成的脚本跑完之后,得到一个 STL 文件。用模型查看器打开,确认尺寸和孔位都对。如果不对,就回去看生成的脚本,检查是哪个参数出了问题。这个排查过程通常很快,因为脚本是透明的,一眼就能看出问题所在。

5. 常见问题与排查技巧实录

5.1 解析结果不准确怎么办

这是最常见的问题。用户说“一个圆柱”,模型可能默认给了一个直径 10、高度 10 的圆柱,但用户心里想的是直径 50、高度 100。这种信息缺失导致的偏差,靠模型自己猜是猜不准的。我的处理方式是加一轮“确认追问”:如果解析结果里有关键参数缺失,就生成一个追问,让用户补充。比如“检测到您没有指定圆柱的直径和高度,请补充这两个参数,或者回复‘使用默认值’”。

还有一种情况是模型理解错了。用户说“一个带孔的方块”,模型可能理解成方块上有一个圆柱形凸起,而不是一个孔。这种语义歧义需要通过提示词来约束,明确告诉模型“孔”对应的是 difference 操作,不是 union。我试过在提示词里加一句“所有‘孔’、‘洞’、‘开口’都对应布尔差集操作”,效果很明显。

5.2 生成的模型尺寸偏差排查

尺寸偏差通常来自三个地方:单位换算错误、参数提取错误、代码模板错误。排查的时候按这个顺序来:先看解析层输出的参数值对不对,如果参数值就错了,那就是提取或换算的问题;如果参数值对但生成结果不对,那就是模板的问题。

单位换算错误我遇到过一次,用户说“2 米长的杆”,解析层提取了数字 2,但单位识别模块没认出“米”,结果按默认的毫米处理,生成了一个 2 毫米的杆。后来我在单位识别模块里加了一个常见单位列表,并且做了大小写不敏感匹配,这个问题就再没出现过。

代码模板错误相对少见,但一旦出现就比较隐蔽。比如模板里的圆柱高度忘了加center = true,导致圆柱的底面在原点而不是中心在原点,打孔的位置就会偏。这种问题只能靠仔细检查模板来解决,建议每写一个新模板都先用简单参数跑一遍,确认几何关系正确。

5.3 复杂形状生成失败的应对策略

复杂形状失败的原因通常是操作步骤太多,或者布尔运算的顺序有问题。比如用户要一个“带倒角的方块,上面有一个沉头孔”,这涉及倒角、打孔、沉头三个操作,顺序错了结果就不对。我的做法是把复杂形状拆成多个简单步骤,每一步生成一个中间模型,最后再做合并。这样即使某一步失败,也能快速定位问题。

另一个策略是限制单次生成的复杂度。如果解析层检测到操作步骤超过五个,就提示用户“当前描述较为复杂,建议拆分成多个简单模型分别生成”。这个限制看起来降低了能力,但实际上提高了成功率,用户体验反而更好。

5.4 常见问题速查表

问题现象可能原因排查方法解决方式
模型尺寸明显偏小或偏大单位换算错误检查解析层输出的参数值确认单位识别模块是否正常工作
孔的位置不对坐标计算错误检查代码生成层的坐标计算逻辑修正坐标计算公式
布尔运算结果异常操作顺序错误检查生成的脚本里操作的先后顺序调整模板里的操作顺序
生成失败无输出文件脚本语法错误用openscad -o /dev/null做语法检查根据错误信息修正脚本
解析结果缺少关键参数用户描述不完整对比输入描述和解析输出加追问机制让用户补充

注意:每次修改提示词或模板之后,一定要用一组固定的测试用例回归一遍。我吃过亏,改了一个提示词想让某个案例更准,结果另一个原本正常的案例反而错了。回归测试能帮你发现这种“按下葫芦浮起瓢”的问题。

6. 进阶优化与扩展方向

6.1 提升解析准确率的几个实用技巧

提示词工程是提升准确率最直接的手段。我总结下来有几个技巧比较管用。第一,在提示词里明确列出所有支持的形状类型和操作类型,让模型知道可选范围。第二,给每个参数定义明确的类型和单位,比如“直径:数值,单位毫米”。第三,加一句“如果信息不足,请输出 null 而不是猜测”,这样模型不会瞎编参数。

另一个技巧是少样本学习。在提示词里放三到五个示例,覆盖不同的形状和描述风格。示例不用多,但要有代表性。比如一个简单形状、一个带孔的形状、一个带多个操作形状。实测下来,加了示例之后,解析准确率能从 70% 左右提升到 90% 以上。

6.2 批量生成与参数化模板的结合

text-to-cad 的一个高价值场景是批量生成。比如你需要一百个不同尺寸的法兰盘,手动一个个描述太慢了。这时候可以结合参数化模板,先定义一个法兰盘的模板,然后用一个 CSV 文件列出所有尺寸组合,脚本读取 CSV 自动生成所有模型。这个流程里,自然语言描述只需要用一次,用来生成初始模板,后面的批量生成完全靠参数驱动。

我做过一个模拟项目,需要生成 50 个不同规格的支架。做法是先写一个支架的 OpenSCAD 模板,把长度、宽度、高度、孔径这些做成参数。然后写一个 Python 脚本,循环读取参数列表,每次替换模板里的占位符,调用 OpenSCAD 生成 STL。整个过程不到五分钟,50 个模型全部生成完毕。如果手动画,一个下午都画不完。

6.3 与现有工作流的集成思路

生成的模型最终要融入实际工作流才有价值。如果是做 3D 打印,生成的 STL 可以直接拖进切片软件。如果是做机械设计,可能需要把模型导入到 CAD 软件里做进一步编辑。这时候输出格式的选择就很重要,STEP 格式比 STL 更适合后续编辑,因为它保留了精确的几何信息。

另一个集成思路是把 text-to-cad 做成一个服务,通过接口调用。比如在内部工具里加一个按钮,点击之后弹出输入框,用户输入描述,后台调用生成管道,几秒钟后返回模型文件。这样非技术同事也能用,不需要懂任何建模知识。我试过用简单的 Web 框架搭了一个原型,前端就是一个输入框加一个预览区域,后端跑生成管道,整体体验很流畅。

6.4 当前方案的局限与应对

必须承认,当前这套方案在处理复杂曲面、自由形状、精细纹理方面基本无能为力。它擅长的是规则几何体,对于艺术造型类的需求,还是得靠传统的多边形建模或者雕刻软件。所以定位要清晰:text-to-cad 是效率工具,不是万能工具。它解决的是“快速把简单想法变成模型”的问题,不是“替代专业建模师”的问题。

另一个局限是对模糊描述的处理能力有限。用户说“一个好看的杯子”,这个“好看”没法量化,系统就不知道该怎么生成。我的做法是引导用户把模糊描述转化成具体参数,比如“杯口直径 80 毫米、高度 100 毫米、带手柄”。如果用户坚持用模糊描述,那就只能给一个默认的基础形状,然后让用户手动调整。

我在实际使用中最大的体会是:text-to-cad 的价值不在于完全自动化,而在于把建模的起点从“空白画布”变成了“一个大概正确的初始模型”。哪怕生成的模型只有 70% 符合预期,剩下的 30% 手动修改也比从零开始快得多。这个效率提升对于快速原型验证来说,已经足够有价值了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 3:16:38

PIP-77 深度解析:Supernova——献给 Apache Pulsar 的 Haskell 客户端库

消息队列流处理后端微服务消息路由 【免费下载链接】pulsar Apache Pulsar - distributed pub-sub messaging system 项目地址: https://gitcode.com/gh_mirrors/pu/pulsar 点击查看 免费下载 导读:本文围绕 Apache Pulsar 仓库中的 PIP-77 提案 展开&a…

作者头像 李华
网站建设 2026/10/16 6:33:37

swiftui-ui-patterns - theming

主题化与动态字体 意图 提供清晰、可扩展的主题化方案,使视图代码保持语义化和一致性。 核心模式 使用单个 Theme 对象作为唯一事实来源(颜色、字体、间距)。在应用根节点注入主题,并在视图中通过 Environment(Theme.self) 读取。…

作者头像 李华
网站建设 2026/10/16 11:48:00

利用预计算上下文,更快速、更低成本地开展支持问题调查

作者:来自 Elastic Abhimanyu Anand 预计算上下文使 Elastic 的支持 agent 的输入 tokens 减少了 58%,延迟降低了 40%,通过减少重复检索,提高了支持问题调查的效率。 Agent Builder 现已正式发布(GA)。立即…

作者头像 李华