OpenGL渲染与几何内核那点事-项目实践理论补充(二-1-(2):当你的CAD学会“听话”:从鼠标点击到自然语言命令)

@TOC

代码仓库入口:


系列文章规划:

巨人的肩膀:

  • deepseek
  • gemini

当你的CAD学会"听话":从鼠标点击到自然语言命令


故事续章:你的CAD已经能处理千人协同了,但用户说:"能不能直接跟我说,把螺栓加粗?"

你作为辣个蓝人【那个男人】,刚刚看了并发和内存那点事,又搞了搞CAD和图形渲染的小九九,正准备庆祝。产品经理又来了:"小C,现在AI这么火,我们的CAD能不能加个'语音助手'?用户说一句'帮我把所有螺栓加粗2mm',软件就自动执行。"

你愣了一下:"这......不就是自然语言转成API调用吗?"但仔细一想,问题远比想象中复杂。

用户说的"螺栓"在图纸里可能是一堆三角形的集合(STL文件),或者是一个块引用(DWG),或者是一个参数化特征(SolidWorks)。计算机不认识"螺栓"这个词 。你开始意识到,你需要一个 Agentic CAD Workflow(智能代理CAD工作流)------让AI当"翻译官",把人类的自然语言,翻译成CAD能执行的指令。


第一步:最原始的方式------硬编码命令,用户得像机器人一样说话

最早的CAD当然没有AI。用户想"加粗螺栓",得手动操作:

  1. 点击"选择工具"
  2. 框选所有螺栓(可能得一个个点)
  3. 点击"偏移面"命令
  4. 输入"2mm"
  5. 点击"确定"

你作为开发者,觉得这太繁琐了。你尝试做了一个命令行输入框,支持一些"宏命令":

复制代码
SELECT ALL BOLTS
OFFSET 2.0

你在代码里写了一个词法解析器 :遇到SELECT就进入选择模式,ALL表示全选,BOLTS是一个预定义的关键词(你得提前把图纸里的物体打上标签)。遇到OFFSET就调用offsetEntity(2.0)

但问题是:

  • 用户必须记住精确的命令词,说"加粗"不行,得说OFFSET
  • 你无法处理模糊语义:"把螺栓弄粗一点"------"一点"是多大?
  • 每个新命令都要你写解析逻辑,累死。

你意识到,这不是真正的"自然语言",只是换了个马甲的命令行。


第二步:引入大语言模型------让AI"猜"用户意图

2023年,ChatGPT火了。你想:能不能让LLM(大语言模型)来解析用户的话?

你设计了一个最简单的架构:

用户输入 :"帮我把所有螺栓加粗2mm"

发送给LLM (调用OpenAI API)

LLM返回{"action": "offset", "target": "bolt", "value": 2.0, "unit": "mm"}

你的CAD程序解析这个JSON,调用对应的C++函数。

你发现,LLM真的能理解"加粗"就是"沿法线向外偏移","螺栓"就是图纸中标记为bolt的物体。你不需要再写死关键词了。

但问题来了:

  • 每次调用都走云端API,延迟高(几秒钟),用户体验差。
  • 敏感图纸不能上传到第三方服务器。
  • LLM有时候"幻觉":用户说"把螺栓变胖",它可能返回{"action": "scale", "factor": 1.5},但"变胖"是径向缩放,不是沿法线偏移------你需要在提示词里做大量工程。

你开始研究 LangChainCoze


第三步:Agentic CAD Workflow------把"大脑"和"躯干"分开

你意识到,一个完整的自然语言控制CAD系统,应该分成四个层次,就像人的神经系统:

1. 感知层 (NLP) ------ 耳朵和嘴巴

接收用户的自然语言指令,转换成结构化的"意图"。你用了 Coze (国内字节跳动的AI Agent平台)或者 LangChain(开源框架)。Coze提供了拖拽式的Bot搭建,你可以快速做一个"CAD助手"原型,不需要自己写LLM调用代码。

