1. 项目概览:text-to-cad 到底在解决什么问题
先用一句话说清楚:text-to-cad 是把"自然语言描述"直接转成可编辑三维 CAD 模型的开源工具。你输入一句"带四个圆柱腿的圆角矩形桌面",它就给你生成一个参数化建模的 STEP 文件,拿过去就能开加工或者继续改。
第一次看到这个项目标题时,我其实先愣了几秒。做结构设计这些年,CAD 建模一直是"人肉驱动"的活儿——画草图、拉特征、倒圆角、装配约束,每一步都要手动点。哪怕是最熟练的工程师,从想法到可用模型,少说也要半小时。而这个项目"text-to-cad"直接把门槛砍掉一大截:自然语言就是建模指令,模型生成代码,代码驱动 CAD 引擎,最终落成真实可用的几何体。
它适合谁?如果你是做机械设计的、搞 3D 打印的、做产品原型验证的,或者是刚接触参数化建模想试试水的新手,这个项目都值得花一个下午跑一遍。对于普通用户,它最大的价值不是替代你手搓模型,而是把"想法到雏形"这段最耗时、最容易劝退的路程变得几乎无感。
先说清楚一个大前提:text-to-cad 不是像 DALL·E 那样直接"画"出 3D 模型,也不是简单的文生图 + 模型重建。它的核心链路是"LLM 语义解析 -> 程序化建模代码 -> CAD 引擎执行"。也就是说,它走的是程序化生成(Procedural Modeling)路线,模型不是点云或网格,而是一段可执行的建模脚本。这个技术选型非常关键,后文我会专门拆开讲为什么这样设计是聪明的做法。
2. 技术原理:为什么选程序化建模这条"笨"路线
2.1 不是生成网格,而是生成建模步骤
我最早看到的 text-to-cad 项目,是在 Hugging Face 上发布的一个开源实现,作者是 Zachary Evans。它的核心逻辑可以用一条链说明:
用户输入文本(比如 "a desk with 4 legs and a flat top") -> LLM 结合参考图像(可选)生成 CadQuery 代码 -> CadQuery 引擎执行,输出 STEP 文件。
注意,这里 LLM 输出的不是"模型",而是"建模操作序列"。CadQuery 是一种基于 Python 的参数化 CAD 建模块,它用代码来描述几何特征——拉伸一个矩形、挖一个孔、倒一个圆角。text-to-cad 把"语义理解"和"几何构建"彻底拆开了:LLM 只负责把自然语言翻译成建模意图,真正的几何内核交给 CadQuery 处理。
这个"笨"路线的好处,我用一个类比说明。假设你要做一个木凳子,方案 A 是 3D 扫描仪对着真凳子扫一圈得到点云,再铺面;方案 B 是拿到一张图纸,按图纸一步步下料、组装。text-to-cad 走的是方案 B——它拿到的是一张可执行的图纸。这样生成的模型天然就是参数化的,尺寸可以改、特征可以删、圆角可以调,甚至可以批量生成一族相似模型。这在工程场景里是刚需:你做完一个零件,老板娘说"尺寸放大 10%,孔位右移 5 毫米",方案 B 改一行参数就完事,方案 A 就得重新扫描铺面,想死的心都有。
2.2 从文本到多视图渲染再到 CAD 代码的完整数据流
text-to-cad 的前期训练数据准备很有参考价值。它先用 Zero-1-to-3 这个视角合成模型,把模型库中的 3D 物体渲染成多视角图像,再把"文本描述 + 渲染图像"喂给微调过的 LLM,让它学会输出 CadQuery 代码。这一步相当于先教模型"看图说话"——看到某个形状的六个视角,能用建模语言复述出它的几何结构。
实际推理时有两套输入路径:
- 纯文本:直接输入 "A cylinder with a radius of 5mm and height 20mm",模型直接输出代码。
- 文本 + 参考图:上传一张真实物体照片或手绘草图,加上一句描述,模型参考图像中的几何形态输出代码。
第二种模式才是这个项目最杀人的功能。你拍一张桌子的照片,说"圆角的桌面,四根圆柱腿",它就能生成一个结构近似的参数化桌子。对于产品逆向、快速原型场景,这个工作流几乎是一种"作弊"级别的效率提升——传统流程里你得先测绘再建模,现在直接"拍照 + 一句话"就起步了。
2.3 LLM 输出代码的容错设计
这类项目的第一个灵魂拷问是:LLM 生成的代码有 bug 怎么办?CadQuery 脚本只要有一个参数类型不匹配,整个构建就崩了。text-to-cad 在架构上做了一个很聪明的容错设计:它会同时生成多份代码候选(实际推理时默认生成 3 份),每一份独立尝试执行,只要有一份成功构建出实体模型,就把它作为结果返回。这个"多路并行 + 竞速"的思路,在工程上叫冗余容错,实际效果非常明显——我试过连续生成十几个模型,失败率大概只有两成左右,而且大部分失败场景是 prompt 本身描述模糊,比如说"做一个好看的东西"这种没法量化的输入。
另外,项目的推理脚本里还有一个"conformation"模块,专门处理生成结果的自检。它会对输出的几何体做基础检查——体是否为流形、是否封闭、维度是否合理。不合格的代码直接淘汰,不会进入最终输出。这个自检机制对下游加工至关重要:一个非流形的网格文件进了切片软件,轻则打印出废品,重则把切片器干崩溃。
3. 环境准备与快速启动:从 GitHub 到第一个模型
3.1 硬件与软件清单
先交代一下我实际跑通的配置,给大家一个参考基准:
- 操作系统:Ubuntu 22.04(Windows 用 WSL2 也可以,但坑更多,后面单说)
- GPU:NVIDIA RTX 3060 12GB(其实 8GB 显存也够跑,只是慢一点)
- Python:3.11
- PyTorch:2.1.2 + CUDA 12.1
- 显存占用:单次推理峰值约 7GB(包括 Zero-1-to-3 图像编码和 LLM 推理)
如果你只有 CPU,也不是不能跑,就是慢。我在一台纯 CPU 的云服务器上试过,单次推理耗时大约 8-12 分钟,GPU 环境下只需要 40-60 秒。这个差距主要在 Zero-1-to-3 的图像编码器,那是纯 CNN,吃显存也吃算力。
3.2 安装过程中的真实踩坑记录
克隆仓库这一步没啥说的,pip 安装依赖才是坑的开始。我建议严格按照 requirements.txt 来装,不要自作主张升级包版本。尤其注意这几个包:
- cadquery 最好用 2.1 以上版本,太老版本对布尔运算的支持不行。
- openai 库的版本要匹配项目代码,太新版 API 有 breaking change。
- torch 和 torchvision 的版本必须一致,否则编译 CUDA 扩展时会炸。
我最初图省事用了pip install -r requirements.txt一把梭,结果 pyTorch 被装成了 CPU 版本,跑起来慢到怀疑人生。后来重新用官方命令装 CUDA 版才正常。
模型权重是另一个大坑。text-to-cad 依赖 Hugging Face 上的预训练权重,项目默认是从 HF Hub 下载,但国内网络环境下载大模型权重经常中断,我是手动下载权重文件后放到本机缓存目录的。操作步骤是:先查看~/.cache/huggingface/hub目录有没有残留文件,有的话删掉再往models--zavant--text-to-cad这样的目录结构里手动放二进制文件。放完之后跑一次推理,它会自动加载缓存里的文件,不需要重新下载。
3.3 跑通最小推理 Demo
进到项目根目录,创建一个最简单的 Python 脚本:
from text_to_cad import TextToCAD # 初始化模型 model = TextToCAD() # 一句自然语言描述 prompt = "a rectangular table with four cylindrical legs" # 生成结果 result = model.generate(prompt) # 保存 STEP 文件 result.save("table_from_text.step")如果你走的是带参考图的模式,需要先把图片转成 RGB 格式并缩放到 256x256 附近,否则 Zero-1-to-3 的前处理会出问题。我第一次喂了一张 1200 万像素的照片进去,跑了两分钟然后报了个尺寸不匹配的错误,后来加了个预处理步骤才解决。
跑通这个脚本之后,你就拿到了第一份 text-to-cad 产出。用 FreeCAD 或者 CadQuery 自带的查看器打开 STEP 文件,你会看到完整的实体模型。这个"自然语言 -> 真实可用三维模型"的瞬间,说实话,比我想象中要有成就感得多。
4. 核心实现细节与参数调优:让生成结果更可控
4.1 理解三个关键参数:视点数量、候选数、温度
text-to-cad 的推理接口里藏着几个直接影响输出质量的参数。我在实际测试中逐个调过,记录如下:
| 参数名 | 默认值 | 作用 | 我的调优建议 |
|---|---|---|---|
| num_images_per_prompt | 1 | 每个 prompt 渲染多少视角图 | 追求精度就调 4,代价是推理时间翻几倍 |
| num_cad_sequences | 3 | 生成多少份 CAD 候选代码 | 保持默认,太高没必要,太低容错下降 |
| temperature | 0.2 | LLM 采样温度 | 结构严谨类描述用 0.1-0.2,创意探索类用 0.6-0.8 |
这几个参数里,temperature 对结果的影响最玄学。我在生成"一个圆角矩形板"这种明确几何时,把温度调到 0.8,结果模型输出了一段完全跑不通的代码,CadQuery 直接报语法错误。后来把温度降回 0.1,输出就稳定多了。经验是:如果 prompt 描述非常具体,低温更安全;如果 prompt 只给了模糊意象,比如"现代风格的椅子",适当高温反而能避开"千篇一律"的平庸结果。
另一个容易被忽略的是 prompt 的措辞习惯。text-to-cad 的 LLM 在训练阶段见过大量"measurement-based"表达(比如带数字的尺寸描述),所以你的输入越像"工程语言",输出质量越高。我测试过几种说法:
- "a cup" -> 生成一个简单的圆柱杯
- "a cylinder with radius 3cm and height 10cm" -> 生成精确的圆柱
- "a large cup with a handle on the right side" -> 生成更复杂的异形杯
第三种生成的杯把手,实际是一个环形扫掠特征。这说明 LLM 对"handle on the right side"这类语义定位是能理解的,但前提是几何形态本身在训练数据里出现过。冷门形态,比如"带三个环形凹槽的不规则十二面体",模型大概率会给你生成一个莫名其妙的组合体。懂了这层,你就知道 prompt 该往哪个方向写了:交代结构、交代数量、交代相对位置,不要指望它理解审美形容词。
4.2 CadQuery 代码输出的常见模式
text-to-cad 生成的 CadQuery 代码大多遵循一套固定语法。我截取一段典型的输出(做了简化):
import cadquery as cq # 创建桌面 table_top = ( cq.Workplane("XY") .box(60, 30, 2) # 长宽高 .edges("|Z") .fillet(2) # 桌边倒圆角 ) # 创建四条桌腿 leg = cq.Workplane("XY").circle(1.5).extrude(25) leg_positions = [ (25, 12), (25, -12), (-25, 12), (-25, -12) ] # 合并主体 result = table_top for x, y in leg_positions: leg_moved = leg.translate((x, y, -12.5)) result = result.union(leg_moved) # 导出 cq.exporters.export(result, "table.step")注意几个特征:一是cq.Workplane("XY")这种起始平面选择,决定了建模的坐标基准;二是fillet倒圆角一定要在box之后单独做,否则会报"no edges selected";三是union合并的先后顺序影响性能,先小后大比先大后小更稳。
这里面最大的坑是坐标基准不一致。LLM 生成的代码里,有的特征用的是世界坐标(x, y, z),有的用 Workplane 局部坐标,两者混用极易导致零件错位。项目作者在实现里也注意到了这个问题,所以推理代码里有一个"坐标规范化"的预处理模块。我自己跑的时候遇到过桌腿位置偏移到桌面外面去的情况,排查后发现是 prompt 里写了"四条腿在角落",模型给每条腿都定义了一个绝对坐标,但桌面是居中的,坐标体系没对齐。解决办法是在 prompt 里明确"四个腿位于桌面四个角落"这种相对空间描述,让模型生成相对位置代码。
4.3 图像输入模式里的预处理管线
带参考图模式比纯文本复杂一个量级,因为图像需要经过 Zero-1-to-3 的多视角渲染后,才能作为条件输入给 LLM。这个管线的核心步骤是:
- 图像缩放:统一到 256x256
- 背景分割:去除背景,只保留主体
- 视角估计:估计图像中物体的近似朝向
- 多视角渲染:从多个虚拟相机位姿渲染出该物体的新视角图
- 特征拼接:把多视角图与文本描述一起交给 LLM
我在跑这一步时遇到的最典型问题是背景没抠干净。Zero-1-to-3 自带的背景分割器对纯色背景处理得很好,但遇到复杂纹理背景就会残留噪声,导致渲染出的多视角图出现"鬼影",最终 CAD 模型表面出现奇怪的凸起。我的经验是上传图片前先用 remove.bg 之类的工具把背景处理成纯白色,能显著降低生成失败率。
另外,图像输入模式下,prompt 的描述最好和图像内容"互为冗余"。也就是说,文本里别只写"桌子",要写"圆角桌面的桌子,桌面比四根腿都宽"。模型在融合图文信息时,如果文本描述与图像内容冲突,它大概率会优先信任图像——这跟多模态模型的训练模式有关。所以你的文本描述应该是对图像的补充,而不是对图像的复述。
5. 常见问题与排查技巧实录
5.1 推理失败的四个高频原因
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| CadQuery 执行报错,类型不匹配 | LLM 生成了非法参数 | 调低 temperature;增加 num_cad_sequences 冗余 |
| 生成结果是个空壳/零厚度的面 | 模型输出了Workplane但没有extrude或revolve | 检查代码中是否有厚度特征;prompt 里强调"solid"、"thickness" |
| 输出模型与描述明显不符 | 多模态信息冲突或 prompt 太模糊 | 增加图像参考;prompt 写得更结构化 |
| 显存不足(OOM) | 单次推理加载了过多模型 | 减小 batch size;升级到 12GB 以上显存 |
这里面最烦人的是第二种——代码语法没问题,模型也生成了,但结果是一张"纸片"而不是实体。原因通常在于 LLM 输出的 CadQuery 代码只定义了二维草图轮廓,而忘了extrude。处理办法我上面写过,最佳预防措施是把显式厚度指令写进 prompt。我在测试中对比过,"a solid metal plate with a thickness of 2mm" 和 "a metal plate" 的结果差异极大,前者 100% 生成实体,后者约 40% 概率生成纸片。
5.2 输出 STEP 文件打不开或导入失败
这个坑我初期也踩过。text-to-cad 默认是直接输出 STEP 模型文件,这种格式按说是最通用的,但如果你拿到的 STEP 文件导入 SolidWorks 时提示"文件包含无效几何体",大概率是模型执行过程中产生了退化面——比如圆角半径过大,导致相邻面自相交。
解决方案分两步:第一步,在 prompt 层面约束圆角半径的合理范围,比如"圆角半径 5mm 以下"。第二步,如果已经生成了坏文件,在 CadQuery 里做一次修复几何体操作再导出:
import cadquery as cq result = cq.importers.importStep("bad_model.step") solid = result.val().fix() # 尝试修复 cq.exporters.export(solid, "fixed_model.step")这个fix()方法会尝试修复退化的边和面,但也不是万能药。如果模型本身拓扑错误严重,修复后仍然可能报错,那时候我只能说:重新生成,这次 prompt 记得写精确点。
5.3 推理速度太慢,如何定位瓶颈
单次推理可以拆成三段耗时:LLM 生成代码(约 10-20 秒)、CadQuery 执行代码(约 1-5 秒)、Zero-1-to-3 图像推理(约 30-60 秒)。如果是纯文本模式,图像推理环节被跳过,整体速度快得多。
如果你觉得慢,先用time命令定位是哪段慢。实测下来,瓶颈通常不在 GPU 算力,而在 Zero-1-to-3 的 UNet 推理。那个模型虽然不大,但前处理环节包含了图像编码和多视角渲染,每一步都有大量张量操作。我试过把它从 FP32 改成 FP16 推理,速度快了接近一倍,精度基本无损。改法是在推理脚本里对模型调用.half(),再把输入张量转成.half(),注意同时要把torch.autocast打开,否则某些算子会被强制转回 FP32,等于白改。
5.4 多候选结果的挑选逻辑
生成 3 份候选代码后,项目默认会挑选第一个构建成功的作为最终结果。但"第一个成功"不等于"质量最好"。我跑过一个案例,三个候选里第一个成功的是一个色彩诡异但几何正确的模型,第二个虽然代码报错,但报错信息提示它想创建一个更复杂的结构,第三个则是一个过度简化的版本。这种场景下,我认为更合理的策略是按需挑选:
- 如果你追求几何保真:选构建成功中最接近 prompt 描述的候选,哪怕它代码有点乱。
- 如果你追求可编辑性:选 CadQuery 代码结构最简洁、特征分离最清晰的候选,方便后续手动改。
- 如果你追求加工可用:选实体体积和面数最常规的那个,避免出现微小碎面。
项目也提供了接口手动指定候选序号,你可以把三个候选都导出,在 CAD 软件里快速扫一眼再决定用哪个。反正生成成本不高,多导几个不亏。
6. 经验总结与进阶玩法:从玩具到生产力工具
6.1 这个项目在实际工作中到底能不能用
先说结论:对于快速验证、教学演示、概念设计,text-to-cad 完全够用;对于直接要交付生产的精密零件,它目前还不够格。原因很直白:LLM 生成的代码虽然逻辑上正确,但对公差、表面精度这类制造层面的约束缺乏感知。你让它做一个"直径 10mm 的圆孔",它可能生成 10.023mm 的孔,这在 3D 打印场景无伤大雅,但在 CNC 加工里可能就不符合 H7 公差要求。
不过它可以帮你节省大量"从零到一"的时间。我的工作流是:先用 text-to-cad 生成一个基础形态模型,导入 FreeCAD 后手动调整关键公差面,补加工艺特征(拔模角、退刀槽),半小时内完成一个传统流程可能要 3-4 小时的零件雏形。这个效率提升是实打实的。
6.2 后续扩展方向
如果你跑通了基本流程,有几个方向值得继续挖:
一是接入自建模型服务。项目默认使用远端推理接口,但你可以把模型权重部署到内部服务上,这样既快又不受限。我在内网部署过一次,单次推理延迟比公共接口低了近一半。
二是和参数化设计工具打通。text-to-cad 输出的是 CadQuery 代码,CadQuery 代码本质就是 Python 脚本,你可以把这个脚本嵌入你的自动化设计流水线。比如批量生成 100 种不同尺寸的支架,只要在大循环里改 prompt 参数就行。
三是反向工程。把 text-to-cad 生成的模型再导入 CAD 软件,用它作为参考几何,重新手工建模出高精度的生产模型。这个流程我用在过一个小零件上,从照片到最终交付模型,总共只用了不到一个上午。
6.3 最后一剂实用建议
如果你打算上手这个项目,我最大的建议是:不要把它当成一个"输入文字就出模型"的黑盒,而要把它当成一个LLM 与 CAD 引擎结合的参考架构。项目本身的模型权重、推理代码、数据管线,拆开看都是一份很好的多模态生成教学样本。哪怕你最后不用它出模型,光是把它的数据流捋一遍,你对"文本到强约束几何生成"这件事的理解都会上一个台阶。
最后分享一个小技巧:text-to-cad 对 prompt 的格式非常敏感。你可以在 prompt 里用逗号分隔多个子句,并用括号标注尺寸单位,比如 "a bracket, L-shaped, (thickness 3mm), (width 40mm), (height 30mm), with two screw holes on the vertical face, hole diameter 4mm"。这种结构化 prompt 的生成成功率远超自然语言长句。我从项目文档里瞄到这个规律后,把所有 prompt 都改成了这种格式,失败率骤降。这就是"跟模型对话"的正确姿势——它擅长的是结构化语义,不是文学修辞。