text-to-cad实战:从自然语言到CAD模型的完整技术链路
发布时间:2026/10/7 11:02:38 锦皓数字建站

1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词我的反应是这不就是把自然语言变成 CAD 模型吗听起来像是给机械工程师准备的“懒人神器”。但真正动手试过之后才发现这件事远比想象中复杂也比想象中有意思得多。简单来说text-to-cad 是一类工具链或技术方案的统称核心目标是让用户用自然语言描述一个零件、一个装配体甚至一个简单机构然后系统自动生成对应的 CAD 几何模型并导出成 STEP、URDF、G-code 等下游可用的格式。它解决的核心痛点是传统 CAD 建模需要大量手工操作一个中等复杂度的零件从草图到拉伸到倒角到装配熟练工程师也要花上几十分钟甚至几个小时而很多场景下用户只需要一个“差不多能用”的模型来验证想法、做仿真或者出个示意图。这个方向适合谁来关注我梳理了一下大概有三类人一是做机器人仿真的朋友经常需要快速生成 URDF 模型丢进 CoppeliaSim 或者 Gazebo 里跑二是做机械设计的工程师想用自然语言快速出概念草图省去重复劳动三是做增材制造或者 CNC 加工的玩家需要从文字描述直接生成可打印或可加工的 G-code。如果你属于这三类中的任何一类那 text-to-cad 这个方向值得你花时间研究。我最初接触这个领域是因为一个实际需求手头有一堆机器人关节的参数想批量生成 URDF 文件导入 CoppeliaSim 做运动学验证。手动在 CAD 里一个个画再导出效率太低于是开始研究能不能用代码和自然语言描述来驱动整个流程。踩了不少坑之后总算跑通了一条从文本描述到 STEP 再到 URDF 的完整链路下面就把我的经验和思考完整分享出来。2. 整体设计思路为什么是“文本→中间表示→CAD”而不是“文本→CAD”2.1 直接端到端生成的陷阱很多人第一反应是搞一个端到端的模型输入文字直接输出 STEP 文件。我一开始也是这么想的但很快发现这条路走不通。原因很简单CAD 模型不是图片它是有严格拓扑结构和几何约束的。一个 STEP 文件里包含了实体边界表示B-rep、曲面方程、拓扑关系等大量结构化信息直接让一个语言模型去“画”出这些数据几乎不可能保证几何有效性。我试过用大模型直接生成 STEP 的文本内容结果出来的东西看起来像模像样但导入 CAD 软件后要么报错要么变成一个破面百出的烂模型。后来我明白了语言模型擅长的是语义理解和代码生成不擅长直接输出精确的几何数据。正确的做法是让模型生成“建模代码”或者“中间参数”再由可靠的几何内核去执行。2.2 中间表示层的选择代码即模型目前业界比较成熟的思路是把自然语言翻译成一段建模脚本比如 CadQuery、OpenSCAD 或者 build123d 的代码然后由这些库调用 OpenCASCADE 等几何内核生成真正的 B-rep 模型最后导出 STEP。这个思路的好处非常明显几何有效性由成熟的内核保证语言模型只需要负责“翻译”工作容错率高得多。我实测下来CadQuery 是目前最适合做 text-to-cad 的 Python 库之一。它的 API 设计非常接近人类描述几何的方式比如cq.Workplane(XY).box(10, 20, 5).faces(Z).hole(3)这样的代码读起来几乎就是一句英文描述。而且它底层用的是 OpenCASCADE导出的 STEP 文件质量很高能直接被 SolidWorks、中望 CAD、Fusion 360 等软件打开。2.3 为什么还要考虑 URDF 和 G-codetext-to-cad 的输出格式选择取决于下游应用场景。如果你做的是机器人仿真URDF 是刚需因为它描述了连杆之间的运动学关系如果你做的是 3D 打印或 CNC 加工G-code 才是最终目标如果你只是想做设计验证或者出图纸STEP 就够了。我的方案是以 STEP 作为中间格式因为它是几何信息的完整载体。需要 URDF 时从 STEP 提取几何信息再附加运动学参数需要 G-code 时把 STEP 导入切片软件或者用 FreeCAD 的 Path 模块生成。这样一条链路下来一份文本描述可以衍生出多种下游格式复用率很高。3. 核心细节解析从文本到几何的关键环节3.1 文本解析与意图识别text-to-cad 的第一步是把用户的自然语言描述拆解成结构化的建模意图。比如用户说“一个长 50 毫米、宽 30 毫米、高 20 毫米的长方体上面中心位置有一个直径 10 毫米的通孔”系统需要识别出基本形状是长方体尺寸是 50×30×20特征是通孔位置在上表面中心直径 10。这一步我建议用大模型来做 few-shot 提示给它几个输入输出示例让它输出结构化的 JSON 或者直接输出 CadQuery 代码。实测下来GPT-4 级别的模型在理解这类几何描述上已经相当可靠但需要注意单位问题。我踩过的坑是模型有时候会把“毫米”和“米”搞混导致生成的模型尺寸差了一千倍。解决办法是在提示词里强制要求所有尺寸统一用毫米并且在代码里加一个尺寸合理性检查。3.2 几何约束与特征建模CAD 建模和普通 3D 建模最大的区别在于约束。一个合格的 CAD 模型应该是参数化的、可修改的。比如你做了一个孔孔的直径应该是一个参数改这个参数后模型能自动更新。CadQuery 天然支持这种参数化建模你可以把尺寸定义成变量然后在建模代码里引用。我在实际项目中总结了一个经验对于 text-to-cad 生成的代码一定要保留参数化的结构不要把尺寸写死。比如不要生成box(50, 30, 20)而是生成length 50; width 30; height 20; box(length, width, height)。这样后续用户想调整尺寸时只需要改几个变量就行不用重新生成整个模型。3.3 格式导出与兼容性处理STEP 导出是 text-to-cad 最常用的输出。CadQuery 的exporters.export(result, output.step)一行就能搞定。但这里有几个细节需要注意一是 STEP 的版本AP214 和 AP203 的区别在于是否包含颜色和装配信息一般用 AP214 兼容性更好二是单位OpenCASCADE 默认用毫米但有些软件打开时可能会按英寸解释需要在导出时显式指定单位。URDF 导出就复杂一些。URDF 本质是一个 XML 文件描述的是连杆和关节的树状结构。从 STEP 到 URDF 需要做几件事把装配体拆分成单独的连杆、计算每个连杆的质心和惯性矩阵、定义关节类型和运动范围。我通常的做法是先用 CadQuery 生成每个连杆的 STEP然后用 Python 脚本计算惯性参数最后拼装成 URDF。这个过程后面会详细展开。G-code 的生成相对独立一般不需要从 STEP 转而是直接把模型导入切片软件如 Cura、PrusaSlicer或者用 FreeCAD 的 Path 工作台生成。如果你的 text-to-cad 流程要覆盖 G-code建议在生成 STEP 后调用命令行切片工具比如prusa-slicer --export-gcode model.step。4. 实操过程手把手搭建一条 text-to-cad 流水线4.1 环境准备与依赖安装先说一下我的环境Python 3.10Windows 11CadQuery 2.4另外装了 FreeCAD 0.21 作为备用工具。CadQuery 的安装推荐用 conda因为它的依赖比较多pip 装有时候会出问题。conda create -n text2cad python3.10 conda activate text2cad conda install -c conda-forge cadquery pip install openai如果你不想用 conda也可以直接pip install cadquery但需要确保系统里有 Visual C 运行库。我遇到过安装 CAD 时出现 C 2005 错误的情况那通常是运行库缺失装一个 vcredist 合集就能解决。CadQuery 虽然不依赖 CAD 软件但底层 OpenCASCADE 也需要一些系统库支持。4.2 用大模型生成 CadQuery 代码我写了一个简单的提示词模板把用户的自然语言描述转换成 CadQuery 代码。核心思路是给模型几个示例让它学会输出格式。import openai SYSTEM_PROMPT 你是一个 CAD 建模助手。用户会用自然语言描述一个零件你需要输出对应的 CadQuery Python 代码。 要求 1. 所有尺寸单位统一为毫米。 2. 使用参数化变量不要把尺寸写死。 3. 代码最后必须把模型赋值给 result 变量。 4. 只输出代码不要输出解释。 示例输入一个 50x30x20 的长方体上表面中心有一个直径 10 的通孔。 示例输出 length 50 width 30 height 20 hole_dia 10 result ( cq.Workplane(XY) .box(length, width, height) .faces(Z) .workplane() .hole(hole_dia) ) def text_to_cadquery(description): response openai.ChatCompletion.create( modelgpt-4, messages[ {role: system, content: SYSTEM_PROMPT}, {role: user, content: description} ] ) return response.choices[0].message.content实测下来这个提示词对大多数简单零件都能生成可运行的代码。复杂零件比如带圆角、倒角、阵列特征的需要更详细的描述和更多的示例。我建议在提示词里加上“如果描述不完整按最常见的工程实践补全”这样的指令让模型有一定的自主决策空间。4.3 执行代码并导出 STEP拿到代码后下一步是执行它并导出 STEP。这里要注意安全不要直接exec大模型生成的代码最好先做一次语法检查和简单的沙箱隔离。我的做法是用ast.parse检查语法然后在一个受限的命名空间里执行。import cadquery as cq import ast def execute_cadquery(code): tree ast.parse(code) # 简单检查只允许赋值和表达式 for node in ast.walk(tree): if isinstance(node, (ast.Import, ast.ImportFrom)): raise ValueError(不允许导入模块) namespace {cq: cq} exec(code, namespace) return namespace[result] result execute_cadquery(generated_code) cq.exporters.export(result, output.step)导出后的 STEP 文件可以直接拖进中望 CAD、SolidWorks 或者 FreeCAD 里查看。我一般会先用 FreeCAD 打开检查一下几何是否有效确认没问题再进入下一步。4.4 从 STEP 到 URDF 的转换URDF 的生成是机器人仿真场景的关键。假设我们有一个简单的两连杆机械臂每个连杆都是一个长方体。我的做法是分别生成每个连杆的 STEP然后计算惯性参数最后拼装 URDF。import numpy as np def compute_inertia_box(mass, length, width, height): # 长方体绕质心的惯性矩阵 ix mass * (width**2 height**2) / 12 iy mass * (length**2 height**2) / 12 iz mass * (length**2 width**2) / 12 return ix, iy, iz def generate_urdf(links): urdf ?xml version1.0?\nrobot namearm\n for link in links: ix, iy, iz compute_inertia_box( link[mass], link[length], link[width], link[height] ) urdf f link name{link[name]} inertial mass value{link[mass]}/ inertia ixx{ix} ixy0 ixz0 iyy{iy} iyz0 izz{iz}/ /inertial visual geometry box size{link[length]} {link[width]} {link[height]}/ /geometry /visual /link # 关节定义略 urdf /robot return urdf这个 URDF 可以直接导入 CoppeliaSim。我实测过CoppeliaSim 对 URDF 的兼容性不错但需要注意 mesh 路径问题。如果 URDF 里引用的是 STL 或 DAE 文件路径要用相对路径或者package://格式否则导入后会找不到模型。4.5 G-code 生成的补充说明G-code 的生成我一般不在 text-to-cad 流程里直接做而是把 STEP 导出后丢给切片软件。如果你确实想自动化可以用 FreeCAD 的命令行模式freecadcmd -c import FreeCAD; import Path; ...但说实话FreeCAD 的 Path 模块配置起来比较繁琐不如直接用 PrusaSlicer 的命令行接口来得方便。我通常的做法是生成 STEP 后用 PrusaSlicer 的 CLI 工具批量切片prusa-slicer --export-gcode --output output.gcode input.step这样一条命令就能搞定适合批量处理。5. 常见问题与排查技巧实录5.1 生成的模型尺寸不对怎么办这是最常见的问题。我遇到过的原因主要有三个一是模型把单位搞混了把毫米当成厘米二是提示词里没有明确尺寸模型自己“猜”了一个三是代码里的变量引用错了比如把长度变量用到了宽度上。排查方法很简单在导出 STEP 后用 CadQuery 读取回来打印 bounding box 的尺寸跟预期对比。result cq.importers.importStep(output.step) bb result.val().BoundingBox() print(fX: {bb.xlen}, Y: {bb.ylen}, Z: {bb.zlen})如果尺寸不对先检查提示词里有没有明确单位再检查生成的代码里变量有没有用错。我一般会在提示词里加一句“所有尺寸单位为毫米请在代码注释中标注每个尺寸的含义”这样出问题时容易定位。5.2 STEP 文件导入 CAD 软件后破面破面通常是因为几何内核在布尔运算时出了问题。比如两个实体相减时如果面相切或者有微小间隙就可能产生无效的 B-rep。解决办法是在 CadQuery 里加一个clean()操作它会自动修复一些常见的几何问题。result result.clean()如果 clean 之后还是有问题可以尝试调整布尔运算的顺序或者把复杂的布尔运算拆成多步。我遇到过一个案例在一个曲面上打孔直接打会破面后来改成先在一个平面上打孔再弯曲问题就解决了。5.3 URDF 导入 CoppeliaSim 后模型位置不对这个问题多半是坐标系定义不一致导致的。URDF 里每个 link 的视觉原点默认在 link 的坐标系原点而 CoppeliaSim 导入时会按照 URDF 的关节原点来摆放。如果 STEP 模型的原点不在几何中心导入后就会偏移。我的经验是在生成 STEP 时确保每个连杆的几何中心在原点或者在 URDF 里显式指定 visual 的 origin 偏移。比如visual origin xyz0 0 0.1 rpy0 0 0/ geometry box size0.1 0.1 0.2/ /geometry /visual这样即使几何中心不在原点也能通过 origin 偏移来校正。5.4 批量生成时速度太慢如果你需要生成几十上百个模型逐个调用大模型 API 会很慢。我的优化方案是先把所有描述批量发给模型让它一次性生成多个代码块然后本地并行执行。另外CadQuery 的建模本身很快瓶颈主要在 API 调用和 STEP 导出上。导出 STEP 时可以用多进程并行我实测 8 个进程能把导出速度提升 5 倍左右。5.5 常见问题速查表问题现象可能原因排查方法解决方案模型尺寸偏差大单位混淆检查 bounding box提示词强制毫米单位STEP 导入破面布尔运算失败用 FreeCAD 检查几何加 clean() 或拆分布尔操作URDF 位置偏移坐标系不一致对比 URDF 和模型原点调整 visual origin批量生成慢API 串行调用计时各环节批量请求加多进程导出代码执行报错语法或 API 错误打印完整 traceback加语法检查和沙箱6. 工具选型与生态对比CadQuery、OpenSCAD 还是 FreeCAD6.1 CadQuery vs OpenSCADOpenSCAD 是另一个常用的代码化建模工具它的语法更简单但功能也相对有限。OpenSCAD 基于 CSG构造实体几何本质上是在做布尔运算的堆叠不支持 B-rep 和 NURBS 曲面。这意味着它做出来的模型精度有限导出的 STEP 质量也不如 CadQuery。我个人的选择是简单零件用 OpenSCAD 快速出图复杂曲面和需要高精度 STEP 的场景用 CadQuery。CadQuery 的学习曲线稍陡但一旦掌握能做的事情多得多。6.2 FreeCAD 作为补充工具FreeCAD 在 text-to-cad 流程里主要扮演两个角色一是作为 STEP 文件的查看器和验证工具二是用它的 Path 模块生成 G-code。FreeCAD 的 Python API 也很强大但相比 CadQuery 更繁琐。我一般只在需要生成 G-code 或者做复杂装配时才会用到它。6.3 大模型的选择我试过 GPT-4、Claude 和几个开源模型。在 CadQuery 代码生成这个任务上GPT-4 的准确率最高Claude 也不错开源模型里 CodeLlama 勉强能用但需要大量微调。如果你预算有限可以考虑用 GPT-3.5 加 few-shot 提示对简单零件也够用。提示无论用哪个模型都建议在提示词里加上“只输出代码不要输出解释”和“确保代码可以直接运行”这两句能显著减少后处理工作量。7. 我踩过的坑和总结的几条经验第一条经验不要追求一步到位。我一开始想做一个“输入一句话输出完整装配体”的系统结果发现复杂度爆炸。后来改成先做单零件再做多零件装配最后做运动学关系每一步都验证通过再往下走效率反而高得多。第二条经验STEP 是好朋友。不管下游要 URDF 还是 G-code先把 STEP 生成好后面的事情都好办。STEP 是几何信息的“通用货币”有了它转换到其他格式只是时间问题。第三条经验参数化是灵魂。text-to-cad 生成的模型如果不可参数化那价值就大打折扣。我现在的做法是强制要求生成的代码里所有尺寸都是变量并且变量名要有意义比如hole_diameter而不是d。第四条经验验证环节不能省。每次生成模型后我都会用 bounding box 检查尺寸、用 FreeCAD 检查几何有效性、用 CoppeliaSim 检查 URDF 的运动学是否正确。这三个检查做完基本能覆盖 90% 的问题。最后分享一个小技巧如果你需要批量生成模型可以先把所有描述写在一个 CSV 文件里然后用脚本逐行读取、调用 API、执行代码、导出 STEP。整个过程可以完全自动化我最多一次生成了 200 多个零件从描述到 STEP 只花了不到半小时。这个效率手动建模是绝对做不到的。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。