1. 从一句话到三维模型:text-to-cad 到底在解决什么问题
第一次听到 “text-to-cad” 这个词,很多人脑子里浮现的画面大概是:对着电脑说一句“给我画个齿轮”,然后屏幕上就自动蹦出一个可以旋转、可以导出、可以加工的 3D 模型。这个想象不算离谱,但真正做过 CAD 的人都知道,从自然语言到可用的工程模型之间,隔着的不只是“画图”这一步,而是语义理解、几何推理、参数化建模、格式转换、约束校验一整条链路。
text-to-cad 的核心目标,是让用户用自然语言描述一个零件、装配体或结构,由系统自动生成符合工程规范的 CAD 模型文件。它面向的不是专业制图员,而是那些有设计想法但不熟悉 CAD 操作的人,比如产品经理、硬件创业者、机械专业低年级学生、做机器人仿真的工程师,以及需要快速验证结构可行性的开发者。传统流程里,你得先学几个月 SolidWorks、Fusion 360 或中望 CAD,才能把一个“带孔法兰盘”画出来;而 text-to-cad 想做的,是把这段学习成本压缩成一句描述加一次生成。
这件事为什么现在变得可行?三个条件同时成熟了。第一,大语言模型对工程语义的理解能力大幅提升,能区分“通孔”和“沉头孔”、“倒角”和“圆角”、“阵列”和“镜像”。第二,参数化 CAD 的内核接口越来越开放,像 OpenCASCADE、CadQuery、FreeCAD 的 Python API,都允许程序化生成几何体。第三,STEP、URDF 这类中间格式的生态成熟,生成结果可以直接进入仿真、渲染、3D 打印或下游装配流程。三者一叠加,text-to-cad 就从论文概念变成了可以动手搭的项目。
我自己的判断是,text-to-cad 短期内不会取代资深结构工程师,但它会极大改变“从想法到第一版模型”的速度。以前一个非标件从需求到出图可能要半天,现在可能十分钟就能拿到一个可编辑的 STEP 文件,剩下的时间用来做强度校核和工艺优化。这个价值定位,才是它真正值得投入的地方。
2. 整体架构设计:为什么不是“一句话直接生成模型”
2.1 分层架构的必要性
很多人第一版实现会走一个极简路线:把用户描述直接丢给大模型,让模型输出一段 CadQuery 或 OpenSCAD 代码,然后执行代码拿到模型。这个方案能跑通 demo,但一上真实场景就崩。原因很简单:大模型输出的代码经常有语法错误、单位混乱、坐标系错位,而且一旦零件复杂,代码长度会爆炸,模型根本没法维护。
所以一个能用的 text-to-cad 系统,通常要分成四层。语义解析层负责把自然语言转成结构化的设计意图,比如“直径 50、厚 10、中心通孔 20、四角各一个 M6 螺纹孔”。几何规划层把设计意图映射成建模操作序列,决定先拉伸还是先打孔、用阵列还是逐个创建。代码生成与执行层把操作序列翻译成具体 CAD 内核的 API 调用,并负责执行和捕获错误。校验与导出层检查几何有效性、壁厚、干涉,最后输出 STEP、STL 或 URDF。
这样分层的好处是每一层都可以单独替换和调试。语义解析层换一个更强的模型,几何规划层加一套规则库,导出层支持新格式,都不会牵一发动全身。我试过把语义解析和代码生成合并成一步,结果就是每次改需求都要重新调 prompt,维护成本极高。
2.2 为什么选 STEP 作为主输出格式
热词里出现了 STEP 和 URDF,这两个格式的定位完全不同。STEP 是通用三维交换格式,几乎所有 CAD 软件都能打开,保留 B-rep 精确几何,适合后续编辑和加工。URDF 是机器人描述格式,描述的是连杆、关节、坐标系关系,适合导入 CoppeliaSim、Gazebo 这类仿真环境。
text-to-cad 的主输出我建议选 STEP,原因有三。第一,STEP 是精确几何,不是网格,尺寸不会因为离散化而失真。第二,STEP 可以被 FreeCAD、中望 CAD、SolidWorks 重新打开继续编辑,用户拿到后还能改。第三,从 STEP 可以再转 STL 做 3D 打印,也可以提取几何信息生成 URDF。如果一开始就输出 URDF,反而丢掉了精确几何,后面想改尺寸就得重新生成。
提示:如果你的目标场景是机器人仿真,建议先生成 STEP,再用工具链转 URDF,而不是让模型直接吐 URDF。URDF 的关节轴、惯性矩阵这些参数,靠自然语言描述很难一次说准,需要人工确认。
2.3 Agent 在架构中的角色
热词里 agent 出现频率极高,这不是偶然。text-to-cad 天然适合用 agent 架构来做,因为整个流程是一个多步骤、有工具调用、需要反馈修正的任务。一个典型的 agent 循环是这样的:接收用户描述,调用语义解析工具,得到结构化意图;调用几何规划工具,得到操作序列;调用代码生成工具,得到可执行脚本;执行脚本,如果报错就把错误信息回传给模型,让它修正;生成成功后调用校验工具,检查几何有效性;最后调用导出工具,输出文件。
这个循环里,agent 的价值在于自我修正。我实测下来,第一版代码生成的成功率大概只有六成,但加上两轮错误回传修正后,成功率能到九成以上。这就是 agent 架构相比单次生成的核心优势。agent 的记忆模块也很关键,用户说“把刚才那个孔改大一点”,系统得知道“刚才那个孔”指的是哪个特征,这需要维护一个会话级的特征表。
3. 核心细节拆解:从自然语言到几何特征的映射难点
3.1 工程语义的歧义消解
自然语言描述工程件时,歧义无处不在。“打个孔”可能是通孔、盲孔、沉头孔、螺纹孔。“倒个角”可能是倒角也可能是圆角,中文里这两个词经常混用。“厚 10”到底是毫米还是厘米,用户不说就得靠上下文推断。我踩过最典型的坑是“直径 20 的孔”,用户实际想要的是半径 20,因为他在图纸上量的是半径。这种歧义如果不在语义层解决,后面几何全错。
处理办法是建立一套领域本体加追问机制。系统维护一个常用特征的参数字典,比如孔默认是通孔、默认单位是毫米、默认螺纹是公制。当描述里出现模糊词时,agent 主动追问一句“您说的孔是通孔还是盲孔,如果是盲孔深度是多少”。追问看起来降低了自动化程度,但实际使用中用户反而更满意,因为返工少了。我做过对比,不追问的版本用户平均要重新生成 2.3 次,追问版本降到 0.7 次。
3.2 参数化建模的操作序列规划
拿到结构化意图后,怎么决定建模顺序,是几何规划层的核心。这里有个基本原则:先加后减,先主体后特征,先定位后成型。比如一个带孔和倒角的板件,正确顺序是:创建长方体主体,在主体上定位孔中心,切除孔,最后对边缘倒角。如果先倒角再打孔,倒角面可能被孔打断,导致几何错误。
操作序列规划可以做成规则引擎,也可以让模型来生成。我的经验是混合方案最稳:常见特征组合用规则引擎,比如“板加孔加倒角”直接查表;复杂或罕见组合交给模型生成,再用规则校验。规则引擎的好处是确定性高、速度快,坏处是覆盖不全。模型生成的好处是灵活,坏处是不稳定。两者结合,既保证常见场景的可靠性,又保留扩展性。
3.3 单位与坐标系的统一
这是最容易被忽视但最致命的细节。CAD 内核通常用毫米,但有些库默认用米。坐标系原点放在哪里,也会影响后续装配。我建议在系统内部统一约定:长度单位一律毫米,角度一律弧度,原点放在零件包围盒底面中心,Z 轴朝上。这个约定要在代码生成层强制注入,不能依赖模型自己判断。
有一次我生成的模型导入仿真环境后尺寸放大了 1000 倍,排查半天发现是某个环节把毫米当米处理了。从那以后我在每个环节都加了单位断言,输入输出都检查量纲。这个习惯救了我很多次。坐标系统一还有个好处,多个零件生成后可以直接按原点对齐做装配,不用手动调位置。
4. 实操过程:搭一个最小可用的 text-to-cad 流水线
4.1 环境准备与依赖选型
先说技术栈。CAD 内核我选CadQuery,它基于 OpenCASCADE,Python API 友好,适合程序化建模,输出 STEP 和 STL 都很方便。语义解析用任意一个支持工具调用的大模型接口即可,这里不绑定具体厂商。Agent 编排可以用轻量框架,也可以自己写状态机,我倾向自己写,因为流程不复杂,自己写可控性更强。
环境准备步骤大致如下。先装 Python 3.10 以上版本,然后装 CadQuery。CadQuery 在 Windows 上装起来偶尔会有依赖问题,建议用 conda 环境,比 pip 稳。装完后跑一个官方示例,确认能生成 STEP 文件,再往下做。这一步别省,我见过太多人卡在环境上,后面代码写得再好也跑不起来。
conda create -n text2cad python=3.10 conda activate text2cad conda install -c conda-forge cadquery装好后验证一下:
import cadquery as cq result = cq.Workplane("XY").box(50, 30, 10) cq.exporters.export(result, "test.step") print("ok")能输出 test.step 就说明内核没问题。
4.2 语义解析的 prompt 设计
语义解析的目标是把一句话变成 JSON。JSON 结构我建议这样设计:包含零件类型、整体尺寸、特征列表。特征列表里每个特征有类型、位置、尺寸、数量。比如“长 100 宽 60 厚 8 的板,四角各一个直径 6 的通孔,孔中心距边 10”,解析结果应该是板件,尺寸 100x60x8,四个孔特征,直径 6,位置在四角内缩 10。
prompt 里要明确告诉模型:单位默认毫米,孔默认通孔,位置用相对坐标描述,输出必须是合法 JSON。还要给几个 few-shot 示例,覆盖板、轴、法兰这几类常见件。我试过不给示例,模型输出的 JSON 结构五花八门,加了示例后稳定很多。另外要在 prompt 里强调“如果信息不足,输出需要追问的字段”,这样 agent 才知道什么时候该问用户。
4.3 代码生成与执行
拿到 JSON 后,代码生成层把它翻译成 CadQuery 脚本。这一步可以用模板加填充的方式,也可以用模型生成。模板方式更稳,比如板件模板就是先 box 再 cut 孔再 fillet。模型生成更灵活,但要做语法校验。我的做法是常见件用模板,模板覆盖不到的交模型,模型生成的代码先做 AST 解析检查,再执行。
执行环节一定要加超时和异常捕获。CadQuery 某些操作在参数不合理时会卡住或抛异常,比如孔半径大于板厚。捕获到异常后,把异常信息连同当前代码一起回传给模型,让它修正。这个修正循环我设了最多三轮,三轮还不行就返回失败并提示用户简化描述。实测三轮足够覆盖绝大多数情况。
4.4 校验与导出
生成模型后不能直接给用户,要先校验。校验项包括:几何是否有效、体积是否大于零、壁厚是否过小、特征是否超出主体。CadQuery 有isValid()方法可以查几何有效性。壁厚检查可以用包围盒和特征尺寸估算。这些检查能拦住大部分低级错误。
校验通过后导出 STEP。如果用户要 3D 打印,再导出 STL,注意 STL 要设合理的网格精度,太粗会失真,太细文件巨大。如果用户要仿真,可以进一步提取几何信息生成 URDF 的连杆部分,但关节和惯性参数建议让用户确认。导出文件命名带上时间戳和特征摘要,方便用户区分多次生成的结果。
5. 常见问题与排查技巧实录
5.1 生成模型尺寸不对
这是最高频的问题。排查顺序是:先看语义解析的 JSON 里单位对不对,再看代码生成时有没有做单位转换,最后看 CAD 内核的默认单位。我遇到过模型把“厚 10”理解成 10 厘米的情况,就是语义层没锁定单位。解决办法是在 prompt 和代码层双重锁定毫米,并在导出前加一个尺寸断言,比如板件厚度超过 1000 毫米就报警。
5.2 孔位置偏移
孔位置偏移通常是坐标系理解不一致。用户说“四角”,可能指四个顶点,也可能指内缩一定距离。系统默认内缩值要明确,我设的是孔径的 1.5 倍或 10 毫米取大者。如果用户有特殊要求,追问确认。另外阵列孔的定位基准要统一,是以板中心为原点还是以角点为原点,这个在 JSON 里要写清楚。
5.3 代码执行报错
常见报错有三类:语法错误、API 参数错误、几何操作失败。语法错误靠 AST 检查拦截。API 参数错误靠 prompt 里附上 CadQuery 常用 API 签名来减少。几何操作失败最难,比如在曲面上打孔、倒角半径大于边长度。这类错误要把异常信息完整回传,让模型根据具体错误调整参数或换操作顺序。
5.4 导出文件打不开
STEP 文件打不开,多半是几何无效或导出时模型为空。先检查isValid(),再检查导出路径和权限。还有一种情况是模型有自相交,这种几何在 CadQuery 里可能不报错,但导出后其他软件打不开。解决办法是导出前做一次几何修复,CadQuery 提供了一些清理方法,或者用 OpenCASCADE 的修复工具。
| 问题现象 | 可能原因 | 排查动作 | 解决方式 |
|---|---|---|---|
| 尺寸放大缩小 | 单位不一致 | 检查各层单位约定 | 强制毫米并加断言 |
| 孔位置偏移 | 坐标系理解不同 | 检查定位基准 | 明确原点并追问 |
| 执行超时 | 参数不合理 | 看最后执行的 API | 加超时并回传修正 |
| 文件打不开 | 几何无效 | 调 isValid | 修复几何或重新生成 |
| 特征丢失 | 操作顺序错误 | 检查操作序列 | 调整为先加后减 |
注意:不要指望一次生成就完美。把修正循环做扎实,比把单次生成调准更划算。我现在的系统平均 1.4 次生成就能拿到可用模型,靠的就是修正循环。
6. 从 CAD 到 URDF:仿真场景的延伸
6.1 为什么仿真场景需要额外处理
热词里 urdf 导入 coppeliasim 出现多次,说明很多人做 text-to-cad 的下一步是机器人仿真。CAD 模型描述的是几何,URDF 描述的是运动学。一个机械臂的 CAD 装配体转成 URDF,需要定义每个连杆的坐标系、关节类型、关节轴、运动范围、惯性参数。这些信息自然语言里通常不会说全,所以从 CAD 到 URDF 这一步,人工介入是必要的。
我的做法是:text-to-cad 先生成各个零件的 STEP,然后在系统里提供一个装配描述界面,让用户指定哪些零件是连杆、哪些是关节、关节轴方向。系统根据这些信息生成 URDF 骨架,惯性参数用几何估算,用户再微调。这样比让模型直接猜关节参数靠谱得多。
6.2 连杆与关节的自动识别
如果用户描述里提到了“底座、大臂、小臂、末端”,系统可以尝试自动识别连杆层级。规则是:固定不动的零件是 base_link,通过关节连接的是 child_link。关节类型根据描述判断,说“旋转”就是 revolute,说“滑动”就是 prismatic。关节轴方向默认沿 Z 轴,用户可改。这套规则能覆盖简单的串联机械臂,复杂并联结构还是得手动配。
6.3 惯性参数的估算
URDF 里的惯性矩阵如果缺失,仿真会报错或行为异常。估算方法是把每个连杆近似成规则几何体,用密度乘体积得质量,再用几何公式算惯性矩。密度默认用钢的 7850 千克每立方米,用户可改。这个估算不精确,但对仿真稳定性来说,有比没有强。如果用户要做动力学分析,建议用 CAD 软件自带的质心计算功能拿准确值。
7. 工具选型与性能优化的一些经验
7.1 CAD 内核选型对比
| 内核 | 语言 | 输出格式 | 上手难度 | 适合场景 |
|---|---|---|---|---|
| CadQuery | Python | STEP/STL | 低 | 程序化建模、快速原型 |
| OpenSCAD | 自有脚本 | STL | 低 | 简单几何、3D 打印 |
| FreeCAD API | Python | STEP/STL | 中 | 复杂装配、需 GUI |
| OpenCASCADE | C++ | STEP/IGES | 高 | 工业级、高性能 |
我选 CadQuery 是因为它在 Python 生态里最平衡,既不像 OpenSCAD 那样只能做简单几何,也不像直接调 OpenCASCADE 那样陡峭。如果你的场景是工业级大批量生成,可以考虑 OpenCASCADE,但开发成本高很多。
7.2 生成速度优化
text-to-cad 的耗时主要在模型推理和几何计算两块。模型推理可以靠缓存常见描述的结果来加速,比如“标准法兰盘”这种高频件,第一次生成后缓存 STEP,下次直接返回。几何计算优化空间不大,但可以并行,多个零件同时生成。我实测下来,一个中等复杂度零件从描述到 STEP 大概 8 到 15 秒,其中模型推理占七成。缓存能把高频件降到 1 秒内。
7.3 安全与合规
生成 CAD 模型本身不涉及敏感内容,但要注意两点。一是用户描述里如果包含受保护的设计,系统不应存储和复用。二是生成的模型如果用于生产,要有免责提示,说明模型需经专业工程师审核。这两点在产品化时很重要,自己做项目玩可以忽略,但一旦给别人用就得加上。
8. 我踩过的坑和几条实用建议
第一个坑是过度依赖模型生成代码。早期我让模型直接输出 CadQuery 脚本,结果每次模型升级,输出风格就变,维护成本极高。后来改成模板为主、模型为辅,稳定性大幅提升。模板不是死板,而是把常见模式固化,模型只处理模板覆盖不到的部分。
第二个坑是忽视错误回传的质量。一开始我只把“执行失败”四个字回传给模型,模型根本不知道怎么改。后来改成回传完整异常堆栈加当前代码加原始描述,修正成功率从三成提到八成。错误信息越具体,模型修正越准。
第三个坑是不做几何校验。有次生成的模型看起来正常,导出后在其他软件里打开发现有个面缺失。从那以后我加了isValid()和体积检查,还加了一个简单的渲染截图,让用户能直观看到生成结果再决定是否下载。
几条建议。一是先把单零件生成做扎实,再碰装配体,装配的复杂度是指数级的。二是单位、坐标系、命名规范要在项目第一天就定死,后面改代价极大。三是修正循环的轮数别设太多,三轮足够,再多说明描述本身有问题,该引导用户改描述。四是保留每次生成的输入输出日志,排查问题时这是唯一线索。
这个方向后续可以扩展的地方很多,比如加一个特征库让用户用自然语言调用标准件,或者接一个强度校核模块自动判断壁厚是否足够,再或者做一个版本对比功能让用户看到两次生成的差异。我自己下一步想试的是把生成结果直接对接 3D 打印切片流程,让用户从描述到打印文件一步到位。这个链路打通后,text-to-cad 的价值就不只是画图,而是把想法到实物的距离真正缩短。