ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

text-to-cad 技术解析:从自然语言到参数化三维模型的工程实践

text-to-cad 技术解析:从自然语言到参数化三维模型的工程实践

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

第一次听到 "text-to-cad" 这个词,很多人脑子里冒出来的画面是:对着电脑说一句"给我画个齿轮",屏幕上就自动长出一个可以加工的三维模型。这个想象方向没错,但真正落地的时候,它解决的问题比"省几下鼠标"要深刻得多。

传统 CAD 建模的流程是这样的:你先在脑子里把零件想清楚,然后打开软件,选基准面、画草图、标尺寸、加约束、拉伸、倒角、打孔、装配。一个中等复杂度的零件,熟练工程师也要折腾一两个小时。问题在于,这个过程中大量的时间花在了"翻译"上——把脑子里的几何意图翻译成软件能理解的草图约束和特征操作。而 text-to-cad 想做的,就是把这层翻译工作交给机器,让工程师用自然语言直接描述设计意图,由系统生成对应的参数化模型或几何体。

它适合谁?我观察下来有三类人最需要:一是做概念设计的产品经理和工业设计师,他们脑子里有想法但未必精通 CAD 操作;二是需要批量生成标准件、变型件的工程师,比如一堆只有孔径和长度不同的支架;三是做仿真、做 AI 训练的数据工程师,他们需要大量带标注的三维模型,手工建模根本喂不饱模型。这三类人的共同点是:他们要的是"快速拿到可用的几何结果",而不是"享受建模过程"。

这里必须先把一个概念说清楚,否则后面全是糊涂账。text-to-cad 目前有两条完全不同的技术路线,很多人把它们混为一谈,结果选型的时候踩大坑。

第一条路线是参数化脚本生成。系统理解你的文字后,生成一段 CAD 脚本(比如 CadQuery、OpenSCAD 或者某个软件的 API 调用),再由 CAD 内核执行这段脚本,输出真正的 B-rep 实体模型。这条路线的产物是"真 CAD"——有精确的尺寸、有特征树、可以继续编辑、可以直接导出 STEP 去加工。

第二条路线是生成式几何合成。用类似大语言模型或扩散模型的思路,直接"画"出三维网格(mesh)。这条路线的产物是三角面片,看起来像那么回事,但尺寸是模糊的,没有特征历史,想改一个孔的位置基本等于重做。

我个人的判断是:如果你的目标是"能拿去加工、能进装配、能出工程图",那必须走第一条路线;如果你只是要个视觉参考、做个渲染图、或者喂给下游的 AI 模型,第二条路线也能凑合。这个区分是理解整个 text-to-cad 领域的第一把钥匙,后面所有的工具选型、效果评估、踩坑经验,都建立在这个区分之上。

2. 拆解 text-to-cad 的技术链路:文字是怎么变成实体的

2.1 意图解析层:把"人话"翻译成"设计语言"

用户输入的是"一个长 80 毫米、宽 40 毫米、厚 5 毫米的板,四角各有一个直径 6 毫米的孔,孔中心距边缘 8 毫米"。这句话对人来说很清晰,对机器来说却是一团需要拆解的语义。意图解析层要做的事情包括:识别出这是一个"板类零件",提取出尺寸参数(80/40/5/6/8),识别出特征类型(拉伸体 + 四个孔阵列),还要推断出隐含的约束(孔是对称分布的,孔中心到两条边的距离都是 8)。

这一层现在主流做法是用大语言模型做结构化抽取,输出一个 JSON 或者类似的结构化描述。我实测下来,这一步的准确率是整个链路里最不稳定的环节。原因很简单:自然语言天生有歧义。"厚 5 毫米"到底是拉伸高度还是壁厚?"四角各有一个孔"如果板是圆角矩形,孔该放在圆角圆心还是理论角点?这些歧义人靠常识能补,模型经常补错。

一个实用的经验是:在提示词里主动消除歧义。与其说"一个厚板",不如说"一个拉伸高度为 5 毫米的矩形板"。与其说"四角打孔",不如说"在矩形四个理论角点向内偏移 8 毫米的位置各打一个直径 6 毫米的通孔"。你多打几个字,后面返工的时间能省一大截。这不是模型笨,而是自然语言本身就不精确,工程场景又恰恰要求精确。

