☰
用Python打造text-to-cad:让CAD听懂自然语言指令
2026/10/26 22:12:31 网站建设 项目流程

我做设计这行快十年了,每天跟CAD打交道的时间比跟家人说话都多。这两年AI工具一堆接一堆冒出来,但老实说,真正能落进日常工作流、不扯淡的少。前段时间我一直在琢磨一个事:既然现在大语言模型能听懂人话了,那能不能让CAD也听懂人话?比如我敲一句"在这张图里画一条从原点出发、角度30度、长度100的线",图纸上就真的出现这条线。这个想法听起来像是科幻片,但实际上做个能跑的"text-to-cad"工具,真没有想象中那么玄乎。这篇文章就是把我从零搭起这个系统的完整过程、踩过的坑、还有最终跑通的效果都记录下来,给想在这条路上试试水的朋友一个参考。

1. text-to-cad到底在解决什么问题

先说个最直接的场景。我见过太多设计师和工程师,每天有一大堆时间花在重复性的绘图操作上:画矩形、拉标注、批量改图层、把散落的图纸拼到一起。这些操作本身不难,但架不住量大、繁琐、容易出错。你要是让一个刚入行的助理去改100张图的标注样式,他改到第30张的时候眼睛已经花了,改到第70张的时候基本是在凭肌肉记忆点鼠标。

text-to-cad这个方向,本质上就是想把这些"一句话能说清楚"的操作,变成"一句话就能执行"的命令。它的核心价值不是替代设计师思考,而是把那些不需要动脑子的重复劳动自动化掉。

用我自己的话总结,这个技术方向主要解决三类问题:

  1. 批量操作的效率问题。比如热词里提到的"python批量对cad修改",100张图纸统一改图层、改字体、改标注样式,用传统方式逐张打开、修改、保存,一个下午就没了。但如果能通过文字指令驱动脚本批量跑,几分钟搞定。
  2. 降低CAD的使用门槛。很多人不是不会画图,而是记不住那些命令。什么"BL"在CASS里对应哪个功能、"F命令用不了"是因为什么,这些细碎问题对老手不值一提,但对新手就是劝退级别的障碍。自然语言指令能把这个门槛削掉一大截。
  3. 跨软件协同的接口问题。CAD不是孤立存在的,它要和CASS、Revit、SketchUp甚至Excel打交道。text-to-cad可以把这些跨软件操作统一成一个"指令入口",不用再记每个软件里不同的操作方式。

为什么是现在这个时间点?因为Python生态已经足够成熟了。不管你是直接用pyautocad这种库去驱动AutoCAD的COM接口,还是用ezdxf这种库直接解析和生成DXF文件,都有现成的工具和大量的案例可以参考。加上现在大语言模型对自然语言的理解能力越来越强,把"人话"翻译成"参数"这一步也比以前靠谱得多。

2. 第一步:把“画一条直线”翻译成CAD能听懂的参数

任何一个text-to-cad系统,最核心的环节不是怎么操作CAD——那个反而是最不难的——而是怎么把乱七八糟的自然语言指令,变成CAD能执行的精确参数。

人说话是模糊的。我说"在图的右下角画个螺丝孔的符号",这句话人类能理解,但CAD不行。CAD需要知道:螺丝孔符号画在哪里(具体坐标)、多大(直径和比例)、放什么图层(我习惯把符号放"符号层")、用什么颜色。如果你不把这些定死,程序根本没法干活。

我一开始的思路是纯规则解析,也就是写一堆正则表达式和关键词匹配规则,把句子里的信息抠出来。比如匹配到"从x=...到y=..."这种结构就识别为画线指令,匹配到"长方形"或"矩形"就识别为矩形指令,再把坐标和尺寸参数提出来。

规则解析的问题很明显:它只能处理你已经预先定义好的句式。用户说"从0,0到100,50画条线"它能听懂,但用户如果说"给我来一条从起点到右上角的直线",它就傻眼了。"起点"和"右上角"这种相对概念需要额外去算。

所以我在规则解析之上又加了一层简单的"语义归一化"。做法是维护一个同义词表,把常见的口语表达映射到标准参数上。比如:

