码上拾光

审核规则为什么做成 DSL,而不是写死在代码里

· #架构#规则引擎#AI应用

今年做的第二个系统是工程图纸审核:图纸(扫描件、PDF、DWG)→ 模型抽取尺寸、公差、粗糙度、材料等要素 → 按规则审核 → 出问题清单。这篇不讲识别,讲规则。

规则是活的

上线前一周,客户给的规则文档改了四版。上线后每个月都有新规则。规则来自国标、行标、企业内部标准,还有”我们厂一直这么要求”的口头规则。

一开始规则写在代码里,一条规则一个方法。改一条就要发版,而且规则越多,方法之间的相互影响越难看清。三周后我停下来重做。

做成 DSL

规则表达成一段小语言,大概长这样:

when element.type == "linear_dimension"
 and element.tolerance is missing
 and element.value > 100
then issue("大于100的线性尺寸缺少公差", level="major")

字段(element.typeelement.tolerance)和函数(is missingissue)是有限集合。解析器很小,执行器也很小,难的不在这。

单一事实来源

难的是:字段和函数的清单在几个地方要用,怎么保证一致。

三个地方各维护一份,早晚会漂。我的做法是用反射从要素模型和函数注册表里生成这份清单,校验器、执行器、提示词都从同一个生成结果取。加一个字段,三处自动同步。

要素模型(代码) ──反射──► 字段清单 ──┬──► DSL 校验器
函数注册表(代码) ──反射──► 函数清单 ──┼──► DSL 执行器
                                     └──► 模型抽取提示词

这是整个规则模块里最值的一个决定。之后半年没出过”提示词里有、执行器里没有”这种事。

规则和要素的关系

还有一层:审核哪些要素是客户在管理页勾的。勾了”公差”才审公差相关规则,没勾就不审。审核引擎启动时按启用的要素动态装配规则集,禁用的要素对应的规则真的不参与,而不是跑了之后再过滤掉。这样客户关掉一个要素,速度也跟着快。

判据放哪

有些规则依赖国标里的表格,比如一般公差按尺寸段查表。这类判据不放规则里,放领域层的常量表,规则里只写”查表”。表改了规则不用改,规则改了表不用动。

代价

DSL 的代价是多了一层学习成本——客户的工程师要学这套写法。实际情况是他们不学,他们把规范文档丢过来,让模型抽。这就引出了下一篇要写的问题:模型抽出来的规则能不能直接上线。


← 回到文章列表