目录 CONTENTS
2. 背景与问题定义:从“能不能跑”到“对不对”
3. 失效机理:沉默几何错误的四类成因
4. 技术路线:几何语义保真度的分层拦截架构
5. 关键数据与案例:公开基准与工程观测
6. 对比与局限:五层拦截的边界条件
7. 结论与展望:从“生成”走向“可验证生成”
8. 主要参考文献
1. 导语:一个被低估的失效面 OVERVIEW
在讨论 LLM 写代码时,社区最熟悉的失败场景是“跑不起来”:语法错误、API 不存在、依赖缺失。这类失败是显性的,反馈即时,修复路径清晰。但当我们把场景切换到 CAD(Computer-Aided Design,计算机辅助设计)建模代码——例如 OpenSCAD、CadQuery、FreeCAD 的 Python API、AutoCAD 的 AutoLISP 或 .NET API——失效的性质发生了根本变化。
一段 CAD 脚本可以顺利通过解释器、成功生成实体、在默认视角下渲染出一张“看起来像那么回事”的图,然后在你把模型交给下游做布尔运算、抽壳、网格化或导出 STEP 时,暴露出自相交、非流形边、零厚度面、法向翻转等问题;更糟的是,某些内核在遇到退化几何时不会报错,而是静默产生错误结果,或者在用户后续编辑操作时直接崩溃、写坏文件。这类问题本文统称为“沉默的几何错误”(silent geometric error)。
需要强调的是,这不是一个纯学术的假想问题。随着 LLM 辅助建模工具(文本到 CAD、自然语言驱动参数化建模)进入真实设计流程,生成代码的“可信度”直接决定了下游制造、仿真、装配的可靠性。一个尺寸偏差 0.2 mm 的孔位,在渲染图里看不出来,在装配时就是干涉。本文试图把这个问题拆解到机制层面,并给出可执行的拦截方案。
2. 背景与问题定义:从“能不能跑”到“对不对” PROBLEM
2.1 CAD 代码的特殊性
与通用业务代码不同,CAD 代码的输出不是数据记录或界面状态,而是一个边界表示(BRep)或构造实体几何(CSG)树所定义的几何体。它的正确性至少包含三个层次:
LLM 在语法层的表现已经相当可观,但几何层与语义层的正确性信号在训练数据中极为稀疏。一段 OpenSCAD 代码“能跑”,只说明语法层通过;它是否真的构造出了设计者想要的形状,需要额外的几何验证。这正是本文关注的缺口。
2.2 为什么“看起来对”具有欺骗性
渲染是几何的“投影”,不是几何本身。一个自相交的壳体在默认视角下可能渲染得完全正常,因为光栅化管线只关心可见表面的深度与着色,不检查流形性。同理,法向翻转的实体在双向光照下也可能“看起来没问题”。这意味着以渲染图或截图作为评测信号,会系统性地高估生成质量。
2.3 问题形式化
设用户意图为 I,LLM 生成的代码为 C,CAD 内核执行 C 得到的几何对象为 G = K(C)。几何语义保真度可定义为:
GSF(C, I) = f( d_geo(G, G*), d_topo(G, G*), d_sem(G, G*) ) 其中 G* 为意图 I 对应的参考几何; d_geo 度量尺寸/位置偏差,d_topo 度量拓扑不变量差异, d_sem 度量工程语义(装配、公差、可编辑性)偏差。
沉默几何错误即:C 通过语法检查,但 GSF 低于可接受阈值,且系统未发出任何告警。拦截的目标,就是把这类“低 GSF 且无告警”的样本比例压到可控范围。
3. 失效机理:沉默几何错误的四类成因 MECHANISM
3.1 成因一:训练语料中几何正确性信号稀疏
LLM 从海量代码中学习“什么样的代码像 CAD 代码”。但代码文本本身并不携带“这段代码构造的几何是否合法”的标签。GitHub 上的 OpenSCAD 或 CadQuery 片段,很多是示例、草稿或从未被下游验证过的玩具模型。模型学到的是表面模式(surface pattern):常见的函数组合、参数写法、注释风格,而不是几何约束的满足关系。
更微妙的是,几何正确性往往依赖参数取值。同一段参数化脚本,在 wall=2 时合法,在 wall=0.5 时可能产生零厚度面。模型没有“参数边界”的概念,它只是续写文本。
3.2 成因二:API 语义与几何语义错位
CAD API 的命名往往描述“操作”,而非“几何后果”。例如布尔差运算 cut(a, b),在 b 与 a 表面恰好相切时,不同内核的行为差异巨大:有的产生退化面,有的静默丢弃,有的抛异常。模型在语料中看到的是“调用成功”的示例,学不到这些边界行为。
这张表并非穷举,而是说明一个结构性事实:API 层的“成功返回”与几何层的“合法构造”之间没有必然联系。模型学的是前者,工程需要的是后者。
3.3 成因三:内核状态机与事务边界缺失
“编译通过后用户一操作模型文件直接损坏”这一现象,指向的是内核的事务性问题。主流几何内核(如 OpenCASCADE、Parasolid、ACIS)在构造复杂实体时,内部维护拓扑数据结构与引用计数。若脚本在构造中途产生非法中间态(例如悬空边、未闭合壳),而调用方没有在事务边界内回滚,后续的用户编辑操作可能在这个非法状态上继续施加变换,最终写出的文件在重新打开时无法修复。
# 伪代码:缺失事务边界的危险模式
doc = open_document()
body = doc.add_body()
shape = build_complex_shape() # 可能产生非法中间态
body.set_shape(shape) # 未校验即写入
doc.save("model.step") # 非法状态被持久化
正确的做法是把“构造—校验—提交”放进显式事务:构造阶段在临时容器中进行,校验通过后再原子地替换目标 body;任何一步失败则丢弃临时对象。这一模式在数据库领域是常识,在 CAD 脚本生成领域却常被忽略,因为 LLM 生成的代码倾向于“线性直写”,缺少防御性结构。
3.4 成因四:评测指标与真实风险脱节
当前公开的文本到 CAD 评测,多数以“生成代码能否执行”“渲染图与参考图的视觉相似度”“点云 Chamfer 距离”为主。这些指标对“沉默几何错误”的检出率有限。一个拓扑错误但外形接近的模型,可能在 Chamfer 距离上得分很高;一个自相交实体,在单视角渲染下可能完全正常。
指标脱节的后果是反馈回路失真:模型在错误的方向上被奖励。要打破这个回路,需要把几何合法性指标(流形性、自相交、体积符号、欧拉示性数等)纳入评测主表,而不是作为附录。
4. 技术路线:几何语义保真度的分层拦截架构 ARCHITECTURE
基于上述四类成因,本文提出五层拦截架构。它的设计原则是:越靠前的层成本越低、越靠后的层覆盖越全;每层都输出可记录的信号,形成可回归的测试资产。
4.1 L1 约束化提示:把几何约束前置
提示工程在几何场景下不应停留在“请生成 OpenSCAD 代码”。有效的做法是把可判定的约束显式写入系统提示与模板:单位制、最小壁厚、布尔运算前的实体合法性要求、禁止零厚度面、参数取值范围。更进一步,可以要求模型在生成代码时同时输出一份约束清单(constraint manifest),列出它认为满足的几何条件,供后续层核对。
{
"units": "mm",
"min_wall_thickness": 1.2,
"boolean_precondition": "operands must be closed manifolds",
"forbidden": ["zero_thickness_face", "self_intersection"],
"param_ranges": {"hole_d": [3, 12], "wall": [1.2, 5]}
}
这份清单的价值不在于模型一定遵守,而在于它把“隐式期望”变成了“显式契约”,让 L2 的断言有据可依。
4.2 L2 几何断言:代码内嵌可执行检查
在生成的脚本中注入断言,是最直接、成本最低的拦截手段。以 CadQuery 为例,可以在关键构造后插入体积、包围盒、面数、流形性检查:
import cadquery as cq
part = cq.Workplane("XY").box(40, 30, 10).faces(">Z").workplane() \
.hole(6)
solid = part.val()
assert solid.isValid(), "invalid BRep"
assert abs(solid.Volume() - expected_volume) < 1e-3 * expected_volume
bb = solid.BoundingBox()
assert bb.xlen > 0 and bb.ylen > 0 and bb.zlen > 0
assert len(solid.Faces()) >= 6, "suspiciously few faces"
断言的关键是选择与几何语义强相关的量:体积符号(负体积意味着法向翻转)、包围盒尺寸、面/边/顶点计数、欧拉示性数。这些量对拓扑错误敏感,且计算成本低。
4.3 L3 差分测试:参数扰动下的稳定性
参数化模型的价值在于可编辑。一个在默认参数下合法、但在参数边界附近崩溃的脚本,是典型的“定时炸弹”。差分测试的思路是:对每个参数在其声明范围内做网格采样或随机采样,重新执行构造与断言,观察几何量是否连续、是否出现异常跳变。
上表的采样规模为示意,实际工程中可按参数敏感度自适应加密。差分测试的副产品是一张“参数安全区间”图,可以直接反馈给用户,提示哪些参数组合是危险的。
4.4 L4 拓扑不变量校验:抓住“结构错”
几何量(体积、包围盒)对“形状偏差”敏感,但对“拓扑错误”可能不敏感。一个自相交实体,体积可能仍然接近期望值。拓扑不变量校验补充这一维度:
- 流形性:每条边恰好被两个面共享;非流形边是下游布尔运算与网格化的常见崩溃源。
- 闭合性:壳是否闭合,是否存在边界边(boundary edge)。
- 欧拉示性数:对闭合可定向曲面,V − E + F = 2 − 2g(g 为亏格)。与预期亏格不符,说明孔洞数量或连通性出错。
- 法向一致性:相邻面法向是否连续,体积符号是否为正。
这些检查在 OpenCASCADE 等内核中有现成接口(如 BRepCheck_Analyzer),工程上应把它们封装成统一的校验函数,作为提交前的强制关卡。
4.5 L5 内核级沙箱:隔离与事务回滚
最后一层是执行环境的隔离。生成代码在独立进程或容器中执行,设置资源上限(内存、CPU 时间、文件大小),并强制事务语义:构造在临时文档中进行,校验通过后才原子提交到目标文件。任何异常或校验失败都触发回滚,目标文件保持不变。
def safe_build(code, target_path):
tmp = temp_document()
try:
exec_in_sandbox(code, tmp) # 隔离执行
shape = tmp.result()
assert_geometry(shape) # L2 + L4 校验
atomic_replace(tmp, target_path) # 原子提交
except Exception as e:
tmp.discard() # 回滚
raise BuildRejected(e)
沙箱还承担一个隐性职责:把“崩溃”转化为“可捕获的失败”。内核级崩溃(段错误、断言失败)在进程内无法安全恢复,只有隔离到子进程才能既保护主流程,又留下崩溃现场用于分析。
5. 关键数据与案例:公开基准与工程观测 METRICS
5.1 公开基准的现状
文本到 CAD 方向已有若干公开工作与数据集。DeepCAD(Wu 等,2021)提供了大规模 CAD 序列数据与生成基线;SkexGen(Xu 等,2022)关注草图与拉伸的联合生成;Text2CAD(2024)探索以自然语言驱动参数化 CAD 序列生成;CAD-MLLM、CAD-Llama 等工作尝试把多模态大模型与 CAD 命令序列对齐。这些工作推动了“生成”能力,但评测仍以命令序列匹配、点云距离、渲染相似度为主。
5.2 工程观测:失效分布的经验画像
以下数据为笔者在公开代码语料与自建测试集上的整合观测(模拟数据,用于说明分布形态,非某单一实验的统计结论),不作为任何官方基准引用:
这张表的核心信息不是具体百分比,而是分布形态:超过一半的失效不是“跑不起来”,而是“跑起来了但不对”,且需要不同层级的检查才能覆盖。这从经验上支持了分层拦截的必要性。
5.3 一个典型的沉默失效案例
考虑一个常见的“带孔法兰”生成任务。模型生成的脚本在默认参数下体积正确、渲染正常。但当用户把孔径调到接近法兰外径时,孔壁与外缘之间的壁厚趋近于零,内核产生退化面。此时体积断言仍然通过(退化面体积贡献接近零),渲染也看不出异常,直到下游做抽壳或导出网格时失败。
这个案例说明:单一断言不足以覆盖所有失效。体积断言 + 最小壁厚检查 + 差分测试的组合才能拦住它。最小壁厚检查在工程上可通过采样面间距离或使用内核的厚度分析接口实现。
6. 对比与局限:五层拦截的边界条件 LIMITS
6.1 与“更大模型”路线的对比
两条路线不是互斥的。分层拦截提供的是底线保障,更大模型提升的是一次通过率。工程上应先建底线,再谈提升。
6.2 局限一:断言与不变量的不完备性
任何有限检查集都无法覆盖全部几何失效。体积、包围盒、欧拉示性数能抓住常见错误,但对“形状偏差在容差内、语义完全错误”的情况无能为力。例如一个孔位偏移 0.1 mm,所有拓扑检查通过,但装配时干涉。这类问题需要语义级校验,而语义级校验依赖对设计意图的建模,目前仍是开放问题。
6.3 局限二:内核差异带来的可移植性问题
同一段脚本在不同内核(OpenCASCADE、Parasolid、ACIS)下可能产生不同结果,尤其是在相切、共面、容差边界附近。断言中硬编码的阈值可能在一个内核下合适、在另一个内核下误报。工程上需要把阈值参数化,并按内核配置基线。
6.4 局限三:性能与吞吐
差分测试与拓扑校验都有计算成本。对交互式场景(用户等待生成结果),全量五层检查可能过慢。可行的折中是分级触发:交互时只跑 L1–L2 的轻量检查,提交/导出时跑全量 L3–L5。这需要工具链支持检查级别的配置。
7. 结论与展望:从“生成”走向“可验证生成” OUTLOOK
沉默的几何错误之所以危险,是因为它绕过了开发者最依赖的反馈信号——编译与渲染。本文的分析主线“几何语义保真度”试图把这一隐性问题显性化:把“看起来对”拆解为可度量的几何、拓扑、语义三个维度,并用五层拦截架构把度量嵌入工程流程。
从工程实践看,最值得立即投入的是 L2 断言与 L5 沙箱:前者成本低、覆盖常见尺寸与合法性错误;后者把崩溃与文件损坏隔离在可回滚的边界内。L3 差分与 L4 拓扑不变量则需要与具体内核和业务场景结合,逐步沉淀为团队资产。
最后需要强调:拦截体系的目标不是“零错误”,而是“错误可见、可回滚、可回归”。把沉默失效转化为显性失败,本身就是巨大的工程进步。
8. 主要参考文献 REFERENCES
[1] Wu R, Xiao C, Zheng C. DeepCAD: A Deep Generative Network for Computer-Aided Design Models. ICCV, 2021.
[2] Xu X, Willis K D D, Lambourne J G, et al. SkexGen: Autoregressive Generation of CAD Construction Sequences with Disentangled Codebooks. ICML, 2022.
[3] Khan M S, et al. Text2CAD: Generating Sequential CAD Models from Textual Prompts. NeurIPS, 2024.
[4] Wang Y, et al. CAD-MLLM: Unifying Multimodality-Conditioned CAD Generation. arXiv, 2024.
[5] OpenCASCADE Technology. BRepCheck_Analyzer Documentation. OpenCASCADE, 2023.
[6] CadQuery Development Team. CadQuery Documentation: Workplane and Assembly API. 2024.
[7] Willis K D D, et al. Engineering Sketch Generation for Computer-Aided Design. CVPR Workshops, 2021.
[8] ParaSolid / ACIS 几何内核容差与布尔运算行为说明,Siemens / Spatial 技术文档,2023。
[9] 本文整合观测数据为模拟数据,用于说明失效分布形态,不构成官方基准结论。

