摘要:本文以智汇园区资产运营管理为真实案例,完整阐述从业务数据到 AI 可理解的本体模型的全过程。涵盖实体/属性/关系的判断标准、押金等边界案例的建模取舍、Apache AGE + PostgreSQL 的混合架构方案,以及智能问答、合同抽取、驾驶舱等 AI 场景的本体映射方法。适合正在做园区数字化或资产运营 AI 化的产品经理、架构师、开发者阅读。

一、为什么需要本体?

半年前我们团队开始做园区资产运营管理系统,目标是让 AI 能准确回答这些问题:

  • “A-101 这个月的租金交了没有?”
  • “哪些租户逾期超过 30 天且月租金超过 2 万?”
  • “微光科技的押金能退吗?”

最开始的做法很直接:把合同 PDF、Excel 台账一股脑喂给大模型。结果问题很明显——AI 经常"胡编",问押金它回答租金,问逾期它答非所问。

问题出在哪?大模型理解的是文字,不是业务。它不知道"合同"和"应收计划"是生成关系,"押金"和"租金"虽然都是钱但生命周期完全不同。

本体就是来解决这个问题的——把散落在各个表格、文档中的业务概念,组织成 AI 能精确理解的知识网络。

在这里插入图片描述

二、实体、属性、关系的判断标准

这是本体设计中最实际也最容易困惑的问题。我们直接用园区数据说话。

黄金法则

能独立变状态、被多次引用、有 CRUD 操作 → 实体
反之 → 属性

案例:一份租赁合同

原始文本:“甲方将 A-101 室(建筑面积120㎡)出租给微光科技有限公司,月租金24,000元,押金48,000元。租期2024.05.01至2026.04.30,按季付。”

我们逐项分析:

信息 判断逻辑 建模结果
A-101 室 有"已租/空置/装修中"等状态,被合同、工单、企业多次引用 Room(实体)
微光科技 有信用评分、行业分类,独立生命周期 Enterprise(实体)
ZY-2024-001 有生效/到期/变更/违约等完整生命周期 LeaseContract(实体)
月租金 24,000 元 合同的数值属性,无独立操作 LeaseContract.monthRent(属性)
建筑面积 120㎡ Room 的固有属性 Room.area(属性)
按季付 合同付款方式枚举值 LeaseContract.cycle(属性)
押金 48,000 元 这个最有争议——往下看 Deposit(实体)

争议焦点:押金是实体还是属性?

直觉上押金就是"一个金额数字",设成合同的一个字段就行了。但真实业务告诉我们不是这样:

押金有完整生命周期:
  收取 → 占用 → 部分抵扣 → 剩余退还

押金有多个业务操作:
  • 合同到期全额退还
  • 上期欠费从押金扣款
  • 续租时旧押金转新押金
  • 提前退租扣押金作违约金

押金是一个"有行为能力的对象":
  Deposit {
    amount: 48000,        ← 金额
    usedAmount: 5000,     ← 已抵扣
    status: "partially_used", ← 独立状态
    refundDate: "2026-05-01",
    source: "新签"          ← 来源追溯
  }

如果押金只是个属性,以上所有操作都得写在业务代码里硬编码。拆成实体后,Cypher 查询自然表达:

// 查询微光科技的押金状态
MATCH (e:Enterprise {name:'微光科技'})-[:SIGNS]->(c:LeaseContract)
MATCH (c)-[:HAS_DEPOSIT]->(d:Deposit)
RETURN d.amount, d.usedAmount, d.amount - d.usedAmount AS refundable,
       d.status, d.refundDate

判断标准总结:有 CRUD、有状态流转、被多个对象引用的 → 实体。否则 → 属性

三、哪些是关系?关系何时提升为实体?

关系命名规则

关系是两个实体之间的"动词":

Enterprise -[:SIGNS]-> LeaseContract        // 企业签订合同
LeaseContract -[:GOVERNS]-> Room            // 合同管辖房间
LeaseContract -[:GENERATES]-> PaymentPlan   // 合同生成应收计划
Enterprise -[:OCCUPIES]-> Room              // 企业占用房间
Enterprise -[:SUBMITS]-> ServiceTicket      // 企业提交工单
Park -[:HAS_BUILDING]-> Building            // 园区包含楼栋

