Skip to content

InterX - 知识图谱增强 ​

上一篇聊了多通道检索系统如何从上万个 chunk 里精准找到相关内容。但有一个根本性的问题它解决不了:跨章节推理。

用户问"空调制冷效果差",首跳检索命中的是"常见原因"章节的 chunk。但解决方案在"维护保养"章节——两个章节之间没有任何字面重叠,BM25 和 Dense 向量都找不到它们的关联。

知识图谱就是为了解决这个问题而引入的。它不是传统意义上需要人工标注的知识图谱,而是一种"Agentic RAG 冷启动"的证据驱动建图方法。

核心思路:用 QA 证据种子,而不是 LLM 盲猜 ​

传统知识图谱构建有两种路径:

  1. 人工标注:成本高,40 本手册、上万个 chunk pair,根本标不完
  2. LLM 盲猜:对所有 chunk pair 调用 LLM 判断是否有关系,成本爆炸(假设 5000 个 chunk,pair 数量是 5000×4999/2 ≈ 1250 万),而且 LLM 对不相关的 pair 大概率回答"无关",噪声巨大

我们的做法完全不同:利用 350 条 QA 评估数据中的证据引用作为种子。

这些 QA 数据是比赛提供的,每条数据标注了"正确答案引用了手册的哪些行"。这些引用天然就是 chunk 之间的关系——如果两个 chunk 同时被一条 QA 引用,它们大概率在语义上相关;如果一个 QA 的证据分散在不同章节,那这些章节之间就存在跨章节关联。

基于这个洞察,我们设计了五阶段流水线。

五阶段建图流水线 ​

Phase 1: 解析证据引用 → evidence_resolved.json
         从 350 条 QA 中提取证据引用,解析为结构化数据
         产出: 1699 条引用,94.5% 解析率

Phase 2: 行号到 Chunk 映射 → evidence_mapped.json
         将手册行号映射到具体的 chunk ID
         方法: 二分查找 + 区间重叠检测

Phase 3: 构建图结构 + CO_EVIDENCE 边 → Kùzu graph.db
         同一条 QA 引用的 chunk 之间建立 CO_EVIDENCE 边
         权重: 0.5(证据共现,非直接语义关系)

Phase 4: LLM 语义边提取 → semantic_edges.json
         对跨章节的 chunk pair,调用 LLM 判断是否存在语义关系
         499 个 batch,仅 2 次失败
         严格 YES/NO 判定,不允许模糊回答

Phase 5: 写入 SEMANTIC 边 → 完整图谱
         LLM 确认的语义关系写入图数据库
         权重: 1.0(直接语义关系)

最终产出两类边:

边类型数量权重来源LLM 成本
CO_EVIDENCE48,508 条0.5QA 证据共现统计零
SEMANTIC3,084 条1.0LLM 确认的语义关系按 batch 计费

48,508 条 CO_EVIDENCE 边是纯脚本构建的——没有任何 LLM 调用。这是整个设计最精妙的地方:我们用 QA 证据引用作为"免费"的关系信号,只对真正需要判断的跨章节 pair 才调用 LLM。

两级置信度图扩展 ​

图建好了,怎么用?

检索阶段,首跳命中的 chunk 作为种子节点,然后在图上做 BFS 扩展。两种边的权重不同:

  • SEMANTIC 边(权重 1.0):LLM 确认的语义关系,置信度高
  • CO_EVIDENCE 边(权重 0.5):证据共现统计,置信度中等

扩展时的评分公式:

score = edge_weight × hop_decay × seed_score

其中 hop_decay = 1.0 / (1.0 + 0.3 × hops)

这个公式很直觉:

  • edge_weight:边的类型决定基础分,SEMANTIC 边给 1.0,CO_EVIDENCE 边给 0.5
  • hop_decay:跳数衰减,每多跳一跳分数衰减。第一跳衰减到 0.77,第二跳衰减到 0.63,越远越弱
  • seed_score:种子节点自身的检索分数,高分种子扩展出来的节点也更可信

