◈本体论工程手册
实证

十 · 技术栈分层与选型框架

L0–L5 六层模型与决策树

选型的困难不在「哪个项目好」,而在「我现在缺的是哪一层」。这一章把语义栈拆成六层,每层给出职责、候选、自建还是采购的判据、以及最常见的失败方式;然后给三种典型团队的完整架构。

六层模型

层职责候选建议
L0 数据源系统,权威值的所在核心、ERP、CRM、湖仓不自建,只能接
L1 存储三元组/图/属性图的持久化与查询rdflib、Jena+TDB2、Oxigraph、Neo4j、TerminusDB按查询形态选,不按「是不是图」选
L2 模型语义的单一源与多目标编译LinkML、Protégé(分析用)、YAML+Turtle必须自建,这是你唯一的资产
L3 校验与推理拒绝坏数据;推出隐含事实pySHACL、SHACL-AF、OWL-RL、ELK、Reasonable校验必买/必用,推理按需
L4 语义服务查询、API、虚拟化、检索Fuseki、Ontop、GraphQL、向量库按消费方式选
L5 消费BI、Agent、应用、动作自建必须自建,这是价值所在

三层关键判断先说结论:

  • L0 与 L1 是「别人的地盘」,你的技术决策只影响接入成本,不影响成败。
  • L2 与 L3 是「你的护城河」,这里的投入直接决定三年后这份资产是能用还是能删。
  • L5 是「唯一能被业务看见的层」,所有其他层的价值都要在这一层兑现,否则等于零。

L0:数据层

这一层看起来没什么可选的——源系统就在那里。但有两个决定会长期影响上层:

一、权威值是单源还是多源。 同一个客户名在两个系统里都说是权威,这个矛盾不会在上层消失,只会被推到上层并放大。做法:给每个关键字段标注权威源,冲突时以权威源为准,差异进对账队列(细节见第六章的状态所有权三分法)。

二、主键是否稳定。 如果源系统的主键会变(重组、迁移、重新编号),那么上层所有引用都会断。做法:在 L0 与 L1 之间加一层「永久 ID 映射」,永久的那个 ID 由你治理。

L1:存储层

选型的实际问题是三个,不是一个:

问题一:需要事务与持久化吗? 不需要 → rdflib(内存)。需要 → Jena TDB2、Oxigraph、图库。

问题二:查询形态是什么? 以「多跳路径 + 聚合」为主 → 属性图(Cypher 更省事)。以「模式匹配 + 联邦」为主 → SPARQL。以「时序回溯」为主 → 需要版本化存储(TerminusDB、或自己在属性图上加双时态)。

问题三:需要推理吗? 需要 → 优先选支持推理或能挂推理机的 RDF 存储。不需要 → 属性图几乎总是更省事。

三个不该犯的错:

  • 用内存图当生产库。 rdflib 没有优化器,也没有并发控制,它适合脚本与测试。
  • 把「图」当成「语义」。 图数据库给你的是存储与查询,不是类型与约束。
  • 忽略许可。 三家常被推荐的内存图库里,两家用的是源码可用许可。

L2:模型层——唯一必须自建的资产

这一层的产物不是软件,是你自己的语义。所以要选的不是「哪个工具最好」,而是「用什么格式承载它,十年后还能读」。

三个要求,按重要性排序:

  1. 人可读、可 diff。 纯文本,能进 git,能在 PR 里 review。
  2. 可编译。 一份源能生成 JSON Schema、SQL DDL、OWL、SHACL、文档。
  3. 不绑定工具。 换一个编辑器不需要重写模型。

符合这三条的现实选择只有两类:YAML 系的建模语言(LinkML 一类,自带 41 个生成器模块)与Turtle 手写 + 脚本生成(成本更高,但完全可控)。

一个反直觉的建议:Protégé 不要当源,当分析工具。 它在检查分类是否合理、公理是否矛盾上无可替代,但它的工程文件不可 diff、不可编译、不可被其他工具消费。正确用法是「导入模型 → 分析 → 把结论写回源文件」。

L3:校验与推理——一个必用,一个慎用

校验必用。 没有校验的语义层只是文档。要求三条:可执行、有非零退出码、在写入或合并路径上。pySHACL 是最省事的选择:覆盖 SHACL Core + SPARQL + Advanced Features,退出码明确。