2.2 脚本生成层:结构化描述到可执行代码

拿到结构化描述后,系统要把它变成 CAD 内核能执行的代码。以 CadQuery 为例,上面那块板大概会生成这样的东西:

import cadquery as cq result = ( cq.Workplane("XY") .box(80, 40, 5) .faces(">Z") .workplane() .rect(80 - 2*8, 40 - 2*8, forConstruction=True) .vertices() .hole(6) )

这段代码的逻辑是:先建一个 80×40×5 的长方体,然后选顶面作为工作平面,画一个内缩 8 毫米的构造矩形,在它的四个顶点上打直径 6 的通孔。注意这里有个细节——孔的位置是通过"构造矩形顶点"来定位的,而不是硬编码四个坐标。这样做的好处是,如果后面要把板宽从 40 改成 50,孔的位置会自动跟着调整,保持边距 8 毫米不变。这就是参数化的价值。

脚本生成层的核心难点在于:同一个几何意图有多种写法,选哪种直接影响模型的可编辑性。硬编码坐标写起来简单,但改一个尺寸就全乱;用约束和引用写起来绕,但改尺寸的时候模型能自适应。我见过不少自动生成的脚本,第一眼能跑通,第二眼想改就发现全是魔法数字,根本没法维护。所以评估一个 text-to-cad 工具,别只看它能不能生成,要看它生成的脚本"像不像人写的"。

2.3 几何内核层:脚本到实体的最后一步

脚本写好了,得有人执行。CAD 内核就是干这个的。常见的开源内核有 OpenCASCADE(CadQuery、FreeCAD 底层都用它),商业的有 Parasolid、ACIS。内核负责把"拉伸""打孔"这些操作变成真正的 B-rep 数据结构——用解析曲面和拓扑关系来描述实体,而不是用三角面片近似。

这一步对用户是透明的,但它决定了很多东西。比如为什么有些工具生成的模型导出 STEP 之后尺寸是准的,有些就飘了?因为前者走的是真内核,后者是网格近似。再比如为什么有些工具打孔特别慢?因为布尔运算(从实体里减去圆柱)是内核里最耗时的操作之一,孔越多越慢。

我踩过的一个坑是:早期用某个基于网格的方案做带几十个孔的板,生成速度飞快,但导出 STEP 之后发现孔变成了多边形近似,直径 6 毫米的孔实际是 5.97 到 6.03 之间波动的多边形。拿去加工直接被师傅打回来。后来换成基于 OpenCASCADE 的方案,速度慢了一半,但尺寸是精确的。在工程场景里,精确性永远优先于速度,这个取舍要想清楚。

3. 主流实现方案横向对比:别被演示视频骗了

3.1 基于代码生成的方案(CadQuery / OpenSCAD 路线)

这条路线的代表是各种"LLM + CadQuery"的组合。用户输入文字,模型生成 CadQuery 的 Python 代码,然后本地执行。优点是产物是真 CAD,可导出 STEP/STL,可参数化,可版本控制(代码就是模型)。缺点是对模型的代码能力要求高,生成的代码经常有语法错误或者 API 用错。

我实测过几个不同的模型来生成 CadQuery 代码,结论是:代码能力强的通用大模型,在这件事上明显优于专门微调过的小模型。原因在于 CadQuery 的 API 虽然不算复杂,但组合方式极其灵活,需要模型有比较强的"编程常识"。专门微调的小模型往往只会背几个常见模板,遇到稍微非常规的需求就抓瞎。

用这条路线,有几个实操要点值得记下来。第一,一定要在提示词里给出 CadQuery 的版本和关键 API 示例,否则模型会用错方法名。第二,生成的代码要先做语法检查再执行,直接 exec 有安全风险。第三,给代码加超时,因为有些布尔运算会卡死。第四,把常用零件做成函数库,让模型调用而不是从零生成,稳定性会高很多。

3.2 基于网格生成的方案(扩散模型路线)

这条路线的思路完全不同:把三维形状表示成某种隐式场或者点云,用扩散模型直接生成。代表工作是各种 text-to-3D 的模型。优点是生成速度快、视觉效果好、能处理非常复杂的有机形状。缺点是产物是网格,尺寸不精确,没有特征结构,改不动。

