前几篇,我们一直在讲 CAD AI 的一个判断:
真正重要的不是“AI 能不能生成一个 3D 外形”,而是它能不能进入工程师熟悉的 CAD 工作流。
Zero-to-CAD 这篇文章讲的是大规模可执行 CAD 构造序列。
这一次,看一个更贴近今天工程Ai Agent 使用方式的项目:earthtojake/text-to-cad
项目地址:
https://github.com/earthtojake/text-to-cad
如果只看名字,很容易把它理解成“文本生成 CAD 模型”。
但真正值得关注的不是这个名字。
它更像是一套给 Codex、Claude Code、Gemini、OpenClaw 这类 coding agent 使用的 CAD 工具链。
也就是说,它不是训练一个模型,让模型直接吐出一个神秘的 CAD 文件。
它做的是另一件事:
让 Agent 根据自然语言需求,写出可版本管理的 CAD 源码,再导出 STEP、STL、DXF 等工程文件,然后通过几何检查和可视化工具反复修正。
这比“文字变 3D”更接近工程软件的真实变化。
它不是一个 CAD 大模型
text-to-cad 仓库里最核心的东西,是一组 agent skills。
包括:
- cad:生成、修改、检查 STEP-first 的 build123d/Python CAD 模型
- cad-explorer:本地打开 STEP、STL、DXF、URDF、SDF、SRDF 做可视化审查
- step-parts:搜索和下载标准 STEP 零部件
- urdf、sdf、srdf:生成机器人和仿真描述文件
- sendcutsend:面向 SendCutSend 上传前的 DXF/STEP 预检

这套东西的工程含义很清楚。AI 不只是回答“你想画什么”。它还要知道:
- 源文件放在哪里。
- STEP 怎么导出。
- 生成结果是不是一个闭合实体。
- 边界框是不是符合预期。
- 哪些面、孔、轴、基准可以被引用。
- 如果检查失败,应该改源码,而不是手改生成文件。
- 这就是 CAD Agent 和普通 3D 生成最大的区别。
- 普通 3D 生成更像“出图”。
- 工程 CAD Agent 更像“跑流程”。

text-to-cad 的原理是什么
把 text-to-cad 理解成一个“文本到 CAD 模型”的神经网络,其实会误解它。它的核心不是一个新的 CAD 生成模型。
它的核心是把 coding agent、CAD 源码、几何内核、检查脚本和可视化工具接成一条链。
第一层,是 skills
skills 不是模型权重,而是一套给 agent 看的工程操作规范。比如 CAD skill 会明确告诉 agent:
- 优先生成 build123d Python 源码。
- STEP 是主要工程输出。
- DXF、STL、3MF 是派生输出。
- 修改时应该改源文件,而不是手改生成的 STEP。
- 生成后必须跑几何检查。
- 检查失败要回到源码修正。
这相当于把 CAD 工程师的一部分工作规程,写成了 agent 可以遵守的操作手册。
第二层,是参数化 CAD 源码
在这条路线里,Agent 不是直接吐一个不可解释的二进制 CAD 文件。
它写的是 Python。例如用 build123d 描述底板、孔、槽、圆柱、耳板、加强筋、布尔切除和标签。
这些源码能进版本管理、能被人读能改参数、能重新生成。
这一步非常关键。因为工程设计不是一次生成就结束,而是不断迭代。
第三层,是几何内核和导出脚本
build123d 背后依赖 OpenCascade 体系。
Agent 写出源码后,scripts/step 会执行源码里的 gen_step(),把 B-rep 实体导出成 STEP。
这个 STEP 才是可以交给 CAD、CAE、CAM 或制造流程继续处理的工程文件。
第四层,是检查和引用。
scripts/inspect 会读取生成结果,输出边界框、主要平面、面数量、几何引用和定位信息。
这就是 cad[...] 引用的意义。
以后如果你说“把这个孔扩大一点”“让这个面和另一个零件贴合”,Agent 不应该靠猜。
它应该能引用具体几何对象,再做精确修改。
第五层,是 CAD Explorer。
CLI 检查负责给出数字和结构事实。CAD Explorer 负责给人看。
它能打开 STEP、STL、DXF、URDF、SDF、SRDF,让工程师快速判断模型是不是空的、比例是不是对、主要特征是不是在正确位置。
所以 text-to-cad 真正的工作方式,可以概括成:
text 自然语言需求
→ Agent 读取 CAD skill
→ 生成 build123d 源码
→ OpenCascade 导出 STEP
→ inspect 做几何检查
→ CAD Explorer 可视化审查
→ 回到源码修正

