Ch26: 知识图谱 PMI 源码——构建、遍历与检索
Part 8: WeKnora 源码走读 前置:Ch25 RRF、Ch11 Graph RAG 后续:Ch27 自适应分块源码
结论先行:WeKnora 图谱路 = 摄入时 PMI 建边 + 查询时实体识别 + 1–2 跳遍历 + chunk 召回。比 RAGFlow 的 LLM 抽三元组 便宜;比纯向量 擅多跳。
一、PMI 建图(摄入侧)
\[PMI(x,y) = \log_2 \frac{P(x,y)}{P(x)P(y)}\]实现步骤(找 graph/ 或 knowledge_graph/ 包):
1. 从 chunk 抽实体(分词+词性 / NER)
2. 段落内共现计数 count(x,y)
3. 算 P(x), P(y), P(x,y)
4. PMI > threshold → 加无向边,权重=PMI
5. 持久化(内存图 / DB / 文件)
冷启动:文档 < 几百篇时 PMI 不稳定——图谱路权重应保守。
二、查询侧(检索)
query → 实体识别 ["WeKnora", "知识图谱"]
→ 从图扩展 1–2 跳邻居实体
→ 检索含邻居实体的 chunk
→ 作为第三路 hits 进入 RRF
与 BM25 差异:query 不含「PMI」一词,仍可能通过「知识图谱→PMI→共现统计」链找到答案(Ch04 例题)。
三、源码阅读清单
rg "PMI\|PointwiseMutual" -g '*.go'
rg "GraphRetriever\|KnowledgeGraph" -g '*.go'
关注:
- 实体抽取停用词表(噪声边来源)
- 共现窗口:chunk 内还是 doc 内
- 增量更新:文档删除时是否重算 PMI
四、失败模式 ↔ issue 类型
| 现象 | 查哪里 |
|---|---|
| 多跳问答全错 | 实体识别 / 跳数限制 |
| 图谱爆炸 | PMI 阈值过低 |
| 与向量重复 | RRF 正常;图谱应补 独有 recall |
| 构建慢 | 全库重算 vs 增量 |
竞赛 L4 方向:增量 PMI、实体 linking 改进——见 Ch10。
五、对比 RAGFlow Graph RAG
| WeKnora PMI | RAGFlow LLM Graph | |
|---|---|---|
| 成本 | 低 | 高 |
| 关系语义 | 共现 | 显式 relation |
| 维护 | 统计重算 | 重跑 LLM 抽取 |
见 Ch17。
章末 · 大师自检
- 口述 PMI 高/低的含义 + 例子
- 画出 query → 实体 → 遍历 → chunk 四步
- 说明冷启动时为何应降低图谱路权重
- 在仓库定位 PMI 或 Graph 相关 Go 包名