我拿这类方案做过一个测试:让它生成"一个带法兰的管道接头"。出来的东西远看挺像,近看法兰的螺栓孔是随机分布的,管道内径和外径的比例也不对。作为概念参考图可以,作为工程输入完全不行。所以这条路线我的定位很明确:概念阶段的视觉探索可以用,进入工程阶段立刻切换到代码生成路线。

3.3 两条路线的关键差异对照

对比维度代码生成路线网格生成路线
输出格式B-rep 实体,STEP/STL三角网格,OBJ/GLB
尺寸精度精确,可标注近似,有误差
可编辑性高,改参数即可低,基本重做
生成速度较慢,依赖内核运算较快
复杂曲面弱,适合规则几何强,适合有机形状
工程可用性可直接加工仅作参考
典型工具CadQuery、OpenSCAD各类 text-to-3D 模型

这张表是我自己在选型时反复对照的。核心结论就一句话:先想清楚你要的是"能用的模型"还是"能看的模型",再选路线。这个判断做错了,后面所有努力都是白费。

4. 从零搭一个可用的 text-to-cad 流程:我的实操步骤

4.1 环境准备与依赖选择

假设你要自己搭一套,我建议的最小可行组合是这样的:Python 3.10 以上,CadQuery 2.x,一个代码能力强的通用大模型 API,再加一个简单的 Web 界面(Streamlit 就够)。为什么选 CadQuery 而不是 OpenSCAD?因为 CadQuery 是 Python 库,能直接和模型生成的代码在同一进程里跑,调试方便;OpenSCAD 是独立语言,还得跨进程调用,链路更长。

安装 CadQuery 有个坑要提醒:它依赖 OpenCASCADE 的二进制包,在某些系统上直接 pip install 会编译失败。稳妥的做法是用 conda 装,或者用官方提供的预编译 wheel。我第一次装的时候在编译环节卡了快一个小时,后来换 conda 五分钟搞定。这种环境问题看着低级,但真的会劝退很多人。

conda create -n text2cad python=3.10 conda activate text2cad conda install -c conda-forge cadquery

装完之后跑一个最小验证,确认内核能用:

import cadquery as cq box = cq.Workplane("XY").box(10, 10, 10) cq.exporters.export(box, "test.step") print("内核正常")

能导出 STEP 文件,说明环境没问题,可以往下走。

4.2 提示词工程:让模型稳定输出可执行代码

这一步是整个流程里最需要打磨的地方。我的做法是准备一个系统提示词,里面包含四块内容:CadQuery 的版本信息、常用 API 的签名和示例、输出格式要求(只要代码不要解释)、以及几条硬性约束(比如"不要使用未定义的变量""所有尺寸用变量表示")。

一个我反复验证有效的技巧是:给模型几个"少样本示例"。比如给一个"生成带孔板"的完整代码,再给一个"生成阶梯轴"的完整代码,模型照着这个风格生成,出错率会明显下降。这比单纯用文字描述要求管用得多,因为代码这种东西,示例比描述精确。

还有一个细节:要求模型把关键尺寸提取成顶部的变量。这样生成的代码长这样:

LENGTH = 80 WIDTH = 40 THICKNESS = 5 HOLE_DIA = 6 EDGE_OFFSET = 8

后面如果用户说"把长度改成 100",你只需要改一个变量重新执行,不用重新问模型。这个设计让整个流程从"一次性生成"变成了"可迭代调整",实用性提升一大截。

4.3 执行沙箱与错误处理

模型生成的代码不能直接在主进程里 exec,这是基本的安全意识。我的做法是开一个子进程执行,设置超时(比如 30 秒),捕获所有异常,把错误信息回传给模型让它自我修正。

自我修正这个环节特别关键。实测下来,模型第一次生成的代码大概有 30% 到 40% 的概率跑不通,但把报错信息喂回去让它改,第二次的成功率能到 80% 以上。常见的错误包括:方法名拼错、参数顺序搞反、忘记 import、workplane 选错面。这些错误模型自己看报错基本都能改对。

import subprocess def run_cadquery_code(code, timeout=30): try: result = subprocess.run( ["python", "-c", code], capture_output=True, text=True, timeout=timeout ) if result.returncode != 0: return None, result.stderr return result.stdout, None except subprocess.TimeoutExpired: return None, "执行超时,可能是布尔运算过于复杂"