在Coze里,你设计了一个工作流:

  • 输入:"帮我把所有螺栓加粗2mm"
  • 插件:调用一个你自己写的"CAD控制"插件(暴露为HTTP接口)
  • 输出:执行结果

2. 决策层 (LLM) ------ 大脑

LLM负责理解意图,并拆解成可执行的步骤。你发现,对于"加粗2mm",LLM需要推理出:

  • "螺栓"是哪些物体? → 需要查找图纸中所有"螺栓"标签的物体。
  • "加粗"是什么几何操作? → 沿每个面的法线方向向外偏移2mm。
  • 偏移后会不会自交? → 需要调用布尔运算检查。

你写了一个提示词模板 ,告诉LLM你的CAD支持哪些原子操作:find_objects_by_labeloffset_facescheck_intersection等。LLM会生成一个计划(Plan),例如:

json 复制代码
{
  "plan": [
    {"step": 1, "action": "find_objects", "args": {"label": "bolt"}},
    {"step": 2, "action": "offset_faces", "args": {"distance": 2.0, "direction": "normal"}},
    {"step": 3, "action": "check_collision", "args": {}}
  ]
}

3. 接口层 (Control API) ------ 神经

你的CAD项目需要暴露一个本地控制接口 。你选择了 WebSocketHTTP (RESTful),因为Coze/LangChain都支持。你在CAD程序里启动一个后台线程,监听localhost:8765

接口设计:

  • POST /find → 根据标签查找物体ID列表
  • POST /offset → 对指定物体ID执行偏移操作
  • POST /undo → 撤销

Coze的插件会调用这些接口。这样,你的CAD项目不需要改造成"AI原生",只需要加上一层薄薄的API外壳。

4. 执行层 (Renderer) ------ 肌肉

你的CAD程序收到指令后,调用现有的渲染管理器和几何内核:

  • render_manager.cpp中,你遍历所有顶点,沿法线方向移动2mm。
  • 如果用的是精确几何(如Open CASCADE的B-Rep),你调用BRepOffsetAPI_MakeOffset
  • 修改完成后,触发重绘。

你终于实现了:用户说一句话,屏幕上所有螺栓真的变粗了。


第四步:混合架构------"大脑"与"躯干"分离

你决定不要另起炉灶重写整个CAD。而是保持原来的C++核心不变,用LangChain/Coze搭建一个"控制端(Controller)",你的CAD项目作为"执行端(Executor)"。两者通过本地网络通信。

为什么这样做?

  • 解耦:AI技术迭代快(今天LangChain,明天可能又有新框架),你的CAD核心不需要跟着改。
  • 安全:图纸数据可以只留在本地,只把必要的文本信息(如物体标签)发给云端LLM,或者干脆用本地小模型(如Ollama + Llama 3)。
  • 复用:你可以把同样的API暴露给其他客户端(比如手机App、命令行脚本)。

你画了一个架构图:

复制代码
[用户] -> [Coze/LangChain] -> [本地WebSocket/HTTP] -> [你的CAD C++程序]
                                      |
                                      +-> [修改顶点数据/Model矩阵]
                                      +-> [重渲染]

第五步:技术挑战------STL文件不认识"螺栓"

你很快遇到了最棘手的问题:STL文件只是一堆三角形,没有语义。它不知道哪堆三角形属于"螺栓",哪堆属于"齿轮"。

你的CAD项目原本支持导入STL,但用户说"把螺栓加粗"时,程序根本不知道哪些三角形是螺栓。

你需要零件语义化。你开始研究几种方案:

方案A:人工打标签(最原始)

用户导入STL后,手动框选螺栓部分的三角形,然后右键"标记为螺栓"。你在代码里记录一个map<triangleId, string>。这是最可靠的,但费时。

方案B:基于几何特征自动识别(进阶)

螺栓有特征:圆柱面+螺纹+六角头。你可以写一个识别算法,遍历所有三角形,计算曲率、法线分布,找出符合螺栓几何特征的区域。这需要你懂计算机图形学和机器学习。

