■ 一个让我放弃调参的现场
去年做了个供应链知识问答系统。需求听起来简单:
"华东仓爆仓了,影响哪些客户的履约?"
用标准 RAG 管道——文档切片、embedding、top-10 检索、拼接 prompt、喂模型。第一周的效果:能答,但答不对。
问"华东仓爆仓影响哪些客户",它给了一堆"仓储管理规范""物流应急预案""华东区域运营周报"的段落拼在一起。每段看起来都跟问题沾边,拼出来的答案离题八万里。
我一开始的直觉跟所有人一样:向量召回不够准,调 embedding 模型、调 chunk 大小、调 top-k。调了一周,从 40% 调到 60%,再也上不去了。
直到我坐下来看了一百条 bad case,发现了同一个模式:不是检索不到相关段落,是段落之间的"关系"没被考虑。 比如系统召回了"华东仓库存周报"和"客户 A 的履约记录"——两段单独看都对,但它们之间有一条关键的链路——仓里存了哪些货、这些货关联了哪些履约单、履约单属于哪些客户——这段链路 RAG 完全不知道。它就两段孤立的文本,让 LLM 去猜它们怎么连。LLM 猜错了。
RAG 的盲区不在"查不到",在"连不上"。
■ RAG 的天花板到底在哪
先把这个说清楚,因为大部分人在 RAG 效果不好的时候,第一反应就是调 embedding、调 chunk、调 top-k。我踩过这个坑——调了两个月,结论是:有些问题就不是参数问题,是架构问题。
RAG 做对了一件事:把"查资料"自动化了。但它有三件事完全没做:
1. 同义不同词。 文档里写的是"库容超限",你问的是"爆仓"——向量距离很远,召不回。这不是 embedding 模型不够好,而是任何基于字面相似度的检索都天然漏掉同义词。
2. 多跳关系。 你问的问题需要跨文档、跨实体走两步以上才能回答。RAG 只能给你"跟问题字面相关"的片段——它不知道片段 A 里的"仓库"和片段 B 里的"履约单"之间有一条 stores → fulfills → Order 的关系链。
3. 逻辑约束。 业务里的硬规则——"金额超 5000 必须走总监审批"——RAG 只能当作文本拼进 prompt,没法当约束执行。LLM 可能违反而不知。
RAG 能做的✅① 单文档问答② FAQ 匹配③ 已知句式检索RAG 做不到的——这就是 OAG 的入场理由❌ 同义不同词("库容超限" vs "爆仓")❌ 多跳关系(仓→货→单→客,跨四张表)❌ 硬约束执行("金额>5000 不走总监审批就是违规")这三件事,任何基于"字面相似度"的检索都解决不了
图1:RAG 的能力边界。右边三件事,就是 OAG 要补的。
这三件事的共同病灶:缺乏对"概念之间关系"的显式建模。 同义词是关系,多跳是关系,约束也是关系。RAG 把这些关系全部交给了向量和 LLM 去"猜"——猜对算命好,猜错算翻车。
■ OAG 的核心思路:不猜关系,定义关系
OAG(Ontology-Augmented Generation)做的事,用一句话说:
在 RAG 的检索管道理,插入一层"关系索引"——不是靠向量算"谁跟谁像",而是靠本体告诉你"谁跟谁怎么连"。
回到爆仓的例子。在 OAG 里,处理这条查询的流程是:
# ===== ① 本体查询扩展 =====
# 先把用户问题里的词,映射到本体里的实体和关系
"华东仓" → Warehouse (hasRegion: "华东")
"爆仓" → CapacityExceeded (owl:equivalentClass 库容超限)
"影响客户" → 解析为 property chain: stores → contains → Order → belongsTo → Customer
# ===== ② 双路检索 =====
# 路径 A:图谱遍历(确定性)
MATCH (w:Warehouse {region:"华东", status:"CapacityExceeded"})
-[:stores]->(g:Goods)
<-[:contains]-(o:Order {fulfillmentStatus:"Pending"})
-[:belongsTo]->(c:Customer) RETURN c.name, o.orderId
# 路径 B:向量检索(补充性)
# 并行跑 top-10 语义相似片段,捞图谱可能漏的边缘证据
# ===== ③ 推理校验 =====
# 推理机对候选结果跑 OWL 公理:
# - CapacityExceeded ⊑ AbnormalStatus → 子类继承,自动打异常标签
# - ∃ belongsTo.Customer ⊑ AffectedEntity → 满足条件的客户自动归类
# ===== ④ 融合 → LLM 生成 =====
# 把图遍历结果 + 向量召回片段 + 推理校验结论,作为 context 喂 LLM 生成注意第三行——owl:equivalentClass。就这么一条声明,解决了"库容超限"和"爆仓"在向量空间里离得八丈远的问题。不是靠更好的 embedding,是靠显式定义了概念之间的等价关系。
这是 OAG 和 RAG 的根本区别:
对比维度 | RAG(向量检索 + prompt 拼接) | OAG(本体 + 图谱遍历 + 推理机) |
|---|---|---|
检索逻辑 | 问"爆仓"→ embedding 算相似度 → 返回 top-k 片段。片段之间不认识彼此。 | 问"爆仓"→ 本体解析为 CapacityExceeded(等价类展开)→ 沿 property chain 遍历 → 返回的是关系完整的子图。 |
同义词 | "库容超限"和"爆仓"在向量空间里距离很远。召不回就是召不回。 | owl:equivalentClass 一条声明,两个词在检索层就等价了。不是靠更好的 embedding,是靠定义。 |
多跳关系 | 不支持。LLM 拿到几个孤立的片段,自己猜它们怎么连。猜错就是幻觉。 | property chain 图谱遍历:Warehouse → stores → Goods → Order → Customer,每一跳都是显式的边,不走概率。 |
硬约束执行 | 约束写在 system prompt 里:"请注意金额超 5000 必须审批"。LLM 可能忘、可能绕、可能忽略。 | 约束写成 OWL 公理。推理机逐条校验候选结果,违反的一律排除。不存在"忘了"这回事。 |
可解释性 | "这个答案为什么对?"→ 因为这几个片段的相似度最高。但相似度高 ≠ 逻辑对。 | "这个答案为什么对?"→ 因为经过 property chain A→B→C,推理机通过了公理 X。每一步都可以回溯和审计。 |
更新与维护 | 文档变了→重新 embedding。简单粗暴,但每次都是全量重跑。 | 本体变更走版本管道(建模→测试→部署→同步),实例数据增量摄入。维护链路长但变更安全。 |
最适合的场景 | 单文档问答、FAQ 匹配、不需要推理的查资料型问题。 | 合规校验、供应链溯源、指标口径对齐——需要"走两步以上才能回答"的问题。 |
一句话:RAG 解决"查得到",OAG 解决"查得对"。 查得到靠向量,查得对靠关系。两者不是替代——是覆盖不同的问题复杂度。
但是不要忘了性能开销
■ 我实际搭了一个能跑的 OAG 管道
说完了理念,说工程。我这个项目的技术栈是 OWL/SWRL + Apache Jena TDB2 + Neo4j + SPARQL,在这个基础之上加了 OAG 检索层。架构入下图:
用户问题"华东仓爆仓,影响哪些客户的履约?"① 本体查询扩展实体链接(Warehouse/CapacityExceeded) + 同义词展开(owl:equivalentClass) + property chain 解析▼ 双路混合检索 ▼②a 图谱遍历(确定性路径)沿 property chain: Warehouse→stores→Goods→Order→belongsTo→Customer②b 向量检索(补充边缘证据)语义相似度 top-10 召回候选片段补充图谱可能遗漏的上下文②c 候选融合 · 去重 · 初始排序双路结果合并为统一候选集③ 推理校验 ⬅ OAG 独有能力层OWL 公理执行:类层级检查 · 属性域值验证 · 子类继承推断 · 不一致检测例:CapacityExceeded ⊑ AbnormalStatus → 自动给爆仓打异常标签,触发受影响方分类④ LLM 上下文增强生成 → 结构化输出以校验后的子图+片段作为 prompt 上下文,生成最终答案OAG 执行管道 · 5 步,自上而下
图2:我这个项目的 OAG 管道实际架构。③ 推理校验是跟 RAG 拉开差距的核心层。
这个架构跑起来之后,供应链问答的准确率从 60% 跳到 85%,没调任何参数。就加了本体那一层。
但我得诚实说一句:图遍历那条路径不是万能的。 属性链定义对了,它就是精确的。定义错了,结果是错的但不自知。这也是为什么有推理校验层——至少能用公理发现逻辑矛盾。但公理本身定义得对不对,还是得人来审。
■ 什么时候该上 OAG,什么时候别折腾
我不想把 OAG 吹成万能。有些场景上了是过度设计。用三个问题自检:
1. 你的核心查询需要跨实体"走两步"以上吗? 要 → OAG。单文档、单实体 → RAG 够用。 2. 你的业务里有"同义但不同词"的概念吗? 有且经常翻车 → OAG 的等价类声明一口气解决。没有 → 先别加层。 3. 你的业务规则是显式的、可枚举的吗? 是(如合规规则、财务科目关系)→ OWL 公理化直接上。都是"看情况"→ 别建模,建了也得推翻。
还有一个成本问题。建模本身有前期投入:一个中等复杂度的业务域(30-50 Class,100+ Property),我自己干大概 3-5 人天。如果用 LLM 辅助抽初版本体,能砍到 2-3 人天,但抽出来的东西得人审——LLM 会抽歪,比如把"子公司"抽成"竞争对手"。
维护是个更长期的账。本体不是建完就完了——业务规则变、组织架构变、新系统接入,本体得跟着动。我这套有版本管道和实例数据自动迁移,但也不是零成本。相比 RAG 的"喂新文档重新 embedding",OAG 的维护链路确实长。如果你团队没有能写 OWL 的人,建议从最核心的 5 个概念起步,跑稳了再扩。
■ 跟 GraphRAG 到底是什么关系
聊 OAG 绕不开 GraphRAG,我一句话说清楚两者的关系:
GraphRAG 靠 LLM 自动建图,OAG 靠人工建模本体。前者快但不可控,后者慢但确定。不是谁替代谁——不同场景选不同工具。
GraphRAG 的优势:文档丢进去,LLM 自动抽实体、抽关系、建社区摘要。适合探索性分析——你不知道数据里有什么,让模型帮你发现。
GraphRAG 的坑:抽取质量不稳。同一个"客户",在文档 A 里是 Customer,在文档 B 里可能被抽成 Client 甚至抽丢。多跳查询的每一跳都建立在抽取结果上——一跳抽歪了,后面全跑偏。
OAG 反过来:前期建模花时间,但一旦建好,关系的确定性远高于 LLM 抽取。适合对精度有硬要求的场景——合规、财务、供应链这种"错一次就是事故"的。
我自己在项目里的做法:先用 OAG 覆盖核心 20% 的高精度场景(供应链合规、指标口径、审批规则),再用 GraphRAG 做剩余 80% 的探索性分析。两套结果合并排序。不是二选一,是分层用。
■ 诚实地说局限
OAG 现在离"随便一个团队就能上"还差得远:
1. 建模门槛。 我花了三个月才把供应链本体建到能用的程度。不是因为技术难,是因为要跟业务方反复对概念。本体不写代码,但需要精确描述业务——这件事的瓶颈永远是"懂业务的人有没有时间坐下来跟你对"。
2. 推理性能。 Jena TDB2 在小规模下跑得很快,但我不知道 10 万 Class + 百万级实例时推理机会不会卡。没实测过这个量级,没发言权。中型项目现在完全够,大规模未知。
3. 生态。 RAG 有 LangChain、LlamaIndex 一整套生态,OAG 目前基本得手搭。Protégé 能帮建模,Jena 能跑推理,Neo4j 能存图——但三者之间没有一套开箱即用的集成方案。我自己写胶水代码写了快两周。
但如果用一句话总结我的判断:检索的下一步不是更准的向量,是更清楚的关系。OAG 不是 RAG 的替代品——是 RAG 够不到的那些问题,唯一的解法。
三个问题,想听听你的实际情况: 1. 你现在的 RAG 项目里,有没有一类问题是"怎么改参数都答不对、但你知道是关系没连上"的?具体是什么问题? 2. 如果让你在现有检索系统里先建 5 个核心本体概念,你会选哪 5 个? 3. 你觉得 OAG 最大的落地阻碍是哪一项:建模人力不够、推理性能不确定、还是团队里没人懂本体? 评论区聊聊。我下篇用 GraphRAG 的成本视角接着拆这个问题。