Gliding Horse 本体论系统设计:给 AI Agent 装上“语义大脑”
在打造 Gliding Horse(流马)这个 AI Agent 操作系统的过程中,我一直被一个问题困扰:如何让 Agent 真正“理解”它产出的每一条数据的含义,而不仅仅是生成文本?
LLM 擅长生成内容,但弱于遵守精确的结构化约束。一个 Agent 产出的 JSON-LD 文档可能缺少必填字段,或者引用了不存在的实体。在简单的单 Agent 场景里,这些问题可以人工兜底,但当一个工程由需求、设计、编码、测试等多个阶段的多个 Agent 协作完成时,数据一致性和语义正确性就成了生死线。
为了解决这个问题,我决定为流马装上一个“语义大脑”——一套完整的本体论系统。它不是事后校验,而是内建于内核的、基于 W3C 标准的语义推理与验证引擎。这篇文章将详细拆解这套系统的设计思路、核心架构、关键组件,以及它为整个平台带来的巨大提升。
一、为什么 Agent OS 需要本体论系统?
传统 Agent 框架大多把知识当作非结构化文本或 JSON 来传递。这带来三个致命问题:
- 弱约束:Prompt 里写“必须包含某个字段”,LLM 可能忽略;
- 不可推理:Agent 产出的数据之间没有逻辑推导能力,无法发现隐含的矛盾;
- 难以追溯:当任务失败,很难定位是哪一环节的数据出了问题。
Gliding Horse 从一开始就采用 JSON-LD 作为统一数据总线,所有数据都有全局 IRI 和语义类型。这套机制需要一个与之匹配的“编译器”和“类型检查器”——这就是本体论系统的用武之地。它提供:
- SHACL 形状约束:像数据库的 CHECK 约束一样,强制数据完整性;
- OWL 推理:通过逻辑推导,发现隐含的知识和矛盾;
- 本体对齐与漂移检测:保持技能图谱和知识图谱的语义一致性;
- 嵌入增强的语义检索:结合向量语义,让模糊搜索更精准。
二、设计思想:库级融合,共享图存储
市面上有不少本体工具,但大多以独立服务(如 MCP Server)的形式存在,需要进程间通信、序列化开销,且各自维护一份数据副本。在流马的设计中,我选择了库级融合(Library Fusion)的方案——将开源本体库 open-ontologies 直接作为 Rust 依赖嵌入内核,通过共享底层的 Arc<oxigraph::store::Store> 实现零拷贝的数据互通。
整个架构围绕一个新增的核心模块 OntologyEngine 展开,它与现有的记忆系统、上下文引擎、事件总线深度集成。
事件总线 (现有)
质量门禁 (现有)
记忆系统 (现有)
本体论系统 (新增)
双核心引擎
Agent 编排引擎
上下文管理引擎
OntologyEngine
SharedGraphStore (适配层)
L2 黑板 (Oxigraph 内存图)
L3 投影引擎
L0 持久化 (Oxigraph + Qdrant)
系统调用门
ToolGuard
EventBus
核心设计理念:本体论系统不引入额外的数据源,而是直接工作于现有的 L2 黑板(Oxigraph 内存图)之上。任何 Agent 写入的 JSON‑LD 数据,都能被本体引擎实时感知、校验和推理。上层应用(SA、PA、CA)通过 OntologyEngine 提供的 Rust API 直接调用推理、对齐等功能,零网络开销。
三、核心架构:OntologyEngine 及 SharedGraphStore
OntologyEngine 是整个本体论系统的“统一入口”,它将 open-ontologies 的各个组件封装在一起,并共享 Gliding Horse 的 Arc<Store>。
pub struct OntologyEngine {
graph: Arc<SharedGraphStore>, // 共享图存储(适配层)
db: StateDb, // 本体演化状态(SQLite)
drift_detector: DriftDetector, // 漂移检测器
enforcer: Enforcer, // 设计模式强制器
planner: Planner, // 本体生命周期规划器
monitor: Monitor, // SPARQL 观察者
alignment: AlignmentEngine, // 本体对齐引擎
lineage: LineageLog, // 血统审计日志
}
其中,SharedGraphStore 是对 Arc<oxigraph::store::Store> 的轻量级适配,使得 open-ontologies 的 ShaclValidator、Reasoner 等能直接操作 GH 的图存储,无需额外的 Mutex 包裹(Oxigraph 的 Store 本身已是线程安全)。
pub struct SharedGraphStore {
inner: Arc<Store>,
}
impl SharedGraphStore {
pub fn from_arc(store: Arc<Store>) -> Self { Self { inner: store } }
// 代理到 inner 的 SPARQL、插入、遍历等方法
}
这样,整个系统中只有一个物理图存储,推理、校验、检索都基于同一份实时数据。
四、关键组件设计详解
4.1 SHACL 门禁 —— 让每次写入都“过安检”
Gliding Horse 的所有 Agent 产出都是以 JSON‑LD 形式写入 L2 黑板的。我们在 Blackboard::write_node() 中植入了一个可配置的 SHACL 校验门禁:
Oxigraph StoreShaclValidatorBlackboardAgentOxigraph StoreShaclValidatorBlackboardAgentalt[校验通过 (或 Warn 模式)][校验失败 (Block 模式)]write_node(JSON‑LD)validate(shape)ok / warning log写入三元组violationsCoreError::ValidationFailed
我们定义了一系列 SHACL 形状,用于约束核心 Agent 概念:
- ExecutionEvent:必须包含
executedBy(执行者)、hasTimestamp(时间戳)且类型为xsd:dateTime; - Task:每个任务至多一个
assignedTo,子任务必须引用合法的 Task 实例; - PDCACycle:阶段数 4‑7 个;
- Skill:必须有
karma权重(浮点数)。
:ExecutionEventShape a sh:NodeShape ;
sh:targetClass gh:Event ;
sh:property [
sh:path gh:executedBy ;
sh:minCount 1 ; sh:maxCount 1 ;
sh:class gh:Agent ;
] ;
sh:property [
sh:path gh:hasTimestamp ;
sh:datatype xsd:dateTime ;
] .
效果:违反形状的数据可在写入前被硬性阻止(Block 模式),确保流入持久层的每一条三元组都是“合规公民”。即使是 LLM 产生幻觉漏掉的字段,SHACL 也能兜底。
下面是用 Rust 定义 SHACL 形状并集成到 Blackboard::write_node 中的完整实战代码:
// ============================================================
// 1. 使用 open-ontologies 的 ShaclValidator 定义形状
// ============================================================
use oxigraph::store::Store;
use open_ontologies::shacl::{ShaclValidator, ValidationReport, Severity};
use std::sync::Arc;
/// 加载并注册 SHACL 形状到验证器
fn load_shacl_shapes(store: &Store) -> ShaclValidator {
let shapes_turtle = r#"
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix gh: <http://gliding-horse.io/ontology/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
# ExecutionEvent 形状:必须包含执行者和时间戳
:ExecutionEventShape a sh:NodeShape ;
sh:targetClass gh:Event ;
sh:property [
sh:path gh:executedBy ;
sh:minCount 1 ; sh:maxCount 1 ;
sh:class gh:Agent ;
] ;
sh:property [
sh:path gh:hasTimestamp ;
sh:datatype xsd:dateTime ;
sh:minCount 1 ;
] .
# Task 形状:至多一个 assignedTo,子任务必须引用合法 Task
:TaskShape a sh:NodeShape ;
sh:targetClass gh:Task ;
sh:property [
sh:path gh:assignedTo ;
sh:maxCount 1 ;
sh:class gh:Agent ;
] ;
sh:property [
sh:path gh:subTaskOf ;
sh:nodeKind sh:IRI ;
sh:class gh:Task ;
] .
# PDCACycle 形状:阶段数 4-7 个
:PDCACycleShape a sh:NodeShape ;
sh:targetClass gh:PDCACycle ;
sh:property [
sh:path gh:phaseCount ;
sh:minInclusive 4 ;
sh:maxInclusive 7 ;
sh:datatype xsd:integer ;
] .
# Skill 形状:必须有 karma 权重(浮点数)
:SkillShape a sh:NodeShape ;
sh:targetClass gh:Skill ;
sh:property [
sh:path gh:karma ;
sh:datatype xsd:float ;
sh:minCount 1 ;
] .
"#;
// 将形状定义解析并加载到验证器
ShaclValidator::from_turtle(shapes_turtle, store)
.expect("SHACL 形状定义解析失败,请检查 Turtle 语法")
}
// ============================================================
// 2. 集成到 Blackboard::write_node 方法中
// ============================================================
use open_ontologies::shacl::ValidationMode;
/// 黑板写入配置
#[derive(Clone)]
pub struct WriteConfig {
/// SHACL 校验模式:Off / Warn / Block
pub shacl_mode: ValidationMode,
/// 推理配置
pub reasoning_profile: ReasoningProfile,
}
/// 黑板写入结果
#[derive(Debug)]
pub enum WriteResult {
/// 写入成功
Accepted,
/// 校验警告(Warn 模式下写入成功但记录警告)
AcceptedWithWarning(Vec<String>),
/// 校验失败被阻止(Block 模式下)
Rejected(Vec<String>),
}
impl Blackboard {
/// 写入节点,经过 SHACL 门禁校验
pub fn write_node(
&self,
json_ld: &str, // 待写入的 JSON-LD 数据
shapes_graph_iri: &str, // SHACL 形状图的 IRI
config: &WriteConfig,
) -> Result<WriteResult, CoreError> {
// 步骤 1:将 JSON-LD 解析为三元组并暂存到临时图
let temp_graph = self.store
.parse_graph(json_ld, "application/ld+json")
.map_err(|e| CoreError::ParseError(format!("JSON-LD 解析失败: {}", e)))?;
// 步骤 2:执行 SHACL 校验
let validator = load_shacl_shapes(&self.store);
let report: ValidationReport = validator.validate_with_shapes_graph(
&temp_graph,
shapes_graph_iri,
)?;
// 步骤 3:根据校验结果和配置模式决定行为
let violations: Vec<String> = report
.results()
.iter()
.filter(|r| r.severity() == Severity::Violation)
.map(|r| format!(
"[{}] 路径: {} | 消息: {}",
r.severity(),
r.path().map(|p| p.to_string()).unwrap_or_default(),
r.message().unwrap_or("无详细信息")
))
.collect();
match config.shacl_mode {
ValidationMode::Off => {
// 关闭校验,直接写入
self.store.load_graph(temp_graph, None)?;
Ok(WriteResult::Accepted)
}
ValidationMode::Warn => {
if violations.is_empty() {
self.store.load_graph(temp_graph, None)?;
Ok(WriteResult::Accepted)
} else {
// 记录警告但允许写入
tracing::warn!(
"SHACL 校验警告 (Warn 模式): {} 条违规",
violations.len()
);
for v in &violations {
tracing::warn!(" -> {}", v);
}
self.store.load_graph(temp_graph, None)?;
Ok(WriteResult::AcceptedWithWarning(violations))
}
}
ValidationMode::Block => {
if !violations.is_empty() {
tracing::error!(
"SHACL 校验失败 (Block 模式): {} 条违规,写入被阻止",
violations.len()
);
return Err(CoreError::ValidationFailed(violations));
}
self.store.load_graph(temp_graph, None)?;
Ok(WriteResult::Accepted)
}
}
}
}
/// 自定义错误类型
#[derive(Debug, thiserror::Error)]
pub enum CoreError {
#[error("JSON-LD 解析错误: {0}")]
ParseError(String),
#[error("SHACL 校验失败: {0:?}")]
ValidationFailed(Vec<String>),
#[error("推理引擎错误: {0}")]
ReasoningError(String),
}
代码要点说明:
load_shacl_shapes()函数将 Turtle 格式的形状定义解析为ShaclValidator实例,支持ExecutionEvent、Task、PDCACycle、Skill四种核心形状;Blackboard::write_node()方法实现了完整的校验流程:解析 JSON-LD → 执行 SHACL 校验 → 根据ValidationMode(Off/Warn/Block)决定是否写入;- Block 模式下,任何
Severity::Violation都会导致写入被拒绝并返回详细的违规信息,Agent 可据此修正数据后重试。
4.2 OWL 推理 —— 从显式声明中挖掘隐性知识
Agent 产出的 JSON‑LD 通常只显式声明最直接的属性,但 Gliding Horse 的 Agent 本体(如 SupervisorAgent、DoAgent)本身是一个 OWL 类层次。
SupervisorAgent rdfs:subClassOf Agent
DoAgent rdfs:subClassOf Agent
Agent rdfs:subClassOf ExecutorEntity
ExecutorEntity gh:hasRole min 1
单纯依靠 SHACL 校验,无法自动推断出 SupervisorAgent 也需要 hasRole 属性,除非显式声明。而我们通过 OWL‑RL 推理引擎,对写入后的数据进行物化(materialization),将推断出的三元组写入一个专门的命名图 <urn:gh:inferred>。
// Blackboard::write_node() 中的调用
if config.reasoning_profile != Off {
Reasoner::run(&graph, "owl-rl", true)?;更多推荐
所有评论(0)