十四 · 本体与模型系统的边界
三个真接触面、两个伪接触面、四条判据
这一章回答一个 2026 年最常被问到、也最容易被答错的问题:有了大模型,还需要本体吗?
先给结论,再给理由:
需要,但不是在多数人以为的地方。 本体对模型系统最大的价值不是「让模型更懂业务」,而是在模型动手之前和动手之后,提供一道可执行、可复现、可审计的边界。这不是 AI 能力的扩展,是 AI 可靠性的基础设施。
反过来,把本体塞进 prompt、或指望模型自己生成契约级的本体,这两条路目前都不成立。
三个真接触面,两个伪接触面
「本体 + 大模型」的讨论之所以混乱,是因为没有区分模型在哪一步用到本体。
| 接触面 | 模型做什么 | 本体提供什么 | 判定 |
|---|---|---|---|
| 一、工具调用前的参数校验 | 提议一个动作(下单、收货、退款) | 前置条件、类型、枚举、引用完整性 | 最强,优先做 |
| 二、检索的元数据过滤 | 检索前缩小范围 | 类型、状态、时效、权限标记 | 中等价值,容易做 |
| 三、生成结果的结构化落地 | 输出 JSON / 引用实体 | sh:class 抓悬空引用,schema 抓结构 | 中等价值,防幻觉有效 |
| 四、把本体写进 prompt | — | 整个模型 | 伪接触面 |
| 五、让模型生成本体 | — | 草稿素材 | 伪接触面(不能做契约) |
接触面一:工具调用前的参数校验(最强)
一个 Agent 要执行 ReceiveBatch(收货)。模型输出:
{"action":"ReceiveBatch","poId":"PO-2026-00871","supplierId":"S-2041",
"materialId":"M-3382","qty":120,"arrivalDate":"2026-11-02"}
在真正调用之前,把这组参数当作数据送进校验器:
def guard(action, args, shapes):
g = to_rdf(action, args) # 参数 → 三元组
report = validate(g, shapes, inference=None)
if not report.conforms:
return Reject(code=report.top_code(), details=report.human_readable())
return Execute(args)
被拒绝的那一刻,系统拿到的是一个确定的、可解释的、与模型无关的结论:
REJECTED SUPPLIER_FROZEN
供应商 S-2041 于 2026-10-12 因质量问题被冻结,尚未解除
这个接触面之所以最强,有四个原因:
- 可复现。 同样的参数永远得到同样的结论,与模型版本、温度、上下文长度无关。
- 可审计。 拒绝记录能直接进审计日志,回答「为什么这笔没做成」。
- 成本近零。 第 11 章实测:16 万三元组校验 1.4 秒;单次动作校验是毫秒级。
- 不随模型升级失效。 换个更强的模型,这道边界还在;换个更弱的,它仍然挡住。
这才是本体在 AI 时代的位置:不是模型的记忆,是模型的刹车。
接触面二:检索的元数据过滤(中等)
RAG 的常见问题不是「召回不到」,是「召回了不该用的」:过期版本的口径定义、已冻结供应商的资料、没权限的项目文档。
本体提供的是过滤维度,不是语义扩展:
SELECT ?doc ?text WHERE {
?doc a ex:MetricDefinition ;
ex:metric ?m ; ex:version ?v ; ex:status ex:effective ;
ex:text ?text .
FILTER (?m = ex:on_time_delivery_rate)
FILTER (?v = (SELECT MAX(?v2) WHERE { ?d2 ex:metric ?m ; ex:version ?v2 }))
}
三条过滤——类型、状态、最新版本——把候选集从「所有文档」缩到「当前生效的那一版」。这比在 prompt 里写「请只使用最新版本」有效得多,因为后者是请求,前者是约束。
⚠️ 注意这里不该做的事:不要指望本体做「语义相似」的召回。类型与约束管不了「意思相近的另一个句子」,那是向量的事。
接触面三:生成结果的结构化落地(中等)
模型生成的结论要落到结构化系统里,两个关口:
关口一:结构。 强制 JSON Schema(可从模型生成,见第 3 章「一份源、多目标编译」)。结构不对直接拒绝,不进后续流程。
关口二:引用。 模型最容易犯的错是引用一个不存在的东西——不存在的指标、不存在的单据号、不存在的条款。而 sh:class 恰好抓这个:
ex:FindingShape a sh:NodeShape ;
sh:targetClass ex:Finding ;
sh:property [ sh:path ex:cites ; sh:minCount 1 ; sh:class ex:Metric ] .
第 11 章实测里,这条约束抓到 finding_rpt_01 → metric_missing。在 AI 场景下,同样的约束抓的是幻觉——模型编了一个指标名,引用完整性直接让它失败。
这是本体与幻觉之间唯一有工程意义的对称关系:你不必让模型不说错话,你只需要让它说的话必须指向存在的东西。
伪接触面四:把本体塞进 prompt
做法:把 200 个类、800 条约束序列化进系统提示,希望模型「遵守」。
四个问题,任何一个都足以否掉它:
- 容量。 完整模型动辄数万 token,挤掉的是上下文里更有用的内容。
- 不可保证。 模型是概率的,写进 prompt 的要求是「请求」不是「约束」。它可能在 95% 的情况下遵守,而 5% 的不遵守恰好落在最贵的那笔交易上。
- 不可解释。 违反时你无法指出「违反了哪一条」,只能重试。
- 随版本衰减。 换模型、改系统提示、加工具,行为都会漂移。
一个可用的弱化形式:只把当前任务相关的 5–15 条约束注入 prompt,作为「提示」而非「保证」,同时在工具侧用校验器做真正的拦截。提示提升一次通过率,校验兜住底线。两者不冲突,但不能互相替代。
伪接触面五:让模型生成本体
「用 LLM 从文档自动抽取本体」是过去两年最有吸引力的演示,也最容易误导决策。
能做的部分(有真实价值):术语抽取、候选类建议、同义词聚类、从样本数据猜测字段语义、把自然语言规则翻译成 SHACL 草稿。
不能做的部分:把生成结果直接作为契约。
三个原因:
- 一致性。 同一份文档跑两次,得到的类名、粒度、关系方向会不同。契约需要的是「三次跑出同一个结果」。
- 不可审计。 无法回答「为什么这个类存在」「为什么这条约束是 0.8 而不是 1」。而模型的每一条约束将来都会拒绝真实业务。
- 责任真空。 自动生成的约束被违反时,没有人能对它负责——而约束必须有负责人(第 13 章的裁决者角色)。
可用的工作流:模型生成草稿 → 人逐条审 → 审过的进入版本控制 → 从此不再由模型改。模型是笔,不是立法者。
RAG、GraphRAG、本体:三者到底什么关系
| 解决什么 | 不解决什么 | 与另外两者的关系 | |
|---|---|---|---|
| 向量 RAG | 「找意思相近的文本」 | 精确约束、跨文档一致性、可审计 | 召回层 |
| GraphRAG | 「沿关系找多跳证据」 | 什么是合法的、什么必须为真 | 召回层的增强,仍不管对错 |
| 本体 | 「什么必须为真、什么必须拒绝」 | 召回、相似度、自然语言理解 | 边界层,不是召回层 |
一句话:RAG 系列解决「找得到」,本体解决「对不对」。 把三者混为一谈的项目,通常在演示时很好,在生产时说不清「为什么这条答案是错的」。
第 9 章的趋势核验里有一条与此相关:GraphRAG 类项目的中位星数(7897)是本体工具(944)的八倍多。这不说明 GraphRAG 更重要,只说明「找得到」是当下更痛的问题。痛的那一端先被解决,是正常的技术演进顺序。
Agent 记忆:本体能给什么,不能给什么
Agent 记忆目前有三种存法:
| 存法 | 存什么 | 擅长 | 缺陷 |
|---|---|---|---|
| 向量库 | 文本片段 + embedding | 语义相似召回 | 无结构、无约束、会漂移 |
| 事件流 | 时间序列的动作与观察 | 时序推理、回放 | 无类型系统、关系查询弱 |
| 图 / 本体 | 实体、关系、约束、状态 | 一致性、可追溯、跨会话共享 | 写入成本高、建模成本高 |
本体对 Agent 记忆的贡献不是「记得更多」,是「记得更准」:类型明确(这是订单不是文档)、约束明确(已冻结的供应商不能下单)、状态有所有权(这个字段谁说了算)、变更可追溯(这条记忆什么时候被谁改的)。
多 Agent 协作时这一点尤其重要:两个 Agent 共享一个向量库,它们共享的是「相似」;共享一个本体,它们共享的是「同一个事实」。
什么时候模型系统真的需要本体
四条判据,满足两条以上才值得做:
- 需要拒绝非法操作。 模型要发起写操作(下单、退款、改价、发消息),且有不能越过的边界。
- 需要跨系统一致。 同一个事实在 3 个以上系统里存在,且要求一致。
- 需要审计。 出问题时要能回答「谁在什么时候基于什么做了什么」。
- 多 Agent / 多团队共享状态。 需要一份共同认可的事实定义。
什么时候不需要:纯问答、摘要、翻译、语义搜索、内容生成。这些场景里,本体带来的复杂度远大于收益——加一份向量库就够了。
一个可落地的集成
把上面三条接触面串成一条链,代码量很小:
def agent_write(action, args, ctx):
# 1. 结构:JSON Schema 校验(模型生成,见编译器)
if not schema_ok(action, args): return Reject("SCHEMA")
# 2. 语义:参数 → 三元组 → SHACL
g = to_rdf(action, args, ctx.base_graph)
rep = validate(g, shapes_for(action), inference=None)
if not rep.conforms: return Reject(rep.code(), rep.detail())
# 3. 执行:动作由确定性代码完成,不由模型完成
result = ACTIONS[action](**args)
# 4. 后置:把结果写回图,供下一次校验使用
write_back(result, ctx.base_graph, audit_who=ctx.who)
return Ok(result)
第四条值得强调:写回让校验具备记忆。例如「同一批次不能重复收货」这条约束,靠的就是上一次成功写回留下了 Batch 记录。没有写回,校验只能看静态规则,看不到历史。
一个必须警告的替代方案
有一种做法正在流行:用 LLM 代替校验器——把数据丢给模型,问「这条数据有没有问题」。
不要这么做,四个原因:
- 不可复现。 同一条数据两次询问可能得到不同结论。而校验的第一要求是确定。
- 不可解释。 你无法把「模型觉得有问题」写进审计报告。
- 成本与延迟。 每次提交调一次模型,成本是校验器的千倍以上,延迟是百倍。
- 无法回归。 模型升级后行为变化,历史结论无法复算。
模型可以做的是校验结果的自然语言解释:把 SUPPLIER_FROZEN 翻译成「这家供应商上周因质量问题被冻结了,找采购部张××解除」。这是有用的产品化工作,但它发生在校验之后,不替代校验。
一句话
模型负责「做什么」,本体负责「什么不能做」。 前者这两年被大幅改善,后者几乎没有进展——而生产系统的事故,绝大多数出在后者。