◈本体论工程手册
实证

十四 · 本体与模型系统的边界

三个真接触面、两个伪接触面、四条判据

这一章回答一个 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 因质量问题被冻结,尚未解除

这个接触面之所以最强,有四个原因:

  1. 可复现。 同样的参数永远得到同样的结论,与模型版本、温度、上下文长度无关。
  2. 可审计。 拒绝记录能直接进审计日志,回答「为什么这笔没做成」。
  3. 成本近零。 第 11 章实测:16 万三元组校验 1.4 秒;单次动作校验是毫秒级。
  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 草稿。

不能做的部分:把生成结果直接作为契约。

三个原因:

  1. 一致性。 同一份文档跑两次,得到的类名、粒度、关系方向会不同。契约需要的是「三次跑出同一个结果」。
  2. 不可审计。 无法回答「为什么这个类存在」「为什么这条约束是 0.8 而不是 1」。而模型的每一条约束将来都会拒绝真实业务。
  3. 责任真空。 自动生成的约束被违反时,没有人能对它负责——而约束必须有负责人(第 13 章的裁决者角色)。

可用的工作流:模型生成草稿 → 人逐条审 → 审过的进入版本控制 → 从此不再由模型改。模型是笔,不是立法者。

RAG、GraphRAG、本体:三者到底什么关系

解决什么不解决什么与另外两者的关系
向量 RAG「找意思相近的文本」精确约束、跨文档一致性、可审计召回层
GraphRAG「沿关系找多跳证据」什么是合法的、什么必须为真召回层的增强,仍不管对错
本体「什么必须为真、什么必须拒绝」召回、相似度、自然语言理解边界层,不是召回层

一句话:RAG 系列解决「找得到」,本体解决「对不对」。 把三者混为一谈的项目,通常在演示时很好,在生产时说不清「为什么这条答案是错的」。

第 9 章的趋势核验里有一条与此相关:GraphRAG 类项目的中位星数(7897)是本体工具(944)的八倍多。这不说明 GraphRAG 更重要,只说明「找得到」是当下更痛的问题。痛的那一端先被解决,是正常的技术演进顺序。

Agent 记忆:本体能给什么,不能给什么

Agent 记忆目前有三种存法:

存法存什么擅长缺陷
向量库文本片段 + embedding语义相似召回无结构、无约束、会漂移
事件流时间序列的动作与观察时序推理、回放无类型系统、关系查询弱
图 / 本体实体、关系、约束、状态一致性、可追溯、跨会话共享写入成本高、建模成本高

本体对 Agent 记忆的贡献不是「记得更多」,是「记得更准」:类型明确(这是订单不是文档)、约束明确(已冻结的供应商不能下单)、状态有所有权(这个字段谁说了算)、变更可追溯(这条记忆什么时候被谁改的)。

多 Agent 协作时这一点尤其重要:两个 Agent 共享一个向量库,它们共享的是「相似」;共享一个本体,它们共享的是「同一个事实」。

什么时候模型系统真的需要本体

四条判据,满足两条以上才值得做:

  1. 需要拒绝非法操作。 模型要发起写操作(下单、退款、改价、发消息),且有不能越过的边界。
  2. 需要跨系统一致。 同一个事实在 3 个以上系统里存在,且要求一致。
  3. 需要审计。 出问题时要能回答「谁在什么时候基于什么做了什么」。
  4. 多 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 代替校验器——把数据丢给模型,问「这条数据有没有问题」。

不要这么做,四个原因:

  1. 不可复现。 同一条数据两次询问可能得到不同结论。而校验的第一要求是确定。
  2. 不可解释。 你无法把「模型觉得有问题」写进审计报告。
  3. 成本与延迟。 每次提交调一次模型,成本是校验器的千倍以上,延迟是百倍。
  4. 无法回归。 模型升级后行为变化,历史结论无法复算。

模型可以做的是校验结果的自然语言解释:把 SUPPLIER_FROZEN 翻译成「这家供应商上周因质量问题被冻结了,找采购部张××解除」。这是有用的产品化工作,但它发生在校验之后,不替代校验。

一句话

模型负责「做什么」,本体负责「什么不能做」。 前者这两年被大幅改善,后者几乎没有进展——而生产系统的事故,绝大多数出在后者。