方案C:从STEP文件中读取语义(工业标准)

STEP文件本身就带有"产品结构",每个零件有名称、ID。你之前已经集成了Open CASCADE,可以读取STEP文件中的标签。例如:

cpp 复制代码
Handle(TDataStd_Name) nameAttr;
if (shape.FindAttribute(TDataStd_Name::GetID(), nameAttr)) {
    TCollection_ExtendedString name = nameAttr->Get();
    // name 可能是 "Bolt_M12"
}

这样,你不需要自己识别,用户直接导入带语义的STEP文件即可。

你决定在项目中同时支持三种方案:用户手动标记、几何特征识别(简单版本)、STEP语义读取。这样无论用户上传什么格式,都能理解"螺栓"。

几何变换逻辑:从"加粗"到"顶点位移"

当LLM决定"加粗2mm"后,你需要修改几何。对于网格模型(STL),做法是:

  1. 找出所有属于"螺栓"的三角形。
  2. 对每个三角形,计算法线方向(归一化)。
  3. 将三个顶点沿法线方向移动2mm。

注意:相邻三角形共享顶点,你不能重复移动。你需要先收集所有受影响顶点,去重,再统一移动。

对于精确模型(B-Rep),调用OCCT的偏移API:

cpp 复制代码
BRepOffsetAPI_MakeOffset offset(face);
offset.SetOffsetValue(2.0);
TopoDS_Shape newFace = offset.Shape();

你把这些逻辑封装成offsetEntityById(entityId, distance)函数,供接口层调用。


第六步:进阶挑战------让你的CAD助手"惊艳"全场

你完成了基础版:用户说"加粗螺栓2mm",程序执行。但产品经理说:"能不能更智能?比如用户指着屏幕说'加粗这颗',或者写一段Python脚本自动生成齿轮?"

你开始研究2026年的高阶路径。

挑战一:多模态交互------让AI"看"屏幕

用户不仅说话,还能用鼠标指向屏幕上的螺栓,然后说"加粗这颗"。你的助手需要"看懂"截图。

你集成了GPT-4o(支持图像输入)或类似的视觉语言模型。流程:

  1. 用户说"加粗这颗",同时鼠标在屏幕上点击。
  2. 你的CAD程序截取当前渲染画面,并记录鼠标坐标。
  3. 将截图+鼠标坐标+用户语音转文字,一起发给多模态LLM。
  4. LLM理解"这颗"指的是截图里鼠标位置附近的物体,返回该物体的ID。
  5. 然后执行加粗操作。

你需要在渲染器中给每个物体分配唯一颜色(ID Render Pass),这样鼠标点击时,你读取该像素的颜色,就能反查出物体ID。这是图形学里的经典技巧。

挑战二:Code Interpreter模式------让AI写代码改模型

用户说:"我想生成一个渐开线齿轮,模数2,齿数20。" 这不是简单的"偏移",而是参数化建模。

你的方案:不让LLM直接调用你的C++ API(太复杂),而是让LLM生成一小段Python脚本,然后由你的CAD程序内置的Python解释器执行。

你在项目中嵌入了Python.h (CPython的C API),或者用pybind11暴露一些几何操作给Python。然后:

  1. LLM生成脚本,例如:
python 复制代码
from cad_api import create_gear
gear = create_gear(module=2, teeth=20)
add_to_scene(gear)
  1. 你的C++程序调用PyRun_SimpleString执行这段脚本。
  2. 脚本通过pybind11调回C++的几何内核,生成齿轮的B-Rep。

这就是 Code Interpreter 模式 ------ 让AI编程,而不是发JSON。好处是:你可以复用已有的Python生态(如numpy、scipy),而且用户也可以自己写脚本扩展功能。


第七步:你的"CAD助手"诞生了

