AI时代的数据本体:从一张订单到Ontology
大模型读过很多数据,却未必认识你的业务。它知道“订单”这个词,却不知道你们公司的订单究竟承诺了什么。
前段时间重新梳理 RAG 和 Agent 的数据链路时,我碰到一个看起来很朴素的问题:供应商发来一封邮件,说某批轴承要延期三天,系统能不能顺着这条消息找出受影响的生产工单、产品、销售订单和客户,再给出下一步建议?
只做文档问答不难。按照之前整理的 RAG 混合检索 那套办法,把邮件放进向量库,问“哪个零件延期”,大概率可以答出来。难的是后半句:这批零件对应哪个物料编码,哪些工单依赖它,工单又在生产什么产品,哪些客户订单正等着这些产品?这些关系散落在采购系统、ERP、MES、CRM 和几张 Excel 里,模型不能靠“读起来像”把它们猜出来。
这正是 Ontology(本体) 重新被翻出来的背景。放在数据工程语境下,它也常被叫作“数据本体”——一套描述业务世界里有哪些对象、它们如何关联、哪些规则成立的显式模型。
名字听着有点哲学,做起来却很工程。这里不打算从定义背诵开始,直接搭一个小型制造业 Ontology,看看它到底比数据库 Schema 和普通知识图谱多了什么,又能为 AI Agent 补上哪块短板。
一封邮件找得到,影响链却找不到
假设一家制造企业同时运行着几套系统:
- 采购系统记录供应商、采购单和预计到货时间;
- ERP 保存物料、库存和销售订单;
- MES 管生产工单、产线和工艺;
- CRM 里有客户及交付承诺;
- 邮件和群聊里还有大量尚未进入系统的变化。
每套系统的数据都可能是对的,放到一起却不一定能直接说话。采购系统里的 bearing_a、ERP 里的 MAT-0018 和邮件里的“A 型主轴轴承”,可能指的是同一种零件。销售口中的“订单”是客户承诺,生产部门口中的“订单”却常常是生产工单。
数据库可以保证 material_id 是字符串、delivery_date 是日期,也能靠外键连接两张设计良好的表。但它不会天然告诉另一个系统:
MAT-0018和“A 型主轴轴承”是同一个现实对象;- 生产工单“需要”零件,销售订单“包含”产品,这两个关系语义不同;
- 如果一个工单生产某产品,而订单包含这个产品,那么零件短缺可能沿这条链影响订单;
- “建议调整排产”和“直接修改排产”是权限完全不同的动作。
这些知识当然可以写进 SQL、服务代码和操作手册。现实里也确实如此。麻烦在于,它们会被分别写很多遍,最后没有一处能完整回答“我们把这个业务世界理解成什么样”。
先画出制造企业的这个小世界
我们先不碰 RDF 和 OWL,只画出本次问题需要的对象:
图很小,却已经暴露出几个有用的约定:供应商和客户都是组织,但扮演的业务角色不同;产品和零件可能都来自同一张物料表,在这个问题里却承担不同含义;工单与订单各自承担不同业务含义,光看中文名称相似就合并会出问题。
假设现在有下面几条具体事实:
- “华东精密”供应“轴承 A”;
- 生产工单
WO-0312需要“轴承 A”; - 该工单生产“工业泵 P100”;
- 销售订单
SO-8848包含“工业泵 P100”; - 客户“远海能源”提交了这张销售订单。
当轴承 A 延期时,影响链就是:
轴承 A → WO-0312 → 工业泵 P100 → SO-8848 → 远海能源
这条链没有什么神秘算法。真正重要的是每条边都有稳定、明确的业务含义,系统不必临时让大模型猜“需要”“生产”“包含”是不是同一种关系。
这张图就是 Ontology 吗
还不能这么说。
Ontology 的经典解释是“对共享概念模型的形式化、显式说明”。翻成人话,可以拆成四个词:
- 概念:这个领域里存在供应商、零件、工单、产品等对象;
- 关系:工单需要零件,订单包含产品;
- 规则:
requires的起点应该是工单,终点应该是零件; - 共享:这些定义不是某个开发者脑中的临时理解,而是人和软件共同采用的约定。
有几个经常被混在一起的概念,可以先划一下边界:
| 概念 | 主要回答的问题 | 制造业例子 |
|---|---|---|
| Taxonomy 分类体系 | 谁属于哪一类 | 轴承属于机械零件 |
| Schema 数据模式 | 一条数据长什么样 | 工单必须有编号和状态 |
| Knowledge Graph 知识图谱 | 当前有哪些对象和关系 | WO-0312 需要轴承 A |
| Ontology 本体 | 对象和关系意味着什么,哪些规则成立 | requires 连接工单与零件 |
| Semantic Layer 语义层 | 上层应用怎样用统一口径访问数据 | “准时交付率”的统一定义 |
边界并非绝对。实际项目中的知识图谱经常自带 Schema,语义层也可能使用 Ontology,轻量本体看起来甚至就是一棵分类树。这里不是为了争论术语,而是提醒自己:把节点和边存进图数据库,只说明数据成了图;业务含义有没有被认真建模,还得另说。
用三元组写下业务事实
语义 Web 体系常用 RDF 表达事实。RDF 的基本结构是三元组:
主语 Subject → 谓词 Predicate → 宾语 Object
例如:
WO-0312 → requires → 轴承 A
Turtle 是 RDF 的一种文本写法,比 RDF/XML 更适合人读。把前面的事实写出来,大概是这样:
@prefix mfg: <https://example.com/mfg/> .
mfg:eastPrecision
a mfg:Supplier ;
mfg:name "华东精密" ;
mfg:provides mfg:bearingA .
mfg:bearingA
a mfg:Component ;
mfg:name "轴承 A" .
mfg:workOrder0312
a mfg:WorkOrder ;
mfg:orderNo "WO-0312" ;
mfg:requires mfg:bearingA ;
mfg:produces mfg:pumpP100 .
mfg:salesOrder8848
a mfg:SalesOrder ;
mfg:orderNo "SO-8848" ;
mfg:contains mfg:pumpP100 ;
mfg:placedBy mfg:oceanEnergy .
mfg:oceanEnergy
a mfg:Customer ;
mfg:name "远海能源" .
mfg:workOrder0312 是一个可唯一识别的资源,a mfg:WorkOrder 表示它属于生产工单类型,mfg:requires 则把它连接到轴承 A。这里的名称、编号和关系都可以追溯到原始系统,比只保存一段模型描述可靠得多。
三元组很灵活,但灵活也意味着容易失控。今天有人写 requires,明天有人写 needs,后天模型又生成 depend_on;“轴承 A”和 MAT-0018 被创建成两个节点,查出来的图很热闹,实际影响链却断了。
所以 RDF 负责表达事实,还需要 Ontology 规定这些词怎样使用。
用 OWL 给关系划出边界
OWL 是 W3C 定义的本体语言。一个最小版本可以先声明类和对象属性:
@prefix mfg: <https://example.com/mfg/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
mfg:Supplier a owl:Class .
mfg:Component a owl:Class .
mfg:WorkOrder a owl:Class .
mfg:Product a owl:Class .
mfg:SalesOrder a owl:Class .
mfg:Customer a owl:Class .
mfg:provides
a owl:ObjectProperty ;
rdfs:domain mfg:Supplier ;
rdfs:range mfg:Component .
mfg:requires
a owl:ObjectProperty ;
rdfs:domain mfg:WorkOrder ;
rdfs:range mfg:Component .
mfg:produces
a owl:ObjectProperty ;
rdfs:domain mfg:WorkOrder ;
rdfs:range mfg:Product .
mfg:contains
a owl:ObjectProperty ;
rdfs:domain mfg:SalesOrder ;
rdfs:range mfg:Product .
这里的 domain 和 range 很容易被数据库经验带偏。它们在 OWL/RDFS 中首先承担推理语义,数据校验只是附带能力。
如果图中只有:
mfg:workOrder0312 mfg:requires mfg:bearingA .
结合上面的定义,推理器可以推出 workOrder0312 是 WorkOrder,bearingA 是 Component。如果错误地让一个客户 requires 某零件,系统也未必像数据库约束那样立刻拒绝;它可能推断这个客户同时还是一张生产工单。只有再声明两类互斥,才可能检测到逻辑不一致。
这是 Ontology 与传统 Schema 一个很关键的思维差异。OWL 通常采用开放世界假设:图里没有某个事实,只代表“目前不知道”,不能直接判定它为假。数据库业务校验更习惯封闭世界:必要字段没出现,就按不合格处理。
数据是否合格,交给 SHACL 来检查
如果我们真正想检查“每张生产工单至少需要一种零件”,SHACL 更直接:
@prefix mfg: <https://example.com/mfg/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
mfg:WorkOrderShape
a sh:NodeShape ;
sh:targetClass mfg:WorkOrder ;
sh:property [
sh:path mfg:requires ;
sh:minCount 1 ;
sh:class mfg:Component ;
sh:message "生产工单至少需要一种有效零件"
] .
这段 Shape 会检查所有 WorkOrder:requires 至少出现一次,而且目标是 Component。工程上可以把它放进数据导入或发布流程,错误数据先进入隔离区,不要静悄悄污染整张图。
简单记一下分工:
- RDF 负责写下事实;
- RDFS/OWL 负责表达概念、关系及可推导语义;
- SHACL 负责验证实际数据是否符合预期形状;
- SPARQL 负责查询图中的事实和关系。
它们可以配合使用,但没有规定每个 Ontology 项目都必须把这套工具全上齐。很多业务只需要受控词汇、少量关系和数据校验,硬上复杂逻辑反而让团队没人敢改。
写一条查询,找出延期影响链
现在假设邮件解析模块已经把“轴承 A 延期”映射到统一资源 mfg:bearingA,接下来可以用 SPARQL 查询受影响对象:
PREFIX mfg: <https://example.com/mfg/>
SELECT ?workOrder ?product ?salesOrder ?customer
WHERE {
?workOrder mfg:requires mfg:bearingA ;
mfg:produces ?product .
?salesOrder mfg:contains ?product ;
mfg:placedBy ?customer .
}
查询路径完全显式:从需要轴承 A 的工单出发,找到工单生产的产品,再找到包含该产品的销售订单和下单客户。
这段代码可以用 Python 的 rdflib 跑起来:
from rdflib import Graph, Literal, Namespace, RDF
MFG = Namespace("https://example.com/mfg/")
graph = Graph()
graph.bind("mfg", MFG)
# 类型和名称
graph.add((MFG.workOrder0312, RDF.type, MFG.WorkOrder))
graph.add((MFG.workOrder0312, MFG.orderNo, Literal("WO-0312")))
graph.add((MFG.bearingA, RDF.type, MFG.Component))
graph.add((MFG.pumpP100, RDF.type, MFG.Product))
graph.add((MFG.salesOrder8848, RDF.type, MFG.SalesOrder))
graph.add((MFG.oceanEnergy, RDF.type, MFG.Customer))
graph.add((MFG.oceanEnergy, MFG.name, Literal("远海能源")))
# 对象之间的关系
graph.add((MFG.workOrder0312, MFG.requires, MFG.bearingA))
graph.add((MFG.workOrder0312, MFG.produces, MFG.pumpP100))
graph.add((MFG.salesOrder8848, MFG.contains, MFG.pumpP100))
graph.add((MFG.salesOrder8848, MFG.placedBy, MFG.oceanEnergy))
query = """
PREFIX mfg: <https://example.com/mfg/>
SELECT ?workOrder ?product ?salesOrder ?customer ?customerName
WHERE {
?workOrder mfg:requires mfg:bearingA ;
mfg:produces ?product .
?salesOrder mfg:contains ?product ;
mfg:placedBy ?customer .
?customer mfg:name ?customerName .
}
"""
for row in graph.query(query):
print(
row.workOrder.split("/")[-1],
row.product.split("/")[-1],
row.salesOrder.split("/")[-1],
row.customerName,
)
安装依赖后运行:
pip install rdflib
python ontology_demo.py
输出如下:
workOrder0312 pumpP100 salesOrder8848 远海能源
普通 SQL 当然也能完成这次查询。如果数据都在同一个关系模型里,关系稳定、维护团队一致,SQL 可能还是更省事的选择。Ontology 真正的价值,是把跨系统反复使用的对象、关系和规则从某条 SQL 里提出来,变成可共享、可治理、可被多种应用复用的语义资产。
LLM 和 Agent 在这条链路里做什么
有了 Ontology,大模型仍然得留着——两边擅长的问题不一样。
供应商可能在邮件里写:
A 型主轴轴承这周赶不上原计划,预计顺延三个工作日。
这段话没有物料编码,也不是规整表格。LLM 擅长从中提取候选实体、事件和时间:
{
"event": "supplier_delay",
"component_name": "A型主轴轴承",
"delay_days": 3,
"unit": "working_day"
}
但它不应该直接断言“A 型主轴轴承就是 bearingA”。更稳妥的链路是:
这条链路里每层各管什么:
- LLM 处理自然语言和模糊表达;
- 实体对齐把别名映射到统一业务对象;
- 知识图谱保存可以追溯的实例和关系;
- Ontology 约束允许使用的对象类型和关系;
- 规则、权限与审批决定 Agent 能不能真的动手。
如果没有 Ontology,LLM 每次抽取都可能发明一套标签:part_of、PartOf、belongs_to 混在同一张图里。反过来,如果没有 LLM,非结构化邮件、维修记录和操作日志又要靠大量人工整理才能进入图中。
它们搭在一起比较合适:LLM 降低知识提取和本体维护的成本,Ontology 限制 LLM 自由发挥的范围。 一个擅长处理模糊,一个负责保留边界。
从“认识名词”走向“允许动作”
经典知识工程里的 Ontology 主要关心概念和逻辑语义。到了企业 Agent 场景,只让系统认识名词还不够,它迟早要面对动词:
对象:零件、工单、订单、客户
关系:工单需要零件,订单包含产品
状态:轴承预计延期三个工作日
动作:调整排产、切换供应商、通知客户
约束:谁能执行、谁来批准、结果写回哪个系统
Palantir 的 Foundry Ontology 就采用了这种更宽的产品化定义。除了对象、属性和链接,它还把 Action、Function、动态权限纳入同一个组织数字模型。用它的话说,语义元素是“名词”,动作和函数则提供“动词”。
这个思路对 Agent 很重要。前面在 Agent 的工具调用与任务规划 里重点处理的是“怎样调用”,Ontology 进一步追问“对什么对象调用、在什么约束下调用”。模型发现订单可能延期以后,可以生成三个方案,但“调整生产计划”“创建替代采购单”“通知客户”光有三个工具名称远远不够。系统还得知道:
- 当前操作者有没有权限;
- 动作需要哪些参数;
- 哪些条件下必须审批;
- 会修改哪些对象;
- 最终写回 ERP、MES 还是 CRM;
- 失败后如何回滚和审计。
不过需要分清语境:把数据、逻辑、动作和安全都称为 Ontology,是现代企业平台对概念的扩展,超出了 W3C OWL 对 Ontology 的原始定义范围。文章里可以借用这套思路设计 Agent,但没必要硬把所有工作流都塞进 OWL。
Ontology 解决不了哪些问题
Ontology 很容易被讲成企业数据的终极答案,真正做起来会发现,它先把许多原本藏着的问题暴露了出来。
最大的成本在达成共识,不在图数据库
销售认为“客户”是签合同的公司,售后认为实际使用设备的单位也是客户,财务只认可付款主体。它们未必有一个唯一正确的定义。
本体建模不是拍脑袋选词,得明确不同概念的边界、映射和适用场景。有时应该统一,有时应该保留 ContractParty、EndUser 和 Payer 三种角色。过早把它们压成一个 Customer,反而会损失信息。
统一 ID 比画关系图更难
如果 MAT-0018、bearing_a 和“A 型主轴轴承”没有可靠映射,再漂亮的 Ontology 也只能得到三个互不相识的节点。主数据、来源追踪、实体消歧和变更记录仍然要做,Ontology 不会自动修好脏数据。
本体也会过期
工艺变了,产品拆分了,组织调整了,原有关系就可能不再成立。本体需要版本、兼容策略、评审人和废弃流程。它更像一份持续演化的领域契约,设计完成那天也谈不上永久正确的"企业真理"。
推理能力越强,使用成本往往越高
OWL 可以表达比本文复杂得多的逻辑,但表达能力、可判定性和计算成本之间一直存在取舍。团队只需要类型继承和简单约束时,使用轻量词汇、SHACL 加普通查询往往更稳。不要因为工具支持某条逻辑公理,就把业务规则全翻译一遍。
LLM 生成本体只能作为草稿
让模型扫描文档并建议类、属性和关系很有用,直接把结果发布到生产图里则很危险。模型会把同义词拆成多个概念,也会把一段常见描述误当成永恒规则。领域专家仍要确认定义,数据工程师仍要核对来源,关键动作仍要保留人工审批。
什么场景值得做,什么场景先别做
Ontology 比较适合这些情况:
- 多个系统对同一业务对象使用不同标识和定义;
- 高频问题需要跨越多类对象和多跳关系;
- 知识要被搜索、分析、规则引擎和多个 Agent 共同复用;
- 结果必须可解释、可追溯,光给一个相似度远远不够;
- Agent 将参与真实业务动作,需要统一的对象、权限和约束。
下面几种情况则可以先缓一缓:
- 只是给一批文档做简单问答,向量检索已经够用;
- 数据仍在频繁改表,连核心业务对象都没有稳定下来;
- 没有领域专家参与,只准备让开发者或大模型猜定义;
- 主数据和唯一标识尚未治理,却希望靠知识图谱自动消除重复;
- 业务只是单库里的简单 CRUD,SQL 和数据字典完全可以覆盖。
判断标准跟数据量大小关系不大。真正要问的是:同一批业务含义是否正在被不同系统、团队和 Agent 反复解释,而且这些解释不一致已经产生了真实成本。
别从企业级大图开始
如果真要落地,我不建议第一天就开会设计“全公司的 Ontology”。这种项目很容易花几个月争论顶层分类,最后没有一个业务问题因此得到更好的答案。
更实际的路径是:
- 选一个高价值问题:例如零件延期会影响哪些客户订单;
- 只列核心对象:先控制在 5~10 种,覆盖整个制造业是后面的事;
- 定义少量稳定关系:每条关系都要能说清来源、方向和业务含义;
- 统一实例标识:保留各系统原始 ID,并建立可审计的映射;
- 写出一个可验证查询:结果由领域人员核对,不先谈“智能涌现”;
- 接入一个受控动作:先生成建议或审批单,再考虑自动执行;
- 用失败案例修订模型:记录缺失关系、错误映射和版本变化。
本例里甚至可以不用专门的图数据库。数据量不大时,rdflib、关系数据库或支持图查询的现有平台都能完成验证。等到关系遍历、跨域集成和图算法真的成为瓶颈,再做存储选型也不迟。
结语
回到开头那封供应商邮件。
LLM 可以读懂“轴承要晚三天”,RAG 可以把邮件找回来,数据库保存工单和订单,知识图谱把具体对象连起来,而 Ontology 负责说明这些对象为什么能这样连接、关系意味着什么、哪些推断和动作可以被接受。
它们更像一组分工不同的零件,各自解决不同环节的问题。少了 LLM,非结构化信息很难进入系统;少了可靠数据,Ontology 只剩一张空架子;少了明确语义,Agent 则可能拿着一堆正确数据,做出一个逻辑流畅的错误决定。
以前,系统只要把数据存对。现在,当 Agent 开始替人查数据、下判断甚至执行操作,我们还得把“这个业务世界究竟是怎样的”说清楚。
参考资料
- Ontology Development 101: A Guide to Creating Your First Ontology
- OWL 2 Web Ontology Language Document Overview
- OWL Web Ontology Language Guide
- Shapes Constraint Language (SHACL)
- RDF 1.1 Turtle
- SPARQL 1.1 Query Language
- Palantir Foundry: Ontology overview
- AWS Prescriptive Guidance: Semantic layer for agentic AI using ontology
版权声明: 本文首发于 指尖魔法屋-AI时代的数据本体:从一张订单到Ontology(https://blog.thinkmoon.cn/post/1037-ai-data-ontology-manufacturing-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。