用户说程序理解
右上角/右上方视口内最大X、最大Y偏移点
从原点/从零点(0,0)
画条直线/连线/拉一条线LINE命令
跟这条线一样/按这个来复制上一条指令的参数

这一层做好之后,系统的鲁棒性会明显提升,至少常见句式都能覆盖到。但说实话,靠规则解析做到80%的覆盖率以后,再往上堆的性价比就很低了。这时候就得考虑上大语言模型做翻译,这个我在后面单独展开聊。

2.1 指令解析的最小实现

我先写了一个非常轻量的解析器,核心就干两件事:识别意图(画线、画圆、加标注、改图层),抽取参数(坐标、长度、角度、半径)。

核心代码大概长这样:

import re class CADCommandParser: def __init__(self): self.intent_patterns = { 'line': r'(画|绘制|拉|连).{0,4}(线|直线)|line', 'circle': r'(画|绘制).{0,4}(圆|圆圈)|circle', 'rect': r'(画|绘制).{0,4}(矩形|长方形|方框)|rect', 'text': r'(写|加|插入).{0,4}(文字|文本|字)|text', } self.coord_pattern = re.compile( r'(?:from|从)?\s*[\((]?\s*' r'(?P<x1>[-+]?\d+(?:\.\d+)?)\s*[,,]\s*' r'(?P<y1>[-+]?\d+(?:\.\d+)?)\s*[\))]?' r'\s*(?:to|到|至|和|,|,)?\s*' r'[\((]?\s*(?P<x2>[-+]?\d+(?:\.\d+)?)\s*[,,]\s*' r'(?P<y2>[-+]?\d+(?:\.\d+)?)\s*[\))]?' ) def parse(self, command_text: str) -> dict: intent = None for key, pattern in self.intent_patterns.items(): if re.search(pattern, command_text.lower()): intent = key break if intent is None: return {"success": False, "reason": "无法识别意图"} coords = self.extract_coords(command_text) result = { "success": True, "intent": intent, "params": {} } if coords: result["params"]["start"] = (coords[0], coords[1]) result["params"]["end"] = (coords[2], coords[3]) return result def extract_coords(self, text: str): match = self.coord_pattern.search(text) if match: return ( float(match.group("x1")), float(match.group("y1")), float(match.group("x2")), float(match.group("y2")) ) return None

这个解析器很简单,但已经能处理"从(0,0)到(100,50)画一条直线"、"画圆"这类基础指令。实际用下来,覆盖率大概在40%左右。要把覆盖率提到90%以上,还得做同义词表、上下文推断、历史参数引用这些增强。但这个雏形作为验证概念,完全够用。

3. 让Python真正驱动CAD:三条路线我全试过了

解析出指令参数只是第一步,接下来要让CAD真正执行操作。这一步我前后试了三种方案,各有各的适用场景。

3.1 路线一:pyautocad——最轻量,也最脆弱

pyautocad是对AutoCAD ActiveX接口的Python封装,安装以后调用非常简单:

from pyautocad import Autocad, APoint acad = Autocad(create_if_not_exists=True) point = APoint(0, 0) acad.model.AddLine(point, APoint(100, 50))

就这几行,就能在AutoCAD里画一条从(0,0)到(100,50)的直线。pyautocad的优点是门槛极低,三分钟上手。缺点是它依赖AutoCAD已经打开或者能自动启动,而且它是通过COM接口跟AutoCAD通讯的,中间任何一个环节出问题——AutoCAD卡死、弹窗拦截、权限问题——脚本就直接挂了。

我拿它做原型验证的时候还好,但一旦开始跑批量的真实绘图任务,稳定性就成了大问题。AutoCAD本来就时不时弹个对话框,COM调用被弹窗挡一下,整个脚本就卡在那里不动了。

3.2 路线二:pywin32直接调COM——稳定,但要写更多代码

pyautocad底层就是用pywin32调COM,但封装层掩盖了很多细节。直接调COM的配置空间更大,错误处理也更精细。

import win32com.client import pythoncom pythoncom.CoInitialize() try: acad = win32com.client.Dispatch("AutoCAD.Application") doc = acad.ActiveDocument model = doc.ModelSpace line = model.AddLine( win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [0.0, 0.0, 0.0]), win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [100.0, 50.0, 0.0]) ) except Exception as e: print(f"CAD调用失败: {e}") finally: pythoncom.CoUninitialize()