这就是它和很多 3D 生成工具的关键区别。
它不是把 AI 放在最后一步,让 AI 直接给你一个结果。
它是把 AI 放进工程流程里,让 Agent 学会调用工具、生成文件、检查结果和继续修改。
换句话说,text-to-cad 的本质不是“文生 CAD 模型”。
更准确地说,它是:
面向 CAD 的 Agent 工作流框架。
我直接让 Codex 跑了一次
为了不把这篇写成项目介绍,我这次直接做了一次实战。
任务不是生成一个简单方块,而是设计一个稍微复杂一点、工程感更强的零件:
机器人云台支架底座。

我给 Codex 的目标大致是:
做一个带安装孔、中心轴承座、两侧耳板、横向轴孔、减重槽和加强筋的机器人云台底座,并导出 STEP。
这类零件适合作为演示对象。
它不是复杂到需要完整产品设计,但也不是只有一个方块加四个孔。
它有几个典型工程特征:
- 底板
- 安装孔和沉孔
- 中心轴承座
- 两侧支耳
- 横向轴孔
- 加强筋
- 减重槽
Codex 先安装了 text-to-cad 的 skills。
然后在本地建了一个 CAD runtime 环境,安装 build123d、OCP、ezdxf、trimesh、vtk 等依赖。
接着生成了一个 Python 源文件(robot_gimbal_base.py,后面会用到):
from build123d import *def _slot(length, width, height): """Capsule-shaped subtractive tool centered at the origin.""" radius = width / 2 return ( Box(length - width, width, height) + Cylinder(radius, height).moved(Location((-(length - width) / 2, 0, 0))) + Cylinder(radius, height).moved(Location(((length - width) / 2, 0, 0))) )def gen_step(): # Origin: center of the base footprint. XY is the mounting plane; +Z is up. base_x = 150.0 base_y = 95.0 base_z = 8.0 boss_radius = 31.0 boss_z = 16.0 bore_radius = 12.0 counterbore_radius = 20.0 ear_x = 18.0 ear_y = 18.0 ear_z = 58.0 ear_gap = 54.0 axle_radius = 7.0 rib_thickness = 8.0 rib_length = 52.0 rib_height = 30.0 cutter_z = 90.0 part = Box(base_x, base_y, base_z).moved(Location((0, 0, base_z / 2))) # Raised bearing boss and two side ears for a compact robot gimbal base. part += Cylinder(boss_radius, boss_z).moved(Location((0, 0, base_z + boss_z / 2))) for y in (-ear_gap / 2, ear_gap / 2): part += Box(ear_x, ear_y, ear_z).moved(Location((0, y, base_z + ear_z / 2))) part += Cylinder(ear_y / 2, ear_x, rotation=(0, 90, 0)).moved( Location((0, y, base_z + ear_z)) ) # Four diagonal-looking reinforcing ribs, kept as rectangular solids for a # stable demo model that still shows engineering intent. for y in (-ear_gap / 2, ear_gap / 2): for x in (-28.0, 28.0): rib_lift = 1.0 rib = Box(rib_length, rib_thickness, rib_height).moved( Location( (x, y * 0.72, base_z + rib_height / 2 + rib_lift), (0, 22 if x * y > 0 else -22, 0), ) ) part += rib # Central shaft bore and top counterbore. part -= Cylinder(bore_radius, cutter_z).moved(Location((0, 0, base_z + boss_z / 2))) part -= Cylinder(counterbore_radius, 7.0).moved(Location((0, 0, base_z + boss_z - 3.5))) # Axle holes through the upright ears. part -= Cylinder(axle_radius, base_x, rotation=(0, 90, 0)).moved( Location((0, -ear_gap / 2, base_z + ear_z)) ) part -= Cylinder(axle_radius, base_x, rotation=(0, 90, 0)).moved( Location((0, ear_gap / 2, base_z + ear_z)) ) # Mounting hole pattern and two service slots. for x in (-58.0, 58.0): for y in (-34.0, 34.0): part -= Cylinder(3.4, cutter_z).moved(Location((x, y, base_z / 2))) part -= Cylinder(6.5, 3.2).moved(Location((x, y, base_z - 1.6))) for y in (-22.0, 22.0): part -= _slot(54.0, 10.0, cutter_z).moved(Location((0, y, base_z / 2))) # Lightening pockets near the ends of the base. for x in (-48.0, 48.0): pocket = _slot(34.0, 14.0, cutter_z).moved(Location((x, 0, base_z / 2), (0, 0, 90))) part -= pocket part.label = "codex_robot_gimbal_base" return part
再由这个源码导出 STEP(robot_gimbal_base.step文件,后面会用到):
ISO-10303-21;HEADER;FILE_DESCRIPTION(('Open CASCADE Model'),'2;1');FILE_NAME('codex_robot_gimbal_base','2026-05-19T10:45:43',('Author'),( 'Open CASCADE'),'Open CASCADE STEP processor 7.8','build123d', 'Unknown');FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));ENDSEC;DATA;#1 = APPLICATION_PROTOCOL_DEFINITION('international standard', 'automotive_design',2000,#2);#2 = APPLICATION_CONTEXT( 'core data for automotive mechanical design processes');#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);#4 = PRODUCT_DEFINITION_SHAPE('','',#5);#5 = PRODUCT_DEFINITION('design','',#6,#9);#6 = PRODUCT_DEFINITION_FORMATION('','',#7);#7 = PRODUCT('codex_robot_gimbal_base','codex_robot_gimbal_base','',(#8) );#8 = PRODUCT_CONTEXT('',#2,'mechanical');#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#7280);#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);#12 = CARTESIAN_POINT('',(0.,0.,0.));#13 = DIRECTION('',(0.,0.,1.));#14 = DIRECTION('',(1.,0.,-0.));#15 = MANIFOLD_SOLID_BREP('',#16);#16 = CLOSED_SHELL('',(#17,#137,#213,#1594,#1643,#2203,#2210,#2265,#2320 ,#2426,#2501,#2803,#2886,#2982,#3009,#3036,#3043,#3098,#3307,#3356, #3408,#3575,#3705,#3737,#3819,#3896,#3979,#4090,#4167,#4403,#4487, #4566,#4693,#4745,#4935,#4995,#5048,#5204,#5257,#5306,#5425,#5530, #5578,#5586,#5682,#5709,#5736,#5743,#5798,#5848,#5995,#6045,#6095, #6145,#6319,#6369,#6376,#6383,#6434,#6461,#6508,#6540,#6591,#6616, #6623,#6629,#6636,#6661,#6667,#6694,#6701,#6728,#6734,#6810,#6866, #6924,#6950,#6956,#7012,#7038,#7085,#7091,#7097,#7122,#7128,#7155, #7162,#7189,#7195,#7202,#7236,#7271));#17 = ADVANCED_FACE('',(#18),#32,.F.);#18 = FACE_BOUND('',#19,.F.);#19 = EDGE_LOOP('',(#20,#55,#83,#111));#20 = ORIENTED_EDGE('',*,*,#21,.F.);#21 = EDGE_CURVE('',#22,#24,#26,.T.);#22 = VERTEX_POINT('',#23);#23 = CARTESIAN_POINT('',(-75.,-47.5,0.));#24 = VERTEX_POINT('',#25);#25 = CARTESIAN_POINT('',(-75.,-47.5,8.));#26 = SURFACE_CURVE('',#27,(#31,#43),.PCURVE_S1.);#27 = LINE('',#28,#29);#28 = CARTESIAN_POINT('',(-75.,-47.5,0.));#29 = VECTOR('',#30,1.);#30 = DIRECTION('',(0.,0.,1.));#31 = PCURVE('',#32,#37);#32 = PLANE('',#33);#33 = AXIS2_PLACEMENT_3D('',#34,#35,#36);#34 = CARTESIAN_POINT('',(-75.,-47.5,0.));#35 = DIRECTION('',(1.,0.,0.));#36 = DIRECTION('',(0.,0.,1.));#37 = DEFINITIONAL_REPRESENTATION('',(#38),#42);#38 = LINE('',#39,#40);#39 = CARTESIAN_POINT('',(0.,0.));#40 = VECTOR('',#41,1.);#41 = DIRECTION('',(1.,0.));#42 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' ) );#43 = PCURVE('',#44,#49);#44 = PLANE('',#45);#45 = AXIS2_PLACEMENT_3D('',#46,#47,#48);#46 = CARTESIAN_POINT('',(-75.,-47.5,0.));#47 = DIRECTION('',(0.,1.,0.));#48 = DIRECTION('',(0.,0.,1.));#49 = DEFINITIONAL_REPRESENTATION('',(#50),#54);#50 = LINE('',#51,#52);#51 = CARTESIAN_POINT('',(0.,0.));#52 = VECTOR('',#53,1.);#53 = DIRECTION('',(1.,0.));#54 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' ) );#55 = ORIENTED_EDGE('',*,*,#56,.T.);#56 = EDGE_CURVE('',#22,#57,#59,.T.);#57 = VERTEX_POINT('',#58);#58 = CARTESIAN_POINT('',(-75.,47.5,0.));#59 = SURFACE_CURVE('',#60,(#64,#71),.PCURVE_S1.);#60 = LINE('',#61,#62);#61 = CARTESIAN_POINT('',(-75.,-47.5,0.));#62 = VECTOR('',#63,1.);#63 = DIRECTION('',(0.,1.,0.));#64 = PCURVE('',#32,#65);#65 = DEFINITIONAL_REPRESENTATION('',(#66),#70);#66 = LINE('',#67,#68);#67 = CARTESIAN_POINT('',(0.,0.));#68 = VECTOR('',#69,1.);#69 = DIRECTION('',(0.,-1.));#70 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' ) );#71 = PCURVE('',#72,#77);#72 = PLANE('',#73);#73 = AXIS2_PLACEMENT_3D('',#74,#75,#76);#74 = CARTESIAN_POINT('',(-75.,-47.5,0.));
这一步很关键。
因为真正的输出不只是一个 STEP 文件。
更重要的是,工程师可以回到 Python 源码里继续改参数、改孔位、改特征。
这和很多“一次性生成一个网格”的 3D AI 完全不同。
实战教程:从安装到生成 STEP
如果你也想复现类似流程,可以按下面这条线走。
先说实测环境。
这次我是在macOS上完成安装、生成、检查和录屏的。
具体环境是:
-
macOS
-
Python 3.11
-
Node.js / npm
-
Codex、Claude Code 或其他支持 agent skills 的 coding agent
-
能正常访问 GitHub 和 PyPI
-
Linux 理论上也适合这条流程。
Windows 也不是不能做,但 CAD runtime、OpenCascade、浏览器预览和路径问题会多一些。第一次实战,建议先用 macOS 或 Linux。
第一步:安装 text-to-cad skills
最直接的方式,是克隆仓库后运行 Codex 安装脚本:
git clone https://github.com/earthtojake/text-to-cad.gitcd text-to-cad./scripts/codex-install.sh
如果你用的是 Claude Code、Gemini CLI 或 OpenClaw,可以换对应脚本:
./scripts/claude-install.sh./scripts/gemini-install.sh./scripts/openclaw-install.sh
安装完成后,重启一次 agent。
这一步很重要。
因为 skills 不是普通 Python 包,而是给 agent 看的工作流说明、脚本和工具入口。重启之后,agent 才能在任务里自动识别 CAD、CAD Explorer 这类能力。
第二步:安装 CAD runtime
skills 装好以后,还需要本机能真正跑 CAD 生成。
下面命令是本文在 macOS 上使用的配置方式。
在自己的项目目录里建一个隔离环境:
python3.11 -m venv .venv-cadskills./.venv-cadskills/bin/python -m pip install --upgrade pip
然后安装 CAD skill 的运行依赖:
./.venv-cadskills/bin/pip install \ -r ~/.codex/skills/cad/requirements.txt
这会安装 build123d、cadquery-ocp、ezdxf、trimesh、vtk、playwright 等依赖。
这里的核心是 build123d 和 OpenCascade 相关运行时。
Agent 写出来的是 Python CAD 源码,真正把实体模型变成 STEP,要靠这些几何库完成。
第三步:给 Codex 一个工程化需求
不要只说:
帮我画一个支架。
这种提示太模糊。
更好的方式是把对象、特征、尺寸和输出说清楚。
我这次用的需求可以写成这样:
使用 CAD skill 设计一个机器人云台支架底座。要求:- 单个 STEP 零件,单位 mm- 底板约 150 × 95 × 8 mm- 四个安装孔,带沉孔- 中央有轴承座和中心通孔- 两侧有竖直耳板,每个耳板有横向轴孔- 加减重槽和加强筋,让模型有工程结构感- 保留 build123d Python 源码- 导出 STEP 后做几何检查- 用 CAD Explorer 打开预览
这类提示比“画一个 CAD”有效得多。
因为它把 Agent 的任务从“想象一个外形”,变成了“按约束生成一个可检查的工程模型”。
第四步:生成 STEP
在这次实战里,Codex 生成的源码文件是:
robot_gimbal_base.py
源码里必须有一个入口函数:
pythondefgen_step():...return part
然后用 CAD skill 的 step 脚本导出:
./text-to-cad-codex-demo/cad/robot_gimbal_base.py \-o robot_gimbal_base.step
正常情况下,会得到:
robot_gimbal_base.step
这里要注意一个原则:
改源码,不要手改 STEP。
STEP 是导出结果。
真正应该保存和迭代的是 Python 源码。
第五步:做几何检查
生成 STEP 之后,不要马上宣布成功。
先跑检查:
./.venv-cadskills/bin/python ~/.codex/skills/cad/scripts/inspect refs \robot_gimbal_base.step \--facts --planes --positioning
重点看几件事:
- ok是否为 true
- kind是否是 part
- shapeCount是否符合预期
- bounds min/max是否合理
- size是否接近设计尺寸
主要平面和定位信息是否正常
我这次第一次检查就发现了问题。
加强筋旋转之后,模型最低点低到了底面以下。
这说明 CAD Agent 实战里,检查不是形式主义。
它真的会抓到肉眼不一定立刻发现的几何问题。
第六步:启动 CAD Explorer 预览
如果要本地打开 STEP,需要安装 CAD Explorer 的前端依赖:
npm --prefix ~/.codex/skills/cad-explorer/scripts/explorer install
然后启动预览:
npm --prefix ~/.codex/skills/cad-explorer/scripts/explorer run dev:ensure -- \--workspace-root "$PWD" \--root-dir "$PWD" \--file assets/text-to-cad-codex-demo/cad/robot_gimbal_base.step
它会返回一个本地地址。
这次我得到的是:
http://127.0.0.1:4310/?file=assets/text-to-cad-codex-demo/cad/robot_gimbal_base.step
打开之后,就可以旋转、缩放、检查模型。
到这里,一次完整的 text-to-cad 实战流程才算跑通:
安装 skills→ 安装 CAD runtime→ 给 Agent 工程化需求→ 生成 build123d 源码→ 导出 STEP→ 几何检查→ 修正源码→ 重新导出→ CAD Explorer 预览
再用 CAD Explorer 做可视化审查
几何检查之后,启动 CAD Explorer。
本地预览地址是:
http://127.0.0.1:4310/?file=assets/text-to-cad-codex-demo/cad/robot_gimbal_base.step
预览结果如下:
这段录屏的意义不是展示一个多复杂的零件。
而是说明一个更重要的点:
- Agent 生成 CAD 以后,不能停在“文件已经生成”。
- 它需要有审查界面。
- 需要能打开 STEP。
- 需要能看到模型是不是空的、是不是比例异常、孔和耳板是不是大致在正确位置。
- 需要把几何检查和人眼审查结合起来。
这就是 text-to-cad 这类工具链的价值。
现实边界很明显
这次实战也说明,text-to-cad 还不能被理解成“AI 已经替代 CAD 工程师”。
第一,Agent 生成的几何仍然需要检查。
它可能做出看起来合理、但局部基准不干净的模型。
第二,复杂工程意图仍然需要人定义。
比如载荷、材料、装配关系、公差、制造工艺、标准件规格,这些不是一句“画个支架”就能自动补全的。
第三,build123d 源码适合参数化建模和自动化生成,但它不等同于 SolidWorks、NX、Creo 里的完整企业建模历史。
所以这类工具当前最适合的位置,不是直接替代工程师做最终设计。
更现实的位置是:
- 快速生成初稿。
- 快速做几何变体。
- 快速导出 STEP。
- 快速做可视化检查。
帮助工程师把“从零起模型”的一部分时间压缩掉。
Ai4Engineer 观察
因为它给 CAD AI 提供了另一条路线。
不是所有 CAD AI 都必须先训练一个大模型。
还有一条路线是:
- 让 coding agent 学会调用 CAD 工具链。
- 让它写可维护的 CAD 源码。
- 让它导出工程文件。
- 让它用检查工具发现问题。
- 让它在可视化环境里把结果交给人审查。
这条路线很务实。
它不一定最像科幻里的“智能设计师”。
但它很像工程软件真正会发生的变化:
AI 先进入那些可脚本化、可验证、可反复执行的工程流程。
从这个角度看,text-to-cad 最重要的信号不是“文本能生成 CAD 了”。
而是:
Codex 这类 Agent,正在开始接触 CAD 的工程闭环。
- 它能写源码。
- 能生成 STEP。
- 能检查。
- 能修正。
- 能打开预览。
这比单纯生成一个漂亮外形更重要。
因为工程软件里的 AI,最终拼的不是谁更会聊天。
而是谁能更可靠地进入设计、检查、仿真、制造和交付流程。
text-to-cad 正好给了一个很好的观察窗口。
[登录查看剩余 70% 内容](javascript:void (0);)