经过几个月的开发,你终于拿出了原型:

  • 感知层:用Coze搭建的Bot,支持语音输入(用户对着麦克风说话)。
  • 决策层:接入GPT-4o,能理解模糊指令,拆解成计划。
  • 接口层 :你的CAD程序暴露了WebSocket API,支持find_by_labeloffset_facesrun_python等操作。
  • 执行层:支持网格和B-Rep的几何变换,支持Code Interpreter。
  • 语义化:自动从STEP文件读取零件名称,也支持用户手动标记STL的三角形组。
  • 多模态:用户鼠标指向+语音,AI能定位物体。

产品经理演示给老板看:他打开一个复杂的齿轮箱装配图,说"把所有的M6螺栓加粗1mm,然后把输出轴的长度缩短5mm"。几秒钟后,图纸自动更新。老板惊呼:"这就像钢铁侠的贾维斯!"

你笑了,你知道这背后是无数个日夜的工程:LLM的提示词调优、WebSocket的稳定性、法线计算的数值精度、Python解释器的隔离......但这一切都值得。


深度解析:Agentic CAD Workflow 从入门到精通

通过上面的故事,你已经对"CAD助手"的构建有了直观理解。下面,我们来系统地、由浅入深地剖析每一个技术点,确保你从零基础到能够自己动手实现。

1. 自然语言控制CAD:从硬编码到Agentic Workflow

阶段一:关键词匹配(远古时代)

  • 实现:if (cmd.find("加粗") != string::npos) { offset(2.0); }
  • 缺点:无法处理同义词、无法理解复杂语义、扩展性差。

阶段二:正则表达式 + 模板填充

  • 实现:正则/(加粗|变粗|放大) (\d+)mm/ 提取数值。
  • 缺点:用户必须按固定模板说话。

阶段三:传统NLP(词性标注、句法分析)

  • 实现:用Stanford CoreNLP提取"动作-对象-参数"三元组。
  • 缺点:需要大量标注数据,难以处理"所有螺栓"这种集合。

阶段四:大语言模型 + 函数调用(Function Calling)

  • 实现:OpenAI的tools参数,让模型返回结构化JSON。
  • 优点:零样本泛化,理解自然语言。
  • 缺点:依赖云端,延迟高,幻觉风险。

阶段五:Agentic Workflow(代理工作流)

  • 实现:LLM作为"大脑",调用多个原子工具(查找、偏移、检查),自主规划步骤。
  • 代表框架:LangChain、Coze、AutoGen。
  • 关键组件:ReAct模式(Reason + Act),模型先推理再行动。

2. LangChain vs Coze:选哪个?

维度 LangChain Coze
性质 开源Python框架 字节跳动云端平台(免费)
适用场景 需要深度定制、自托管、本地模型 快速原型、国内网络友好、拖拽式开发
核心概念 Chain, Agent, Tool, Memory Bot, Plugin, Workflow, Knowledge
代码示例 agent.run("加粗螺栓") 画布上拖拽"大模型节点"+"代码节点"
本地部署 支持(Ollama等) 不支持,必须走云端
多模态 需自行集成 内置图像理解(需申请)

建议:初学者用Coze快速跑通原型,生产环境自托管LangChain以保护图纸数据。

3. 感知层:如何让CAD"听"懂指令?

语音转文字

  • 本地方案:Vosk、Whisper.cpp(离线、隐私安全)
  • 云端方案:讯飞、阿里云、Azure Speech-to-Text

文字到意图

  • 用LLM的函数调用(Function Calling)定义你的CAD工具集:
json 复制代码
{
  "name": "offset_faces",
  "description": "沿法线方向偏移指定物体的表面",
  "parameters": {
    "object_ids": ["string"],
    "distance_mm": "number"
  }
}
  • 提示词工程:告诉LLM"加粗"等价于offset_faces,距离为正表示向外。

4. 决策层:LLM如何拆解复杂指令?

ReAct模式原理