边界案例:关系带属性时提升为实体

最典型的是"付款":

// 错误做法:把付款当关系
Enterprise -[:PAYS]-> PaymentPlan
// 问题:付款有付款方式、付款时间、凭证号、操作人,这些属性挂在哪里?

// 正确做法:把 PAYS 提升为 PaymentRecord 实体
Enterprise -[:MAKES]-> PaymentRecord -[:SETTLES]-> PaymentPlan

PaymentRecord {
  id: "PAY-2026-001",
  payMethod: "银行转账",     ← 属性
  payTime: "2026-05-05 14:30", ← 属性
  voucherNo: "BOC-20260505-001", ← 属性
  operator: "张三"           ← 属性
}

判断规则:关系本身如果有属性、有状态、需要独立查询 → 提升为实体。

四、园区资产运营的核心本体模型

六域全景

空间域 合同域 企业域 财务域 服务域 政策域
Park LeaseContract Enterprise PaymentPlan ServiceTicket Policy
Building ContractChange Contact PaymentRecord ServiceProvider SubsidyApplication
Floor Deposit Industry Invoice
Room ContractTemplate CreditScore OverdueLetter
ParkingSpace LegalCase

核心关系图

// 创建一个完整履约画像的图查询
MATCH path = (e:Enterprise {name:'微光科技'})
  -[:SIGNS]->(c:LeaseContract)
  -[:GOVERNS]->(r:Room)
MATCH (c)-[:GENERATES]->(pp:PaymentPlan)
OPTIONAL MATCH (pp)-[:REFERENCED_BY]->(inv:Invoice)
OPTIONAL MATCH (e)-[:SUBMITS]->(st:ServiceTicket)
OPTIONAL MATCH (c)-[:HAS_DEPOSIT]->(d:Deposit)

RETURN {
  企业: e.name,
  合同: c.no,
  房间: r.roomNo,
  押金: d.amount,
  应收: collect({
    期次: pp.period,
    金额: pp.amount,
    状态: pp.status,
    发票: inv.invoiceNo
  }),
  工单数: count(st)
}

五、技术选型:为什么选 Apache AGE 而不是 Neo4j

选型时我们面临一个实际问题:知识图谱的数据从哪里来?

如果选 Neo4j,架构是这样:

PostgreSQL(业务系统)──CDC/Kafka──→ Neo4j(知识图谱)
                              ↑
                         数据同步管道
                       延迟、不一致、运维

如果选 Apache AGE:

PostgreSQL(同一库)
  ├── 关系表(contract, enterprise, room...)
  └── AGE 图(同一事务里写表和写图)

AGE 是把图数据库"装进"了 PostgreSQL。 对我们最实在的三个好处:

1. 零数据同步

-- 同一个事务里写表和写图,强一致
BEGIN;
  INSERT INTO lease_contract (...) VALUES (...);
  SELECT * FROM cypher('park_graph', $$
    CREATE (c:LeaseContract {no: $1, monthRent: $2})
  $$) AS (v agtype);
COMMIT;

没有 Debezium、没有 Kafka、没有延迟,一个事务搞定

2. SQL + Cypher 混查

-- 关系库做聚合,图库做遍历
WITH overdue_enterprises AS (
  SELECT * FROM cypher('park_graph', $$
    MATCH (e:Enterprise)-[:SIGNS]->(c:LeaseContract)
    MATCH (c)-[:GENERATES]->(p:PaymentPlan)
    WHERE p.status = 'overdue' AND p.overdueDays > 30
    RETURN e.id AS eid, e.name AS name, 
           sum(p.amount) AS total, count(p) AS periods
  $$) AS (eid agtype, name agtype, total agtype, periods agtype)
)
-- 关联关系表做补充
SELECT oe.name, oe.total, oe.periods, 
       e.credit_score, lc.month_rent
FROM overdue_enterprises oe
JOIN enterprise e ON e.id = oe.eid
JOIN lease_contract lc ON lc.enterprise_id = e.id;

3. 完全复用 PostgreSQL 生态

pg_dump 备份、Patroni 高可用、pgAdmin 管理——不需要额外学一套运维工具。