注意这里坐标要用VARIANT数组传进去,这是COM接口的硬性要求。很多人第一次写这个会直接在AddLine里传Python列表,然后被报错搞得一头雾水。我的建议是直接封装一个辅助函数:

def make_point(x, y, z=0): return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [float(x), float(y), float(z)]) def add_line(p1, p2, layer=None): line = model.AddLine(make_point(*p1), make_point(*p2)) if layer: line.Layer = layer return line

这条路线的稳定性和可控性明显比pyautocad好。尤其当你的操作开始涉及图层管理、图块插入、标注样式设置这些更复杂的功能时,COM接口最直接。

3.3 路线三:ezdxf——不进AutoCAD也能改图纸

如果你不想依赖AutoCAD本体(比如你只是要批量处理DXF文件,或者你手上根本没装AutoCAD),那ezdxf就是最优解。它直接读写DXF文件,完全不碰CAD程序。

import ezdxf doc = ezdxf.readfile("input.dxf") msp = doc.modelspace() msp.add_line((0, 0), (100, 50), dxfattribs={"layer": "线条层"}) doc.saveas("output.dxf")

ezdxf处理批量修改特别顺手,尤其是改图层、改字体、合并图纸这类不需要重新计算几何关系的操作。它的性能比COM方案好很多,因为压根就不用启动AutoCAD,纯文件级操作,几十张图唰唰就处理完了。

三条路线怎么选?我现在的建议是:

使用场景推荐方案
原型验证、单次小批量操作pyautocad
完整工作流、依赖现有图纸环境pywin32 + COM
批量处理、无头环境、自动化流水线ezdxf

实际项目里,我是COM和ezdxf混合用的。批量流程用ezdxf,需要实时操作当前打开的图纸、或者要调用AutoCAD特有的功能时,就切回COM。

4. text-to-cad最小系统实战:把指令变成真正的图纸

光有解析器和CAD驱动还不够,得把它们串成一个完整可用的系统。我做了一个非常精简但能跑通全流程的版本,整个过程分为四层。

第一层是输入层,接收用户的自然语言指令。第二层是解析层,把自然语言转成结构化命令。第三层是执行层,根据结构化命令调用对应的CAD驱动程序。第四层是反馈层,把执行结果(成功、失败、参数补充提醒)翻译回人能看懂的描述。

模块之间用JSON传递数据,结构很简单:

{ "intent": "add_line", "params": { "start": [0, 0], "end": [100, 50], "layer": "默认", "color": 1 } }

这样一个全链路的text-to-cad最小实现就成型了。我拿真实场景测了一轮,效果还过得去。比如输入"把图里所有图层为'临时'的实体移到'已完成'图层",程序就能通过ezdxf遍历所有实体,过滤出图层为"临时"的实体,改到"已完成"图层,然后保存。

再比如热词里提到的"cad图纸合并"。多张图纸要合并成一张,我做了个指令:

def merge_drawings(input_files, output_file): merged = ezdxf.new() for idx, f in enumerate(input_files): doc = ezdxf.readfile(f) msp = doc.modelspace() offset_x = idx * 200 # 每张图在新图中横向偏移200个单位 for entity in msp: new_entity = entity.copy() new_entity.translate(offset_x, 0, 0) merged.modelspace().add_entity(new_entity) merged.saveas(output_file)

思路是把每张图的实体复制到一个新文档里,然后通过平移避免图纸重叠。这个实现比较粗糙,真实合并图纸还要考虑图框、比例、标注互相干扰的问题,但作为text-to-cad的一个具体场景,验证了思路是通的。

5. 从"能跑"到"能用":我在实操中踩过的坑与对策

做原型容易,做到能放心交给同事用是另一回事。我在这个过程中踩了不少坑,每一个都是文档里不会写、只有真正跑起来才会遇到的那种。我把最关键的几个列出来,给后来人省点时间。

5.1 坐标系与单位:你以为的1就是1吗

最典型的问题是单位。CAD图纸里"1个单位"到底是1毫米还是1英寸,完全取决于图纸设置。如果用户的自然语言指令里说"画一个100x50的矩形",但没说明单位,程序就只能用图纸当前的单位体系去解释。