这段代码是我实际在用的简化版。注意超时处理,因为有些几何操作真的会卡住,没有超时保护整个服务就挂了。

4.4 结果验证:怎么判断生成的模型"对不对"

代码跑通了不代表模型是对的。我见过生成的代码能执行、能导出文件,但尺寸完全不是用户要的情况。所以必须加一层验证。

验证分两个层面。几何层面:检查包围盒尺寸是否和用户描述一致,检查孔的数量和位置。这个可以用 CadQuery 自己的 API 做,比如box.val().BoundingBox()能拿到包围盒。语义层面:把生成的模型渲染成图片,让多模态模型看一眼,判断"这像不像用户要的东西"。这一层能抓住一些几何检查抓不到的错,比如用户要的是"L 形支架",结果生成的是"T 形"。

我个人的经验是,几何层面的自动检查能覆盖 70% 的错误,剩下的靠人工确认或者多模态复核。完全自动化的闭环目前还不现实,但把人工介入点从"每次都要看"降到"只在可疑时看",效率提升已经很大了。

5. 实战中真正会遇到的坑:几个典型场景复盘

5.1 尺寸歧义导致的返工

有个场景我印象很深:用户说"做一个能放下手机的盒子"。这句话里没有任何一个精确尺寸。模型只能猜,猜出来一个 150×80×10 的盒子。用户一看说不对,我要的是能放下带壳的手机,而且要有 2 毫米余量。于是重新描述,模型再生成,来回好几轮。

这个坑的本质是:自然语言描述天然缺少工程所需的精度。解决办法不是让模型更聪明,而是在交互设计上做文章——当用户描述里缺少关键尺寸时,系统主动追问,而不是自己猜。我后来在流程里加了一个"参数确认"环节,模型先输出它理解的参数列表,让用户确认或修改,确认后再生成代码。这一步加进去之后,返工率下降非常明显。

5.2 布尔运算失败与几何退化

打孔、开槽、倒角这些操作本质都是布尔运算。布尔运算在几何上有个麻烦:当两个面恰好重合或者相切时,内核可能算不出来或者算出退化结果。比如你要在一个直径 6 的孔的位置,恰好那里有个直径 6 的凸台,两者相切,布尔减就可能失败。

我遇到过一次:生成一个带沉孔的板,沉孔深度恰好等于板厚,结果沉孔底面和板底面重合,内核直接报错。解决办法是把沉孔深度设成板厚减 0.01,留一点余量。这种"工程上的小聪明"模型是不会主动想到的,得靠人在提示词里加约束,或者在错误处理里加自动修正规则。

提示:在提示词里加一条"避免任何两个面完全重合的几何操作,必要时留 0.01 毫米余量",能规避掉相当一部分布尔运算失败。

5.3 复杂装配体的组合爆炸

单个零件好办,一旦涉及装配,难度陡增。用户说"把这三个零件装在一起,轴穿过两个轴承座",模型要理解的不只是三个零件的几何,还有它们之间的配合关系、同轴约束、间隙。我试过让模型直接生成装配代码,结果经常是零件位置对不上,或者配合面有干涉。

我的做法是分而治之:先分别生成每个零件,确认无误后,再用一个单独的步骤处理装配。装配这一步用显式的坐标和约束描述,而不是让模型自由发挥。虽然麻烦一点,但可控性高得多。装配这件事,目前阶段还是人给约束、机器执行比较靠谱。

5.4 生成结果的版本管理

用代码生成模型有个巨大的好处:模型就是代码,可以用 Git 管理。我现在的做法是每次生成都存一个带时间戳的脚本文件,配合一个简单的元数据记录(用户输入、生成时间、是否通过验证)。这样出问题能回溯,好的结果能复用。

这个习惯看起来不起眼,但用久了价值很大。有一次用户说"上次那个支架挺好的,就是孔再大一点",我直接翻出历史脚本,改一个变量重新生成,两分钟搞定。如果没有版本管理,就得从头再来一遍。

6. 这套东西的边界在哪里:什么能做,什么别指望

6.1 适合自动生成的零件类型

根据我的实践,以下几类零件用 text-to-cad 生成的成功率最高:板类零件(带孔、带槽、带倒角)、轴类零件(阶梯轴、带键槽、带螺纹)、简单的支架和连接件、标准件的变型(不同尺寸的螺栓、垫圈、法兰)。这些零件的共同特点是几何规则、特征明确、参数化程度高。