复制代码
Thought: 用户要求"加粗螺栓2mm"。我需要先找到所有螺栓。
Action: find_objects(label="bolt")
Observation: 返回了 [id1, id2, id3]
Thought: 找到了3个螺栓,现在执行偏移。
Action: offset_faces(object_ids=[id1,id2,id3], distance=2.0)
Observation: 偏移成功,无自交。
Thought: 任务完成,回复用户。
Answer: 已成功加粗3个螺栓。

LangChain实现

python 复制代码
from langchain.agents import initialize_agent, Tool
from langchain_openai import ChatOpenAI

tools = [
    Tool(name="find_objects", func=call_cad_find, description="根据标签查找物体"),
    Tool(name="offset_faces", func=call_cad_offset, description="偏移物体表面")
]
agent = initialize_agent(tools, ChatOpenAI(), agent="zero-shot-react-description")
agent.run("帮我把所有螺栓加粗2mm")

Coze实现:在Bot的工作流中,添加"大模型节点",配置提示词和输出格式,然后接"代码节点"调用HTTP插件。

防止幻觉

  • 给LLM提供"原子操作列表",禁止它发明新操作。
  • 要求LLM输出JSON Schema,并做校验。
  • 让LLM在行动前先"反思"(Self-ask)。

5. 接口层:如何安全地暴露CAD控制API?

技术选型

  • WebSocket(双向通信,适合长连接,可推送进度)
  • HTTP REST(简单,适合单次调用)
  • gRPC(高性能,适合内部微服务)

本地WebSocket示例(C++,使用websocketpp库)

cpp 复制代码
class CADWebSocketServer {
public:
    void on_message(websocketpp::connection_hdl hdl, message_ptr msg) {
        auto json = nlohmann::json::parse(msg->get_payload());
        if (json["action"] == "find") {
            auto ids = findObjectsByLabel(json["label"]);
            send(ids.dump());
        } else if (json["action"] == "offset") {
            offsetFaces(json["object_ids"], json["distance"]);
            send("{\"status\":\"ok\"}");
        }
    }
};

安全考虑

  • 只监听127.0.0.1,不暴露到公网。
  • 加上简单的Token验证(防止本地其他恶意程序调用)。
  • 限制请求频率,避免恶意循环。

6. 执行层:几何变换的细节

网格(STL)的偏移算法

  1. 遍历每个三角形,计算单位法线(归一化后的叉积)。
  2. 三个顶点分别沿法线移动:v' = v + normal * distance
  3. 注意:相邻三角形共享顶点,需要合并移动。做法:先收集所有受影响顶点的偏移量,再平均(或按面积加权)。
  4. 重新计算法线(用于光照)。
  5. 更新VBO,触发重绘。

精确几何(B-Rep)的偏移

  • Open CASCADE:BRepOffsetAPI_MakeOffset
  • 内部算法:沿法线方向偏移曲面,再裁剪、缝合。
  • 注意:偏移量过大会导致自交,需要检测并报错。

参数化建模(Code Interpreter模式)

  • 嵌入Python:用pybind11暴露C++类。
  • 安全沙箱:限制Python脚本的访问权限(文件、网络、CPU时间)。
  • 示例暴露函数:
cpp 复制代码
PYBIND11_MODULE(cad_api, m) {
    m.def("create_cylinder", &createCylinder, "半径", "高度");
    m.def("boolean_union", &booleanUnion, "两个形状");
}
  • 用户脚本:import cad_api; bolt = cad_api.create_cylinder(5, 20); ...

7. 零件语义化:让计算机认识"螺栓"

方案对比

