Ch42: 挑战深读④——图谱构建、PMI vs LLM 与增量更新
Part 10 · 合并 challenges #4 + #13 · Ch26 PMI 源码 · Ch31 Wiki 自维护 · Ch23 EventManager
结论先行:WeKnora 默认 PMI 统计图谱——便宜、无标注,但噪声边多、无因果、缺消歧;LLM 三元组 准但按 chunk 计费,无法每日全量重建。维护与实时性的共同瓶颈是 增量一致性:文档删改后 PMI 共现、chunk、向量若未级联重算,多跳检索会带过期边。EventManager + DocumentUpdated 插件链 是把 #4 与 #13 合成一条 PR 线的正确切口。
一、日常类比:便利贴墙与画线
知识库像一面贴满便利贴的墙;图谱是在便利贴之间画线。「谁该连谁?」PMI 靠 共现频率 猜——成本低,但「BM25 与向量检索常一起出现」会被画成强边,却不回答「BM25 为何优于向量」。LLM 像请专家逐张读贴再画线——语义对,但墙每改一张就要重读周边。增量更新 就是:改一张贴时,哪些旧线该删、哪些新线该加,且检索在更新过程中仍要自洽。
二、PMI vs LLM:路线对照
| 维度 | PMI 统计 Ch26 | LLM 三元组 (GraphRAG 类) |
|---|---|---|
| 构建成本 | 低:离线共现脚本 | 高:每 chunk 一次 LLM |
| 数据需求 | 无标注 | 可选 few-shot / 校验 |
| 关系质量 | 相关≠因果;小语料 PMI 不稳 | 可消歧、可抽因果表述 |
| 维护 | 删 doc → 共现计数需回滚 | 删 doc → 需删/重抽三元组 |
| WeKnora | ★ 默认三路之一 | 实验/可选 |
| 冷启动 | 边少、噪声大 | 未跑完 ingestion 无图 |
混合贡献方向:PMI 产候选边 → LLM 批量校验 top-K 高 PMI 边 → 写入持久化图谱;日常增量仍走 PMI + 校验队列,控制 LLM 预算。
三、增量更新三难(#13)
| 难点 | 表现 | 与 #4 的交点 |
|---|---|---|
| 级联影响 | 改一段 → 多 chunk、多 PMI 对重算 | 图谱边与 chunk 不同步则多跳错 |
| 更新期一致性 | 新旧向量混检,答案随机 | 双缓冲或版本化索引 |
| 版本共存 | 对话中途 doc 换版,上下文断裂 | Ch31 矛盾标记 |
WeKnora 在 wiki/ 增量 PMI 上领先于多数平台,但 chunk 级 re-embed 与图谱级联 仍可能漏触发——见 Ch23 摄入链是否完整订阅 DocumentUpdated。
四、EventManager 增量链(大师 grep)
rg -n "DocumentUpdated|ChunksIndexed|PMI|pmi" internal/ --glob "*.go" | head -40
rg -n "Register\(|Emit\(" internal/eventmanager/ --glob "*.go"
期望 DAG(概念):
DocumentUpdated
→ 语义 diff(可选:仅 typo 跳过 re-embed)
→ 受影响 chunk_id 列表
→ re-embed job + 向量 upsert
→ PMI 增量:回滚旧 doc 贡献 → 重算共现 → 删/降权边
→ ChunksIndexed / GraphUpdated 事件
与 lab/corpus 联动:改 weknora-arch.md 中「向量库个数」后,应用 benchmark/smoke-10.jsonl 中 zh-003 类时效题验证图谱+向量是否同步。
五、诊断表
| 症状 | 先查 | 关联 case/issue |
|---|---|---|
| 多跳全错 | 实体抽取、max_hops | Ch26 |
| 噪声边爆炸 | PMI 阈值、中文停用词 | 贡献:词典 PR |
| 删 doc 后边仍在 | 增量 PMI 未触发 | #13 · EventManager 插件 |
| 小库图谱误导 | 冷启动 | graph_weight=0 直到 doc 数 > N |
| 更新后答案 flip-flop | 双索引未原子切换 | 双缓冲方案 |
六、五平台更新策略(简表)
| 项目 | 增量 | 图谱 | 弱点 |
|---|---|---|---|
| WeKnora | 图谱增量 ★ | PMI | chunk 级联可能不全 |
| Dify | Celery 异步 | 弱/无 | 更新期仍检旧 chunk |
| RAGFlow | 偏全量 | — | 大 PDF 代价高 |
| FastGPT | QA 全量重生 | — | LLM 成本高 |
七、实验(约 90 分钟)
- 构建:上传 lab/corpus 10 篇相关 doc,记录图谱边数与
zh-003baseline。 - 删除:删 1 篇 hub 文档,检查关联 PMI 边是否消失或降权(应变化)。
- 对比:「双路 BM25+向量」vs「三路含图谱」在 5 条多跳 hard 上的 Recall@5。
- 增量:改同一 doc 一段关键事实 → 跑 smoke-10 子集 → PR 附 before/after 四指标(faithfulness / latency / 边数 / chunk 数)。
八、贡献方向(Volunteer PR)
DocumentUpdated插件:输出affected_chunk_ids+ 触发 re-embed + PMI 回滚 Ch23- 中文实体 linking 小词典(产品代号、错误码)
- 冷启动配置与 admin 文档:
min_docs_for_graph - 与 Ch31 巡检联动:过期 doc 自动排队 re-ingest
- 图谱路 超时降级(与 Ch43 延迟章衔接)
章末自检
- 用一句话对比 PMI vs LLM Graph 的 成本与质量 trade-off
- 解释「删文档后 PMI 边仍存活」的根因与 EventManager 修复点
- 说清冷启动时
graph_weight=0的理由 - 画出从
DocumentUpdated到ChunksIndexed的最小事件链(≥4 步)