店长早上打开仓库,发现新鲜草莓缺货。店里有一款叫“双人下午茶”的套餐,名字里没有“草莓”两个字。店长问:
草莓缺货,为什么双人下午茶也会受影响?
先不用任何数据库术语。看看店里原本就有的三份资料:一张果酱配方、一张蛋糕配方、一张套餐组成表。它们分别记着下面这些事实。
{{figure:01-value|图 5-1 三份真实配套资料各说一件事;连起来,才能解释草莓和双人下午茶之间的关系。}}
从右上方读:双人下午茶包含招牌蛋糕,招牌蛋糕需要草莓酱,草莓酱需要新鲜草莓。 所以草莓缺货可能沿着这条链影响双人下午茶的供应。
再从图底部反过来想:草莓不够,草莓酱可能做不了;果酱不足,招牌蛋糕可能做不了;套餐里的蛋糕不够,双人下午茶就可能无法按现有组成出售。每一步都有一份资料支持,没有凭感觉补出一条关系。
这里的“可能”有实际含义:店里也许还剩预制果酱或蛋糕,也许临时改了套餐配方。仅靠配方关系,不能断言今天已经售罄;这些情况还要查库存与最新安排。
这三份配套资料没有哪一份直接写着“草莓缺货影响双人下午茶”。回答需要把它们连接起来:
| 手里只有哪份资料 | 知道什么 | 还缺什么 |
|---|---|---|
| 双人下午茶组成表 | 套餐包含招牌蛋糕 | 蛋糕需要什么 |
| 招牌蛋糕配方 | 蛋糕需要草莓酱 | 果酱需要什么 |
| 草莓酱配方 | 果酱需要新鲜草莓 | 哪些商品使用果酱 |
第四章的关键词和语义检索仍然可以找到相关资料;它们也可能找齐三份。但如果候选只有套餐介绍和某段草莓介绍,就还不能完整解释中间的蛋糕与果酱。图检索增加的能力,是按明确的“包含”“需要”关系找到连接路径,并取回路径上的各份原文。
这不是拿甜品店比喻某个 IT 系统。本章数据库里真正放的就是这套配方、套餐和店员分工。课件里的问题可以用代码执行,5.12 会展示相同资料与预算下的实际对照,不预先宣称哪种方式一定失败。
图上的新鲜草莓、草莓酱、招牌蛋糕、双人下午茶,叫实体节点;“需要”“包含”的箭头叫关系;一串连接起来的箭头叫路径。根据这种结构找资料,就是本章要做的图检索。
“图索引”在这里指用实体、关系和来源组织检索证据。Neo4j 的属性索引、唯一约束负责快速找对象、避免编号重复;它们不会自动替我们读配方、判断“需要”还是“不需要”。
{{figure:01-pipeline|图 5-2 相关文字检索与关系检索同时提供资料,合并后再回答店长的问题。}}
两种查找方法一起工作:Milvus 查相关文字,Neo4j 查已知关系,再把候选合并、排序、核对预算,交给模型组织回答。默认每次进入 RAG 都给图通道一次查找机会,不先要求学生训练一个“这是不是关系问题”的分类器。
图通道仍有边界:没有找到可靠对象就返回空候选;找到对象后限制知识域、关系类型、路径长度与数量。它不会因为用户提到甜品,就把整家店所有东西都塞进答案。
先体验统一入口:
python -m graph_qa ask \
--question "草莓缺货,为什么双人下午茶也会受影响?" \
--mode hybrid --scope 甜品店
hybrid 表示相关文字和图关系一起召回;甜品店 指这家教学甜品店的资料范围。后面还会用 milvus、graph 分别执行同一道题。
现在把问题升级为“草莓缺货,为什么双人下午茶也会受影响?该通知谁?”前三份组成与配方资料只能解释影响链;通知谁,还要增加第四份资料——套餐分工表。配套资料里,套餐上架由小陈负责,通知位置是收银台。这也是一条有原文支持的关系,不能让模型因为“做蛋糕”三个字就猜应该通知烘焙师。
巧克力饼干使用可可粉,是这套数据中的负例:它不能只因为“也是甜品”就被连到草莓上。普通的打包规则、营业说明又可能直接从一段原文得到答案,未必需要图。
{{runtime:overview}}
本章接下来按刚才读图的顺序学习:先表示东西和关系,再把资料写入图,识别用户说的是哪个东西,找到路径、补上原文,最后与已有检索融合。懂了这幅图,再学习节点、关系、多跳,就不需要先懂企业系统架构。