资讯详情

Text-to-CAD实战:从一句话描述到可制造的CAD模型

📅 2026/10/8 16:45:13 | 华诺云谱 👁 阅读
Text-to-CAD实战:从一句话描述到可制造的CAD模型
我第一次注意到“text-to-cad”这个词是在一个3D打印社群里。有人发了一段话说“帮我做一个能卡在桌沿的理线架开口要 12 毫米宽”然后贴出了一张渲染图。底下人第一反应是“你用什么软件画的”结果回答是“我没画是用 text-to-cad 生成的”。当时我还在用传统建模软件一点一点拉草图说实话有点被刺激到。这个技术说白了就是让计算机根据自然语言描述直接生成可用的 CAD 模型。它和文生图最大的区别在于图片可以“看起来像”CAD 模型必须“真的能加工”。一个圆孔偏了 0.2 毫米装配的时候就装不进去。所以 text-to-cad 的核心不是“生成好看的样子”而是“生成有约束、有尺寸、能被制造系统识别的几何体”。这篇文章我想从自己的实际体验出发聊聊 text-to-cad 到底怎么工作、现阶段能做到什么程度以及如何用一套最小可用的流水线把“一句话描述”变成 STEP 或 STL 文件。不管你是 3D 打印玩家、机械工程师还是刚开始接触参数化建模的新手这篇内容应该都能给你一些可以落地的参考。1. Text-to-CAD 到底是什么先搞清楚它解决的问题1.1 不只是一个“翻译器”很多人第一次看到 text-to-cad会以为它是一个把自然语言“翻译”成三维形状的黑盒。实际上它更像是一个“需求理解 几何推理 工程约束满足”的组合问题。比如你说“一个直径 40 毫米、高度 60 毫米的圆柱体顶部开一个直径 10 毫米的沉头孔”这句话里包含了几个关键信息基本体素圆柱、尺寸参数直径、高度、特征操作开孔、孔的类型沉头。text-to-cad 需要把这些要求拆解成一系列可执行的建模操作而不是简单地画一个像素图。这种“结构化输出”的要求决定了它不能靠纯视觉模型硬扛。大多数成熟的方案都会引入中间表达要么生成一段参数化建模代码要么生成一个可以被后处理算法转成网格的隐式几何场。理解了这一点你就明白了为什么 text-to-cad 的评估标准里除了“看起来像”更重要的指标是“尺寸对不对”“能不能出工程图”“能不能被 CAM 识别”。1.2 两条主流技术路线代码生成与几何生成现在市面上讨论最多的 text-to-cad 实现基本可以分成两条路线。第一条是代码生成路线。模型输出一段脚本比如 CadQuery、OpenSCAD、SolidPython 代码然后由脚本引擎执行生成真正的实体模型。这个路线的优势非常明显因为有代码作为中间层每一步操作都可以被检查、修改和重新执行生成结果是参数化的后续改一个尺寸就能重新生成。坏处是模型得“会写代码”而且写出来的代码得能通过语法检查和几何引擎的校验。第二条是直接几何生成路线。模型直接输出 SDF有符号距离场、点云或者三角网格再用 marching cubes 之类的算法重建表面。这条路线适合自由曲面、有机形态比如鼠标外壳、人体工学手柄但输出通常不容易参数化编辑而且经常出现非流形网格、破面、缝隙直接拿去切片或加工会比较痛苦。在实际项目里这两条路线经常被混着用。比如先用代码生成参数化主体再用神经网络生成复杂曲面最后合并成一个模型。我自己的经验是如果目标是 3D 打印或者简单机械件代码生成路线现阶段要可靠得多。1.3 什么人在用用在哪身边的用户大致有三类。一类是创客和 3D 打印玩家用 text-to-cad 快速产出夹具、外壳、支架这类“一次性”零件一类是机械工程师在概念设计阶段用它做方案验证而不是直接出最终图纸还有一类是刚学参数化建模的人把“文本生成代码”当作一个快速入门辅助工具。一个很典型的场景是你想做一个 Raspberry Pi 的外壳传统流程是测量板子尺寸、画草图、考虑螺丝柱和开孔位置前前后后要折腾几个小时。用 text-to-cad你可以直接描述“一块 85x56x20 毫米的盒子壁厚 2 毫米底部留四个直径 3 毫米的螺丝柱位置”十几分钟就能得到一个能继续修改的初版模型。但请注意我说的是“初版”不是“终版”。把它当成一个能对话的建模助手而不是全自动总工程师才是现阶段最合理的心态。2. 为什么这件事比想象中难但仍然值得试2.1 难点在“确定性”大模型天生是概率系统同一个问题问两遍结果可能不一样。但 CAD 模型要求的是确定性直径 10 毫米的孔不能有时候是 9.98有时候是 10.03。每次生成都带一点随机抖动这在机械设计里是不能接受的。所以 text-to-cad 的工程难点不在于“把模型生成出来”而在于“如何保证每次生成都在公差范围内”。这也是为什么我强烈建议采用代码生成路线代码是可以被静态检查的尺寸参数直接写在数值里引擎一执行就知道是不是 10 毫米。如果代码里写的是10 random()那就是另一个故事了。此外自然语言本身就有歧义。“大一点的孔”到底是多大“靠近边缘”是靠近多少毫米模型需要结合上下文做合理默认并在输出里把这些默认值明确出来。我遇到过模型把“孔径 10mm”理解成“半径 10mm”一看实体傻眼了。所以提示词里最好要求模型“把所有尺寸显式标记在代码注释中”这一步能省掉后面非常多的排查时间。2.2 一个真实场景文本生成一个手机支架为了说明这条流水线长什么样我用一个最简单的例子串一遍。假设我想要一个“放在桌上的手机支架倾斜角 60 度底部开一个充电线走线槽”。我把这段描述发给一个能写代码的大模型要求它用 CadQuery 生成。模型的输出大致是import cadquery as cq def build_model(): # 底座 base cq.Workplane(XY).box(70, 20, 8) # 背板 back cq.Workplane(XY).moveTo(0, -30).box(70, 60, 8) back back.rotate((0, 0, 0), (1, 0, 0), 60) # 合并 result base.union(back) # 走线槽 result result.faces(Y).workplane().slot(10, 8, taper0).cutBlind(-5) return result这段代码能不能直接跑通取决于模型对 CadQuery API 的掌握程度。但至少思路是对的先建底座再建背板旋转出倾角最后切一个槽。把这个 Python 脚本用 CadQuery 执行输出 STEP 文件再用 FreeCAD 打开微调整个流程是走得通的。但你如果让它用 OpenSCAD 写输出的可能是另一种风格。OpenSCAD 更像编程语言一个rotate([60,0,0])加上一个cube()也能达到同样效果。选哪个引擎不重要重要的是你熟悉哪个、后续要接哪条制造链路。2.3 现阶段的能力边界用了几个月以后我给自己总结了一张“能做什么、不能做什么”的清单。能做的包括简单的机箱、支架、盒子、法兰、齿轮坯料以及带圆角、倒角、孔位的基础机械特征。这类零件结构规整、尺寸明确语言模型只要不犯糊涂代码通常一次就能跑通。暂时做不好的是复杂的装配体比如需要铰链配合、公差链分析、A 级曲面汽车覆盖件那种、经过拓扑优化的有机结构轻量化件以及需要大量行业规范判断的零件。不是说完全不能生成而是生成结果往往需要专业工程师大量返工省下的时间有限。所以我的建议是把 text-to-cad 用在“从 0 到 0.6”的设计阶段把“从 0.6 到 1.0”留给传统 CAD 工具。它最大的价值是帮你把空白画布变成一个可以被编辑的起点而不是替你完成全部工程判断。3. 亲手搭一条可用的 Text-to-CAD 流水线3.1 选型思路既然要在本地落一条流水线第一件事是选语言模型和 CAD 引擎。语言模型方面优先选代码能力强、上下文窗口大一点的。上下文窗口重要是因为你要把 API 文档片段、用户需求、历史报错信息都塞进对话里。窗口太小的模型塞不进参考文档就容易胡说。如果隐私要求高可以用本地模型比如 Qwen 系列、Llama 系列配合 Ollama 跑起来如果不在乎数据出网用云端接口也省心。CAD 引擎方面我个人推荐 CadQuery。原因很简单它是 Python 生态大模型对 Python 语料的学习量远大于其他脚本方言生成代码的准确率更高而且它直接输出 STEP 和 STL对接 FreeCAD、PrusaSlicer、Cura 都很方便。OpenSCAD 我也试过但它的函数式语法对语言模型来说踩坑率稍高特别是$fn、union()这类约定俗成的写法不够显式。3.2 基础代码骨架下面这个脚本是我常用的最小实现输入一段自然语言描述经过大模型生成 CadQuery 代码然后执行并输出 STEP/STL 文件。为了演示我用的是云端接口实际使用请替换成你本地的模型服务。import re import os import subprocess import sys import json from openai import OpenAI client OpenAI( base_urlhttp://localhost:11434/v1, # 这里可以替换为本地 Ollama 或云端 api_keyEMPTY ) def build_prompt(user_request: str) - str: return f 你是一个 CadQuery 建模专家。请根据用户描述生成一段 Python 代码。 要求 1. 使用 cadquery 库定义函数 build_model()返回一个 cq.Workplane 对象。 2. 所有尺寸必须使用毫米并在注释中标明关键尺寸。 3. 只能使用 cadquery 已存在的 API不要编造不存在的函数。 4. 输出格式代码块 python ... 。 用户需求 {user_request} def extract_code(raw: str) - str: match re.search(rpython\n(.*?), raw, re.S) if match: return match.group(1).strip() # 如果模型没按代码块输出就直接返回原文 return raw.strip() def run_code(code: str, work_dir: str) - None: script_path os.path.join(work_dir, generated_model.py) with open(script_path, w, encodingutf-8) as f: f.write(code) # 使用 subprocess 隔离执行防止依赖冲突 subprocess.run( [sys.executable, script_path], cwdwork_dir, checkTrue, capture_outputTrue, timeout120, ) def text_to_cad(prompt: str, output_dir: str output): os.makedirs(output_dir, exist_okTrue) user_prompt build_prompt(prompt) resp client.chat.completions.create( modelqwen2.5-coder:14b, messages[{role: user, content: user_prompt}], temperature0.2, # 低温度保证确定性 ) code extract_code(resp.choices[0].message.content) print(生成的代码\n, code) run_code(code, output_dir) print(完成结果在, output_dir) if __name__ __main__: user_desc sys.argv[1] text_to_cad(user_desc)你可能注意到temperature我设成了 0.2。这一步很关键。太高的温度会让模型“发挥”生成尺寸和结构飘忽不定太低则会让输出过于机械。0.2 左右是我试下来兼顾稳定和灵活的一个区间。另外timeout120要保留因为某些模型在复杂布尔运算时生成的代码可能会陷入死循环。3.3 让提示词模板安抚“幻觉”Text-to-CAD 最常见的失败方式不是模型不懂几何而是模型“一本正经地编造 API”。比如它会输出cq.Workplane().sphere(10, 50)实际上 CadQuery 里没有这种写法又比如它把box()的参数从 (长, 宽, 高) 记成 (中心点, 尺寸列表)。为了压制这种幻觉我在系统提示词里固定加了一段“API 记忆锚点”CadQuery 常用 API - Workplane(XY).box(length, width, height) - Workplane(XY).circle(radius) - Workplane(XY).workplane(offset10).hole(diameter) - Workplane(XY).union(other) - Workplane(XY).faces(Z).workplane().cutBlind(depth)这段内容不需要完整但要把最容易写错的基础函数列出来。模型在生成时会把这些作为“事实约束”而不是自己发挥。实测下来加了这段锚点之后代码的可执行率从不到 50% 提升到了 80% 左右。另外输出格式也最好强制让模型只返回一个 Markdown 代码块不要附带解释性文字这样解析起来最省事。3.4 执行与文件输出生成代码后我会把它写进一个独立目录再在 subprocess 里执行。这一步有两个原因。一是隔离依赖。本机可能装了多个版本的 Python 库直接把生成代码 import 到主进程里容易污染环境。二是安全。让模型生成的代码在子进程里跑即便它写出os.remove之类的东西摧毁的也只是临时工作目录不会动到主程序。如果你更谨慎可以用 Docker 单独开一个只读根目录的容器执行。执行完以后工作目录里通常会有 STEP 和 STL 两个文件。CadQuery 默认的导出函数是cq.exporters.export(result, model.step)和export(result, model.stl)。脚本里最好把这两个都导出。STEP 拿去做工程评审和精密加工STL 直接丢进切片软件打样两边都不耽误。3.5 快速验收别只盯着渲染图生成文件之后我强烈建议做一次“自动验收”不是肉眼看一眼就完事。最简单的方法是用trimesh加载 STL检查网格是否流形、体积是否合理、包围盒尺寸是否贴近预期。import trimesh mesh trimesh.load(output/model.stl) print(包围盒尺寸(mm):, mesh.extents) print(体积:, mesh.volume) print(是否为水密模型:, mesh.is_watertight)这个脚本能帮你捕捉两类问题一是模型单位错了比如实际尺寸比预期大了 25.4 倍包围盒一出来就能发现二是网格破洞、不可打印is_watertight直接告诉你该不该回炉。我一般会在验收脚本里加一条断言包围盒的每一项都必须在预期的 95% 到 105% 之间否则直接抛错让程序自动触发一次“修正对话”。4. 我踩过的坑和排查笔记4.1 单位错位一切都对就是尺寸不对有一次我让模型生成一个“宽 80 毫米的盒子”输出的 STL 在切片软件里显示宽度是 2032 毫米。翻了代码发现模型把所有长度都写成了3.149这种值明显是把 CAD 内部的“英寸”习惯带进来了。这种问题特别隐蔽因为模型代码里没有单位只有数字你不把尺寸打印出来根本看不出来。解决方法是双管齐下。一方面在提示词里反复强调“所有尺寸使用毫米”并且在代码注释里要求写出关键尺寸。另一方面验收脚本里对包围盒做断言。只要有一次尺寸超差就自动把测得值和预期值喂给模型让它重新生成。把“尺寸校验”做成年年都能自动跑的一条检查比每次都靠人眼靠谱得多。4.2 布尔运算让人怀疑人生CadQuery 里cut()、union()偶尔会失败报错信息往往晦涩难懂。我遇到最多的一种情况是两个体只在一个边缘上轻微相交浮点误差导致布尔运算找不到有效相交区域直接抛ValueError: Failed to find intersectable。这类问题的排查思路是先把布尔操作改成最简单的验证比如用一个临时脚本把两个体分别导出在 FreeCAD 里手动观察相交情况。如果你对几何有信心可以用fuse()替代union()用cut()之前先intersect()预览一下。还有一个更实用的技巧在操纵实体之前给所有尺寸加一个微小间隙比如把底座加厚 0.1 毫米让相交体积足够大运算成功率会高很多。4.3 大模型的“幻觉 API”是个常态我统计过自己一星期内生成的 100 次代码大约有 18 次会调用不存在的函数最常见的包括Workplane().rect()、Workplane().extrude()的参数写反、cq.Vector()和cq.Workplane()混用。不是说模型不会而是它在给不出精确记忆的时候倾向于编一个“听起来合理”的函数名。应对这个问题的核心手段是“把文档喂进上下文”而不是靠模型背诵。我在提示词里嵌过的 API 参考片段包括Workplane(),box(),cylinder(),sphere(),hole(),cutBlind(),union(),rotate(),faces(),workplane(),edges(),fillet()这些核心方法的签名。你不用贴完整文档太长反而会稀释注意力选高频操作就够了。4.4 常见问题速查表下面这张表是我自己整理的每次翻车后都会回填一行。你现在拿去用大概率能少走一半弯路。现象最常见原因处理方法STL 尺寸放大 25.4 倍模型混入英寸单位提示词强制“毫米”验收脚本断言包围盒布尔运算报错两个实体仅边角接触将接触面尺寸微增 0.1mm或用fuse()代码调用了不存在的函数幻觉在提示词注入 API 签名片段提供几个正确示例输出文件无法切片网格不是水密模型用trimesh.is_watertight检查要求模型重新生成模型有破面/缝隙高精度网格未合并顶点导出时设linear_deflection0.01,angular_deflection0.1底部孔位偏移坐标系参考面搞错代码里显式用faces(Z).workplane()不要默认XY平面生成的模型空壳没有执行export()在提示词要求代码块末尾必须包含导出指令4.5 让模型自己修错与其手工改代码我更常做的是把报错信息原封不动地塞回对话上下文。比如脚本执行抛了AttributeError: module cadquery has no attribute box我把这行错误贴进模型对话紧跟着一句“请检查并更正代码”。几次下来模型就能自己定位到 API 拼写和参数问题。但你要注意多轮修正会累积上下文模型可能在修好一个错误的时候引入另一个新错误。所以我会做一个“最多修正三轮”的限制超过三轮就从头开始用新会话重新生成而不是让它无限打转。这个机制看起来简单实际上能让最终的输出质量稳定不少。5. 从 Text-to-CAD 继续延伸5.1 接上 3D 打印与数控加工Text-to-CAD 生成的模型最直接的出口就是增材制造和减材制造。STL 文件可以直接拖进 Cura 或 PrusaSlicer 切片但前提是网格必须水密。如果你的目标是 CNC 加工那最好用 STEP 文件毕竟 STEP 携带精确的边界表示CAM 软件做刀路规划时信息更全。我建议在流水线里同时保留 STEP 和 STL 两个输出内部用 STEP 做验收外部用 STL 做切片。另外如果模型是给 3D 打印用的还要注意最小壁厚。语言模型经常生成 0.5 毫米甚至 0.2 毫米的薄壁打印出来一碰就碎。所以在提示词里加一句“请确保壁厚不小于 1.2 毫米”能省掉很多返工。5.2 和 AI 编程工具组合使用我自己更喜欢把 text-to-cad 和 AI 编程工具配合起来。比如用 AI 编程助手打开生成的 CadQuery 脚本让它在我要加圆角的地方直接改代码或者让 text-to-cad 批量生成一系列参数化零件然后我用循环脚本统一导出。这样单个零件的效果或许还不够惊艳但胜在速度快适合做系列化探索。一个特别有用的组合是把常用特征抽象成自己的函数库比如add_screw_boss()、add_rib()、add_snap_fit()然后让模型在生成代码时优先调用这些函数。你只需要在提示词里贴一份函数签名模型就会像拼积木一样组合。这相当于把一个通用 CAD 引擎变成你私有的设计语言非常值得一试。5.3 一个小技巧让“模板填充”替代“自由发挥”最后分享一个我反复使用的小技巧。如果某类零件你已经做过很多次不要每次都用自然语言让模型自由写代码而是把上次成功的代码拿过来挖掉其中几个关键参数变成一个带__PLACEHOLDER__的模板再让模型只负责填数字。比如def build_model(): result ( cq.Workplane(XY) .box(__LENGTH__, __WIDTH__, __HEIGHT__) .edges(|Z).fillet(__FILLET_RADIUS__) ) # 在顶部开孔 result (result .faces(Z).workplane() .hole(__HOLE_DIAMETER__) ) return result让模型以这个模板为基础根据你的自然语言描述填参数。这样做的好处非常明显API 调用正确率接近百分之百因为模板本身就是你验证过的代码你只需要关注数值是否符合需求。我在项目里把常用的盒子、法兰、托架都做成了这样的模板然后 text-to-cad 就从“试错生成器”变成了“参数填充器”可靠性一下子完全不同。我在实际使用中的体会是text-to-cad 不会替代 CAD 软件但它确实把“从文本到第一版模型”的距离压缩到了让人上瘾的程度。你不需要背下每个建模命令只要能把需求拆清楚剩下的交给模型去试探你再去做那个最终把关的人。这种工作方式真的很值得尝试尤其是那些需要快速验证想法的个人项目和原型开发。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