三者相乘,确保了:近的、强关联的、高分种子扩展出来的 chunk 得分高;远的、弱关联的、低分种子扩展出来的 chunk 得分低。

跨章节证据发现:一个真实案例 ​

回到开头的问题:"空调制冷效果差怎么办?"

首跳检索
  │  命中: "常见原因"章节的 chunk
  │  内容: "制冷效果差可能原因包括滤网堵塞、制冷剂不足……"
  │
  ▼ 图扩展(BFS)
  │  通过 CO_EVIDENCE 边 → 发现"维护保养"章节的 chunk
  │  通过 SEMANTIC 边  → 发现"故障排查"章节的 chunk
  │
  ▼ 扩展结果
     新增 8 个跨章节 chunk
     包含: 滤网清洁步骤、制冷剂补充方法、专业维修建议

没有知识图谱,系统只能返回"常见原因"章节的内容——告诉用户原因,但不告诉用户怎么办。有了图扩展,系统自动发现了"维护保养"章节的解决方案,补全了跨章节的证据链。

这就是知识图谱的核心价值:它不是给系统增加了"知识",而是增加了"关联"。手册里的知识本来就在那里,只是分散在不同章节。图谱把它们连起来了。

工程健壮性:不只是算法对了就行 ​

算法思路对了,工程上如果不够健壮,一样跑不起来。我们做了几个关键的工程设计:

每手册独立 Kùzu 数据库 ​

40 本手册,如果全部塞进一个图数据库,内存占用会很大,而且一本手册重建会影响其他手册。所以我们给每本手册建了独立的 Kùzu 数据库——需要重建某本手册时,只动那一个库,其他库完全不受影响。同时也规避了内存泄漏的风险。

增量构建 ​

图数据库本身记录了哪些 chunk pair 已经处理过。Phase 3 写入 CO_EVIDENCE 边时,会先查询是否已存在;Phase 4 提取 SEMANTIC 边时,也会跳过已有边的 pair。不需要额外的状态文件,图数据库本身就是状态。

断点续传 ​

Phase 4 是最耗时的阶段(499 个 batch 的 LLM 调用)。如果跑到一半网络断了或者进程被 kill,不需要从头开始。我们每 20 个 batch 周期性保存进度,--resume 参数可以从上次中断的地方继续。

并发 LLM 提取 ​

单线程串行调用 499 个 batch 太慢了。我们用 ThreadPoolExecutor(4) 并发提取,提速 10-20 倍。同时设置了 pair 数量上限 3000 + 可重现采样(seed=42),保证结果可复现。

同 BigChunk 内 pair 跳过 ​

如果两个 chunk 在同一个 BigChunk(900 tokens 的大块)内,它们已经在同一个 section 里了,层次关系已经通过 chunk 聚合体现,不需要 LLM 再判断一遍。这个优化大幅减少了需要处理的 pair 数量。

检索阶段完全零 LLM ​

最后强调一个关键设计点:知识图谱的检索阶段完全没有 LLM 调用。

图扩展是纯 BFS + 权重计算,确定性算法,延迟可预测。LLM 调用只发生在离线建图阶段(Phase 4),而且是一次性的。图建好之后,检索时的扩展操作就是遍历邻居节点、计算分数、排序——没有任何随机性,也没有任何在线成本。

这也是为什么我们选择 Kùzu 作为图数据库:它是嵌入式的,不需要独立部署,查询性能足够好,而且和 Python 生态集成得很好。

效果总结 ​

指标数值
CO_EVIDENCE 边48,508 条(零 LLM 成本)
SEMANTIC 边3,084 条(LLM 提取)
构建时间约 7.5 小时(一次性离线成本)
检索阶段 LLM 调用0 次
每次检索扩展 chunk约 8 个(两个 RAG 案例均值)

知识图谱在 InterX 中扮演的角色,不是"智能大脑",而是一个"关联索引"——它把手册中分散在不同章节的关联信息预先连接起来,让检索时能跨越 chunk 边界找到完整的证据链。这种"离线建图、在线查图"的架构,既保证了检索质量,又控制了在线成本。