我们的结论:园区资产运营的场景查询深度通常在 3-6 跳(企业→合同→应收→发票),AGE 完全胜任。如果未来需要 20+ 跳的深度图算法(供应链溯源、社区发现),再考虑用 Neo4j 做补充查询层。

六、AI 落地:从本体到智能应用

场景 1:智能合同要素抽取

对应你们实现的 contract-extract.html 页面:

合同 PDF → OCR → NER 抽取 → 本体实例化

抽取结果映射:
  "承租方" → Enterprise.name
  "租赁房屋" → Room.roomNo
  "月租金" → LeaseContract.monthRent
  "押金" → Deposit.amount
  "租期" → LeaseContract.{startDate, endDate}
  "付款周期" → LeaseContract.cycle

自动推理生成:
  LeaseContract -[:GENERATES]-> PaymentPlan × N期
  (根据周期和租期自动计算每期金额和到期日)

场景 2:智能问答

对应你们实现的 tenant-services.html 中的 QA 模块:

# NL2Cypher:自然语言转图查询
用户问题 = "A101这个月的租金付了没?"

# 查询解析
意图: 查询付款状态
实体: Room(roomNo='A-101')
时间: 当前月份
属性: PaymentPlan.status

# 生成 Cypher
MATCH (r:Room {roomNo:'A-101'})<-[:GOVERNS]-(c:LeaseContract)
MATCH (c)-[:GENERATES]->(p:PaymentPlan)
WHERE p.dueDate >= '2026-05-01' AND p.dueDate < '2026-06-01'
RETURN p.status, p.amount, p.dueDate

# 结果 → LLM 组织自然语言"A101室本月租金¥24,000,付款截止日5月5日,目前状态:已收款。"

场景 3:驾驶舱智能指标

对应你们实现的 cockpit.html

本体提供了"可下钻"的数据结构:
  Park → Building → Room:空间维度的下钻
  时间 + 状态 + 企业:多维度交叉分析

AI 增强的根因分析:
  发现"云龙数字港出租率下降"→ 沿本体遍历:
  1. 哪些 Room 退租了?
  2. 退租企业的行业分布?
  3. 同期租金是否有调整?
  → 自动生成分析报告:"3家IT企业因合同到期未续租,建议定向招商同行业补位"

七、实施建议:分步走

Phase 1:梳理本体(1-2 周)

不需要一开始就完美。建议用白板 + Excel 做三轮:

第一轮:列出所有"名词"——合同、房间、企业、账单、发票、押金……
第二轮:标出哪些有自己的状态——押金有状态→实体,楼层没状态→属性
第三轮:画出关系连线——谁和谁有关?关系是什么动词?

Phase 2:存量数据导入(2-4 周)

1. 清洗现有 Excel/ERP 数据
2. 建立实体唯一标识(企业 ID 统一)
3. 写入 PostgreSQL 关系表
4. 通过同一事务写入 AGE 图

Phase 3:AI 能力接入(4-6 周)

1. NL2Cypher 转换层(LLM + Few-Shot)
2. RAG Pipeline(检索图谱 → 组装上下文 → LLM 生成)
3. 规则引擎(逾期 → 催缴 → 律师函的自动流转)

Phase 4:迭代优化(持续)

1. 补充缺失的实体和关系
2. 优化查询性能(AGE 索引、Cypher 调优)
3. 积累 NL2Cypher 训练样本

总结

从 Excel 到知识图谱,我们走过最大的弯路就是把 AI 当"黑盒"——以为投喂大量文档就能得到准确答案。本体的核心价值是让 AI 不再猜,而是沿着预先定义好的业务关系链精确检索。

几条可复用的经验:

  1. 实体/属性分不清时,看它有没有"自己的事要做"——押金可以退、可以扣、可以转,所以它是实体不是字段
  2. 关系带属性时警惕——付款不是一个"动作"而是一个"事件",该拆成实体
  3. Apache AGE 比 Neo4j 更适合业务系统团队——不用部署新数据库、不用同步数据、会 SQL 就能上手
  4. 本体不是一次设计完成的——先定义 80%,剩下的在 AI 落地过程中迭代补齐

最终,你的 AI 能回答的不只是"根据文档推测",而是"根据知识图谱精确查询并引用事实来源"——这就是从 Excel 到知识图谱的质变。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