方法 原理 优点 缺点
人工打标签 用户手动框选三角形 100%准确 费时
文件名/图层约定 按规则命名(如bolt_* 简单 依赖用户习惯
STEP语义 读取标准格式中的产品结构 工业标准 需要用户提供STEP而非STL
几何特征识别 基于曲率、厚度、螺纹特征 自动化 算法复杂,可能误判
深度学习分割 PointNet++等直接识别点云 前沿 需要训练数据,推理慢

你的项目实现 :混合策略。优先用STEP语义;如果没有,尝试基于文件名(如bolt.stl);再不行,让用户手动标记一次,保存标记结果到附属文件。

8. 进阶挑战深度解析

多模态交互:视觉定位

  • 实现"点击屏幕识别物体"的技术:ID Render Pass
    1. 正常渲染前,额外渲染一次"ID Pass":每个物体用唯一颜色(如物体索引映射为RGB)。
    2. 鼠标点击时,读取该像素的颜色,解码回物体ID。
    3. 将物体ID和截图一起发给多模态LLM,LLM就能理解"这颗"指的是ID。
  • GPT-4o的输入:[图像] + [鼠标坐标] + [文字],模型输出物体ID。

Code Interpreter的安全沙箱

  • 限制内存setrlimit(RLIMIT_AS, ...)
  • 限制CPU时间alarm()sandbox2
  • 限制模块导入 :重写__import__,只允许白名单模块
  • 隔离文件系统 :用chroot或Docker容器执行脚本
  • 参考:Google的Sandboxed API 、Python的RestrictedPython

性能优化

  • LLM推理延迟:用本地小模型(如Phi-3、Llama 3 8B)量化后,可在CPU上实时运行。
  • WebSocket消息:批量传输,减少往返。
  • 几何变换:对于大量物体,用OpenMP并行处理每个三角形的偏移。

9. 完整项目架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     用户界面 (语音/文字)                      │
└─────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────┐
│                   Coze / LangChain (控制端)                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ 感知层(NLP) │→│ 决策层(LLM) │→│ 规划与工具调用       │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                                │ WebSocket / HTTP
                                ▼
┌─────────────────────────────────────────────────────────────┐
│              你的 CAD C++ 程序 (执行端)                      │
│  ┌─────────────────────────────────────────────────────────┐│
│  │ 接口层: WebSocket Server, 解析JSON, 调用核心函数         ││
│  └─────────────────────────────────────────────────────────┘│
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │ 几何内核      │  │ 渲染管理器   │  │ Python解释器     │  │
│  │ (OCCT/自研)  │  │ (OpenGL)     │  │ (Code Interpreter)│  │
│  └──────────────┘  └──────────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────────────┘

10. 学习路线总结

  1. 入门:用Coze拖拽一个Bot,调用公开API(如天气查询),理解Agent概念。
  2. 进阶:用LangChain + OpenAI搭建本地Agent,实现"查找+偏移"两个工具。
  3. 实践:给你的CAD项目加上WebSocket接口,用Python脚本调用,实现"语音控制"。
  4. 深入:研究ReAct论文,自己实现一个简单的Agent循环(不用LangChain)。
  5. 精通:集成多模态模型、Code Interpreter沙箱,优化延迟和安全性。

你现在已经掌握了从零构建"CAD助手"的全部知识。剩下的就是动手写代码了。记住:AI不会取代CAD开发者,但会用AI的CAD开发者会取代不用AI的。


相关推荐
风象南2 小时前
AI Coding 进化史
人工智能
jinglong.zha2 小时前
AScript + Cursor:让 AI 直接操控你的设备,一句话完成自动化编程(源代码)
运维·人工智能·自动化·ascript·openclaw
企业架构师老王2 小时前
2026电力能源巡检进化论:如何基于企业级AI Agent构建非侵入式数据分析架构?
人工智能·ai·数据分析·能源
竹之却2 小时前
OpenClaw 2026.4.5版本更新详解
网络·人工智能·agent·openclaw
airuike1232 小时前
高性能MEMS IMU:重构无人机飞行控制核心
人工智能·算法·重构·无人机
恒者走天下2 小时前
手机行业cpp c++相关就业岗位详细汇总
c++
蕤葳-2 小时前
AI自动化办公的工具与工作流设计
人工智能
Thomas.Sir2 小时前
第6节:Function Calling深度剖析
人工智能·python·ai·functioncalling
学技术的大胜嗷2 小时前
YOLO细长目标检测中的多框分段现象解析:为什么检测容易多框,分割更容易连起来?
人工智能·yolo·目标检测·计算机视觉