反过来,以下几类目前别指望:自由曲面(比如汽车外形、叶轮叶片)、复杂的有机形状、需要大量工程判断的结构(比如考虑受力优化的拓扑结构)、高精度配合的装配体。这些要么几何太复杂,要么需要领域知识,模型目前搞不定。

6.2 精度与公差的现实

text-to-cad 生成的是"名义几何",也就是理想尺寸。但实际加工需要公差。模型不会主动给你标公差,也不会考虑配合间隙。所以生成的模型只能作为设计的起点,公差标注、配合选择这些还是得工程师来做。

我一般会把生成的模型当作"第一版草图",然后在这个基础上手动加公差、加技术要求。这样整体效率还是比从零建模高,但别指望它一步到位出成品图。

6.3 和现有 CAD 工作流的衔接

生成的 STEP 文件能导入主流 CAD 软件,但导入之后是一个"哑实体"——没有特征树,没有草图,改尺寸得用直接建模的方式。如果你需要保留参数化特征,那得用 CadQuery 脚本本身作为"源文件",而不是 STEP。

我的建议是:把 CadQuery 脚本当作设计源文件管理,STEP 当作交付格式导出。这样既有参数化的可编辑性,又能和下游工具对接。这个工作流和传统 CAD 的"源文件 + 导出"逻辑是一致的,只是源文件从二进制变成了代码。

7. 我踩过的几个印象深刻的坑

第一个坑是过度信任模型的几何直觉。有一次让模型生成一个"壁厚 2 毫米的方管",结果它生成了一个实心方块。我盯着代码看了半天才发现,模型把"方管"理解成了"方的管子",但生成的时候用的是 box 而不是带抽壳的体。这种错误不是语法错误,代码能跑,但语义完全错了。从那以后我养成了习惯:生成完先看包围盒和体积,体积明显不对就说明理解错了。

第二个坑是忽略单位。CadQuery 默认单位是毫米,但有些模型生成的代码里混入了英寸的数值。有一次生成的零件尺寸大了 25.4 倍,导进 CAD 一看像个巨型雕塑。后来我在提示词里强制要求"所有尺寸单位为毫米,并在代码注释里标注单位",这个问题就少了。

第三个坑是布尔运算的顺序。先打孔再倒角,和先倒角再打孔,结果可能不一样。模型有时候会选一个导致几何问题的顺序。我的经验是,在提示词里明确要求"先做加法(拉伸、凸台),再做减法(打孔、开槽),最后做倒角和圆角",这个顺序最稳妥。

第四个坑是对"简单"的误判。用户说"很简单,就一个圆柱",结果这个圆柱要带螺纹、要带退刀槽、要带中心孔。模型按字面理解生成了一个光圆柱。这提醒我:用户的"简单"和工程的"简单"不是一回事,交互时要多问一句"有没有其他特征要求"。

8. 给想上手的人的几条实在建议

如果你现在想动手试试 text-to-cad,我的建议是按这个顺序来。先用现成的工具跑几个例子,感受一下能力边界,别一上来就自己搭。然后从最简单的零件开始,比如一块带四个孔的板,把整个链路跑通。跑通之后,再逐步增加复杂度,每次只加一个变量,这样出问题容易定位。

工具选型上,如果你要工程可用的结果,认准基于 CadQuery 或类似代码生成路线的方案;如果你只是要视觉效果,网格生成路线更省事。别在选型上纠结太久,两条路线各花半天试试,感受比看一百篇对比文章都直接。

最后说一个心态问题。text-to-cad 现在的能力,大概相当于一个刚学会 CAD 基本操作的实习生——能干活,但需要你盯着,需要你给清晰的指令,偶尔会犯低级错误。把它当实习生用,你的预期就对了;把它当资深工程师用,你一定会失望。这个定位想清楚了,用起来反而顺手,因为你会在合适的地方介入,而不是指望它全自动。

我自己现在的用法是:概念阶段用它快速出几个方案,选定方向后,用生成的脚本作为起点手动细化。这样既享受了自动化的速度,又保证了工程的严谨。这个"人机协作"的模式,我认为是现阶段最务实的做法。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进