
用 Databricks OntoBricks 构建本体并接入 AI 查询
用 Databricks OntoBricks 构建本体并接入 AI 查询
本体(Ontology)把业务概念、属性与关系显式定义出来,让 AI 和人都能按同一套语义理解数据。本文从 RDF、OWL、SPARQL、SHACL 的基础概念讲起,说明在 Databricks 上搭建 OntoBricks 环境的思路,演示手工建模、LLM 自动生成本体、Auto-Map 数据映射、Triple Store 与知识图谱查询,以及和 AI Agent 的衔接方式,并给出企业环境下的设计与运维要点。
本体(Ontology)要解决的问题很具体:数据表里有 customer_id、policy_no、claim_id,但「这份理赔属于哪份保单、这份保单属于哪位客户、客户与合同之间是什么关系」这些业务语义并没有写在数据里。AI 再强,也只能靠猜。本体就是把概念、属性、关系、约束显式定义成一套机器可读的模型,让数据带上语义,让知识图谱可以被查询、被推理、被校验。
Databricks OntoBricks 是 Databricks 环境里用来构建和使用本体的能力集合,覆盖本体建模、LLM 辅助生成本体、数据映射、Triple Store 构建、知识图谱查询,以及和 AI Agent 的对接。这篇教程面向数据工程师、数据架构师,以及想把业务数据和 LLM、AI Agent 打通的人。读完之后,你应该能独立走完一条链路:从概念模型出发,落到 RDF 三元组,映射到真实数据,最后用自然语言或 SPARQL 把知识查出来。
需要先说明一点:OntoBricks 相关功能、可用区域、配额与计费方式会随产品迭代变化,具体以 Databricks 官网当前信息为准。本文讲的是方法与流程,不承诺某个具体版本的行为。
准备工作
概念基础
动手之前,先把几个名词分清楚,否则后面每一步都会卡住。
- 本体与数据模型的区别:数据模型描述「数据怎么存」,本体描述「数据意味着什么」。表结构里有外键,但外键只说明两列值相等,不说明「客户持有保单」这种业务关系。本体把后者也表达出来。
- RDF:用「主语—谓语—宾语」三元组表达事实,例如「保单 P001 的持有人是客户 C001」。三元组是知识图谱的最小单位。
- RDFS 与 OWL:在 RDF 之上定义类、属性、层级和约束。RDFS 提供基本的类型与继承,OWL 表达能力更强,可以声明属性的定义域与值域、基数约束、等价类等,从而支持推理。
- SPARQL:查询 RDF 图的语言,形态上类似 SQL,但匹配的是图模式而不是表。
- SHACL:校验 RDF 图是否满足形状约束,例如「每份保单必须有且只有一个持有人」。它管的是数据质量。
- 实现方式:RDF Graph 以三元组为中心,适合语义推理与跨源整合;Property Graph 以节点和边为中心,适合图算法和高性能遍历。选哪种取决于你要做的是语义整合还是图分析。
环境与账号
你需要一个可用的 Databricks 工作区,并且具备创建计算资源、创建 Catalog 与 Schema、读写表的权限。OntoBricks 的构建过程会涉及存储三元组的数据集,因此还需要在 Unity Catalog 里有可写的目标位置。
如果计划使用 LLM 自动生成本体或做自然语言查询,需要确认工作区所在区域已开放对应的模型服务,并确认调用配额。模型端点名称、可用模型清单、单次调用的 token 上限都属于易变信息,请以官网当前信息为准。
数据侧的准备同样重要。建议先在 Catalog 中准备好样例数据,例如客户表、保单表、理赔表。字段命名尽量规范,主键清晰,外键关系明确——LLM 自动生成本体的质量,很大程度上取决于输入表结构和字段注释的可读性。
操作步骤
第一步:确定本体的范围与核心概念
不要一上来就建全公司的本体。先圈定一个业务域,列出这个域里的核心类和关系。以保险场景为例,可以先确定这几个类:客户、保单、理赔、产品。关系包括:客户持有保单、保单引用产品、理赔关联保单。
把这份清单写成结构化的形式,每个类列出属性名、数据类型、是否必填。这一步用表格或 YAML 都可以,关键是让后续的建模有据可依。
第二步:用 RDF 与 OWL 表达本体
把上一步的清单翻译成三元组。下面是一个最小示例,用 Turtle 语法描述类和属性:
@prefix ex: <https://example.com/insurance/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ex:Customer a owl:Class .
ex:Policy a owl:Class .
ex:Claim a owl:Class .
ex:holdsPolicy a owl:ObjectProperty ;
rdfs:domain ex:Customer ;
rdfs:range ex:Policy .
ex:claimOnPolicy a owl:ObjectProperty ;
rdfs:domain ex:Claim ;
rdfs:range ex:Policy .
ex:policyNumber a owl:DatatypeProperty ;
rdfs:domain ex:Policy .
定义域(domain)和值域(range)不只是注释,它们会参与推理:如果系统知道某条三元组的主语是 ex:holdsPolicy 的主语,就能推断出它是 ex:Customer 的实例。这正是本体比表结构多出来的能力。
如果业务里有层级概念,例如「车险保单」是「保单」的子类,用 rdfs:subClassOf 声明。层级越清晰,后续推理和查询越省事。
第三步:在 Databricks 中搭建 OntoBricks 环境
环境搭建的核心是把本体文件、映射配置和三元组存储放到 Unity Catalog 管理之下,这样权限、血缘和审计都能沿用平台既有机制。
- 在目标 Catalog 下创建专用 Schema,例如
ontology,用于存放本体定义、映射规则和生成的三元组。 - 把第二步写好的 Turtle 或 OWL 文件上传到 Volume,作为本体的版本化来源。
- 创建计算资源。建模与映射阶段用通用计算即可;涉及 LLM 生成和批量推理时,注意计算规格与并发配置。
- 确认模型服务端点可用,记录端点名称,后续在生成与查询环节会用到。
具体到某个工作区,OntoBricks 的入口位置和菜单名称可能不同,以你所在环境的实际界面为准。本文只描述流程,不描述按钮位置。
第四步:用 LLM 自动生成本体
手工建模适合概念清晰的场景,但面对几十张表、上百个字段时,人工梳理成本很高。LLM Ontology Generate 的思路是:把表结构、字段名、字段注释作为输入,让模型提出候选的类、属性和关系,再由人审核修订。
使用时有几个实践要点:
- 输入要带注释:字段注释是模型判断语义的主要依据。没有注释的字段,模型只能靠命名猜,准确率会明显下降。
- 分批处理:一次投喂全部表容易超出上下文长度,也容易让模型混淆。按业务域分批,每批控制在十几张表以内。
- 结果必须人工审核:模型会生成看似合理但实际错误的关系,例如把两个都叫
id的字段强行关联。审核环节不能省。 - 保留中间产物:把模型输出的候选本体存成文件,便于对比不同批次、不同提示词的效果。
素材中提到的中级实践使用了十张表的客户旅程数据来演示自动生成,这个规模适合作为起步参照:表太少看不出跨表关系,表太多则难以人工校验。
第五步:用 Auto-Map 完成数据映射
本体是模型,数据是实例。Auto-Map 负责把表里的行映射成三元组:哪张表的哪一列对应本体的哪个属性,主键如何转成 IRI,外键如何转成对象属性。
映射配置通常包含三部分:
- 主语生成规则:例如客户表的主键
customer_id映射为ex:Customer/{customer_id}形式的 IRI。 - 属性映射:
customer_name映射到ex:customerName,并声明数据类型。 - 关系映射:保单表的
customer_id外键映射为ex:holdsPolicy的宾语。
Auto-Map 会基于字段名和注释给出建议映射,同样需要人工确认。特别要检查外键方向:把「客户持有保单」写成「保单持有客户」,图的方向就反了,后续查询会全部出错。
第六步:构建 Triple Store 并查询知识图谱
映射执行后,三元组会写入 Triple Store。此时可以用 SPARQL 查询。下面这个查询找出某位客户名下的全部保单及其关联理赔:
PREFIX ex: <https://example.com/insurance/>
SELECT ?policyNumber ?claimId
WHERE {
?customer ex:customerId "C001" .
?customer ex:holdsPolicy ?policy .
?policy ex:policyNumber ?policyNumber .
OPTIONAL {
?claim ex:claimOnPolicy ?policy .
?claim ex:claimId ?claimId .
}
}
注意 OPTIONAL 的用法:没有理赔的保单也应该出现在结果里,否则统计口径会偏。这类细节在从 SQL 迁移到 SPARQL 时最容易出错。
除了 SPARQL,知识图谱还支持自然语言查询:把用户问题、本体摘要和少量示例查询一起交给 LLM,由模型生成 SPARQL 再执行。这种方式降低了使用门槛,但生成结果需要校验,尤其是涉及聚合和否定条件的问题。
第七步:用 SHACL 做质量校验
数据映射完成后,先别急着接 AI。用 SHACL 定义形状约束,检查图里是否存在缺属性、类型错误、孤立节点等问题。例如要求每份保单必须有且仅有一个持有人、保单号必须符合固定格式。校验不通过的记录要回到映射环节修正,而不是在查询层打补丁。
第八步:接入 AI Agent
本体最大的价值在于给 AI 提供可靠的语义底座。通过 MCP 或 Databricks Apps,可以把知识图谱的查询能力暴露给 AI Agent:Agent 拿到用户问题后,先查本体确认概念与关系,再生成查询,最后基于结果作答。
这一层的设计要点是限制 Agent 的能力边界:只允许查询,不允许写入;对生成的查询做语法与权限校验;对返回结果做条数上限。否则一个模糊的问题可能触发全图扫描。
一个完整示例
下面把前面的步骤串成一条最小可跑通的链路,场景是「查询某客户的全部保单与理赔」。
1. 准备数据。在 Unity Catalog 中建三张表:customers(customer_id, customer_name)、policies(policy_no, customer_id, product_code)、claims(claim_id, policy_no, claim_amount),各插入两三行样例数据。
2. 定义本体。使用第二步的 Turtle 片段,补充 ex:customerId、ex:claimId、ex:claimAmount 三个数据属性,保存为 insurance.ttl 并上传到 Volume。
3. 配置映射。为三张表分别配置主语规则与属性映射,外键方向按「客户 → 保单 → 理赔」组织。
4. 生成三元组。执行映射任务,把结果写入 Triple Store 对应的数据集。检查行数与源表是否匹配,确认没有因主键重复导致的合并。
5. 执行查询。运行第六步的 SPARQL,把 C001 换成实际存在的客户编号,确认返回该客户的保单号与理赔编号。
6. 校验。写一条 SHACL 形状,要求 ex:Policy 实例必须有 ex:policyNumber,运行校验,确认无违规。
7. 接入问答。把上述查询作为示例,连同本体摘要一起提供给模型,测试「C001 有哪些理赔」这类自然语言问题能否得到正确结果。
这条链路跑通之后,再扩展到更多表和更复杂的推理规则,风险可控得多。
注意事项
- 本体不是数据字典:只把字段名翻译成类名,得到的是一份带层级的表结构说明,不具备推理能力。要真正发挥价值,必须把业务关系、约束和层级定义进去。
- LLM 生成结果不可直接上线:自动生成解决的是起草效率,不是正确性。审核环节缺失时,错误的关系会一路传导到查询和 AI 回答。
- 外键方向与基数:一对多、多对多关系在 RDF 里都表现为三元组,方向写反或基数理解错,查询结果会静默出错,不会报异常。
- 图规模与查询性能:全图扫描类查询在数据量增长后会明显变慢。设计查询时尽量从具体实例出发,避免无约束的模式匹配。
- 权限沿用平台机制:本体、映射和三元组都放在 Unity Catalog 下,权限按 Schema 和表粒度管理,不要另建一套访问控制。
- 版本管理:本体文件要纳入版本控制。模型变更会影响已有查询和 AI 回答,需要能回溯到具体版本。
- 易变信息以官网为准:OntoBricks 的功能范围、模型可用性、配额与计费方式都可能调整,实施前请核对 Databricks 官网当前信息。
本体建设的投入主要在前期的概念梳理,后期的查询、推理和 AI 接入反而相对轻。先把一个业务域做扎实,再横向复制,比一次性铺开所有域更容易成功。