我的解决方案是:在系统里增加一个"单位声明"环节,强制用户明确单位。如果用户没说,就默认使用图纸模板的单位设置,并在反馈里提醒"默认使用毫米单位"。

5.2 图层和线型的命名规范比你想的重要

刚开始我在测试时,图层全用代码里写死的名字,比如"Layer1""Layer2"。结果一接入真实项目图纸就出问题了——人家的图层叫"框架梁-配筋""机电-消防-喷淋"。没有任何规则能猜到这些图层的命名逻辑,只靠程序硬猜必然翻车。

所以我现在在系统里内置了一层"图层映射配置":每个用户或每个项目都有独立的图层字典文件(就是个JSON),把自然语言里的"结构层""机电层""装饰层"映射到具体的CAD图层名。这个配置看起来笨,但实际非常有效。

5.3 异常恢复:脚本跑一半CAD崩了怎么办

批量处理时最怕的情况是:前面20张图都处理成功了,第21张图属性有问题,CAD直接崩溃,然后后面80张全部没处理。以前做普通脚本时对这种问题睁一只眼闭一只眼,但text-to-cad系统是给人用的工具,用户不可能接受这种半途而废。

我的做法是增加一个"检查点机制",每处理完一个文件就写一条处理记录到日志。下次运行时先比对日志,已经处理过的自动跳过,只处理未完成的。另外每个文件处理前先备份原文件,处理失败就一键回滚。

5.4 输入的自然语言总是出乎意料

最后必须承认:纯规则解析的鲁棒性是有限的,用户的实际表达总是超出你的预期。比如"把那根线稍微延长一点",规则解析完全处理不了"稍微"、"一点"这种模糊量词。对这些问题,我开始引入大语言模型作为解析层的补充:先用规则解析快速处理90%的标准指令,剩下的模糊指令扔给LLM,让LLM结合上下文输出结构化JSON。

这是目前text-to-cad从"玩具"走向"生产力工具"的最关键一步。我给LLM写的系统提示词大致是:

你是CAD指令解析器。把用户的自然语言转换为JSON指令。 指令格式: {"intent": "add_line|add_circle|change_layer|...", "params": {...}} 如果用户指令中的参数不完整,在params中用null标记缺失项。

实测下来,LLM对模糊表达的处理能力远超规则解析。比如"把最后画的线变成红色",LLM能根据上下文推断出"最后画的线"指的是上一条指令创建的实体,并输出带实体ID的修改指令。这种上下文推断能力,是传统解析器完全做不到的。

6. 下一步:text-to-cad能做到什么程度

这个系统目前在我的工作流里已经能承担相当一部分重复性劳动了。但我心里很清楚,距离"真正用自然语言自由操控CAD"还有很长一段路。眼下最现实的扩展方向有三个。

方向一是语义理解向设计意图延伸。现在做的是"理解指令",下一步可以尝试"理解意图"。比如"帮我排一下这面墙的插座",系统需要的不仅是简单的指令翻译,还需要理解插座布置的基本逻辑(间距、高度、避开柱位)。这已经接近"AI辅助设计"了,虽然不容易,但值得探索。

方向二是和设计规范结合做自动检查。既然text-to-cad能解析并操作图纸实体,那反过来它也能检查图纸里有没有违反规范的地方,比如标注有没有重叠、图层有没有用错、线型是不是统一。我计划下一步在这个方向上加点东西,把检查逻辑也做成自然语言驱动:"检查一下这张图里所有字体是不是都是HZ"这种指令。

方向三是把语音输入加进来。CAD操作本身有两个痛点:一是双手离不开键盘鼠标,二是眼睛离不开屏幕。如果text-to-cad的入口能接上语音识别,设计师就能一边看图一边说"把这个改成虚线"——这对现场修改图纸的场景会非常友好。

我做这个项目最大的体会是:text-to-cad不是要取代设计师,而是要把设计师从低效的重复操作里解放出来。它的核心价值在于把"想法"和"操作"之间的距离压缩到最短——在CAD里,想是一句话的事,做却要几十次点击。text-to-cad就是把这几十次点击,压缩回一句话。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询