推理慎用。 它不报错、耗时不可预测、诊断信息对业务方无意义(第四、十章有实测)。合理的位置是构建期(检查建模错误)、或查询期(OBDA 下推),不要放在写入路径。

一个必须知道的能力边界:OWL 2 RL 推不出「至少一个」这类约束,而它恰恰是业务里最常见的约束。这类需求归校验层,不归推理层。

L4:语义服务层

按消费方式分四种,选一种就够,别混:

消费方式形态工具
人查SPARQL 端点 + 可视化查询器Fuseki、Sparnatural
应用调REST/GraphQL API自建薄层,别直接暴露 SPARQL
不搬数据OBDA 虚拟化Ontop(+ R2RML 映射)
模型检索向量 + 图混合图库 + 向量索引

第三条(OBDA)在第九章被判为「最被低估的一条」,理由很实际:它把「建语义层」从「重建数据资产」降级为「写一份映射」。代价是映射错了不报错,所以必须配对账。

L5:消费层——价值兑现的地方

这一层没有现成工具,因为它就是你的业务。它决定前面四层是资产还是负债。

两条设计原则:

一、先做一个能演示的闭环,再做平台。 一个闭环 = 一类对象 + 五条约束 + 一次可拒绝的动作 + 一张能对账的报表。这个闭环能在两周内做出来,并且能让业务方当场看到「坏数据被挡住了」。

二、动作要在这一层,规则要在 L2/L3。 动作的声明(参数、前置条件、副作用、权限)是 L5 的事,但前置条件的实现必须落到 L3 的约束上。否则规则会分裂成两套:一套在模型里、一套在代码里,然后慢慢不一致。

三种典型架构

A. 小团队(1–3 人,一个业务域,两周出结果)

L0 关系库(不动)
L1 不引入图库 —— 直接用关系库 + 视图
L2 YAML 模型(十几类)  ← 唯一新建
L3 pySHACL(对导出数据跑)
L4 不建端点 —— 生成 SQL 视图供 BI 用
L5 一张对账报表 + 一份违规清单

要点:不引入新的存储与端点。语义层以「生成的 SQL 视图 + 校验流水线」形态存在,业务方无感知,但口径统一了。这是投入产出比最高的形态。

B. 中型(一个平台组,3–8 人,多业务域)

L0 多个源系统 + 永久 ID 映射
L1 三元组库(Jena TDB2 或 Oxigraph)或属性图
L2 LinkML 一类编译器 → OWL + SHACL + DDL + 文档
L3 CI 里跑 SHACL + 一致性检查;构建期跑 ELK
L4 Fuseki(内部查询)+ REST API(应用)
L5 一个业务应用 + 一个 Agent 上下文接口

要点:L2 的编译器是核心投资。它让「改模型」变成「改 YAML 提 PR」,而不是「找人改图」。

C. 受监管(有审计要求,10 人以上)

L0 源系统 + 双写对账
L1 带版本的存储(TerminusDB 或自建双时态)
L2 编译器 + 变更影响面计算
L3 SHACL(三档严重级别 + 带期限豁免)+ 策略版本化
L4 端点 + 动作网关(所有写入经动作)
L5 审计台(who/what/when/why/result 五字段)+ 对账任务

要点:写入必须经动作,动作必须留五个字段的审计,审计必须能回答「当时生效的策略是什么」。这三件事任缺一件,架构 C 就退化成 B。

三件不该做的事

不要先建全量本体。 「先把整个企业的概念梳理清楚再动手」是这类项目最常见的死法。正确顺序是反的:先用一个小域跑通闭环,再抽公共部分。

不要为推理而推理。 如果没有一个具体的、业务真的会问的「能不能推出」问题,推理层就是纯成本。

不要在建校验之前建可视化。 漂亮的图会让人以为工作完成了,而它通常是唯一没有下游消费者的产物。

成本的一个粗估

按人力月计(不含硬件):

形态首版稳态维护主要成本项
A 小团队0.5–1 人月0.2 人月/月模型 + 校验
B 中型3–5 人月1 人月/月编译器 + CI + 端点
C 受监管8–15 人月2–3 人月/月动作网关 + 审计 + 对账

稳态维护成本是最容易被低估的一项,也是决定项目能否活过第二年的关键。如果拿不出「每月一人月」的维护预算,就不要做 B 或 C——做 A,并且接受它的能力上限。