Graph RAG:知识图谱增强检索

进阶 B · Graph RAG:知识图谱增强检索

当知识之间存在关联("A 依赖 B"、"X 是 Y 的子模块"),传统 RAG 无法捕捉这些关系。Graph RAG 用知识图谱把知识织成网。


1. 传统 RAG 的盲区

arduino 复制代码
问题:"项目中哪些模块依赖了 userService?"

传统 RAG:检索到 3 个提到 userService 的文档 Chunk
实际需要:遍历 import 图,找出所有直接/间接引用 userService 的文件 → 可能有 15 个

传统 RAG 只能检索"文本相似"的内容,无法理解"关系"。Graph RAG 弥补了这个缺陷。


2. Graph RAG 架构

markdown 复制代码
文档摄入
    │
    ├──→ 文本分块 → 向量存储(传统 RAG)
    │
    └──→ 实体关系抽取 → 知识图谱(Neo4j / NebulaGraph)
              │
              ▼
        图谱检索
              │
              ▼
    检索结果融合 → LLM 生成

2.1 实体关系抽取(Node.js)

csharp 复制代码
// graph/extract.ts
import { ChatOpenAI } from "@langchain/openai";

interface EntityRelation {
  entities: { name: string; type: string }[];
  relations: { from: string; to: string; type: string }[];
}

class GraphExtractor {
  private llm = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });

  async extractFromDocument(doc: string): Promise<EntityRelation> {
    const response = await this.llm.invoke(`
      从以下文档中提取实体和关系,以 JSON 返回。
      实体类型:模块、组件、函数、API、配置项
      关系类型:depends_on, contains, calls, configures

      文档:
      ${doc}

      返回格式:
      {
        "entities": [{"name": "名称", "type": "类型"}],
        "relations": [{"from": "实体A", "to": "实体B", "type": "关系类型"}]
      }
    `);

    return JSON.parse(response.content as string);
  }
}

2.2 存入 Neo4j

php 复制代码
// graph/store.ts
import neo4j from "neo4j-driver";

const driver = neo4j.driver(
  "bolt://localhost:7687",
  neo4j.auth.basic("neo4j", "password")
);

class GraphStore {
  async insert(entityRelation: EntityRelation): Promise<void> {
    const session = driver.session();

    try {
      // 创建节点
      for (const entity of entityRelation.entities) {
        await session.run(
          `MERGE (n:Entity {name: $name}) SET n.type = $type`,
          entity
        );
      }

      // 创建关系
      for (const rel of entityRelation.relations) {
        await session.run(
          `MATCH (a:Entity {name: $from}), (b:Entity {name: $to})
           MERGE (a)-[r:${rel.type}]->(b)`,
          rel
        );
      }
    } finally {
      await session.close();
    }
  }
}

2.3 图谱检索

vbnet 复制代码
// graph/search.ts
class GraphRetriever {
  async search(query: string): Promise<GraphResult> {
    const session = driver.session();

    try {
      // 1. 找出与查询相关的实体
      const entities = await session.run(`
        MATCH (n:Entity)
        WHERE n.name CONTAINS $query
        RETURN n.name, n.type
        LIMIT 10
      `, { query });

      const entityNames = entities.records.map(r => r.get("n.name"));

      // 2. 查找 1 跳邻居关系(直接依赖/引用)
      const neighbors = await session.run(`
        MATCH (n:Entity)-[r]->(m:Entity)
        WHERE n.name IN $names
        RETURN n.name AS source, type(r) AS relation, m.name AS target
        LIMIT 50
      `, { names: entityNames });

      return {
        entities: entityNames,
        relations: neighbors.records.map(r => ({
          from: r.get("source"),
          relation: r.get("relation"),
          to: r.get("target"),
        })),
      };
    } finally {
      await session.close();
    }
  }
}

3. 与文本 RAG 融合

javascript 复制代码
// graph/fusion.ts
async function graphEnhancedRAG(query: string) {
  // 1. 文本 RAG 检索
  const textResults = await textVectorStore.similaritySearch(query, 5);

  // 2. 图谱检索
  const graphResults = await graphRetriever.search(query);

  // 3. 融合生成
  const prompt = `
## 相关文档
${textResults.map(d => d.pageContent).join("\n\n")}

## 知识关联
${graphResults.relations.map(r => `"${r.from}" --[${r.relation}]--> "${r.to}"`).join("\n")}

## 问题
${query}

请结合文档内容和知识关联来回答。如果知识关联揭示了文档中不明显的依赖/module关系,请特别指出。
`;

  return llm.invoke(prompt);
}

4. 适用场景与局限

场景 传统 RAG +Graph RAG
"React.memo 怎么用?" 没帮助
"哪些模块依赖了 AuthService?" ⚠️ 可能漏 ✅ 精确遍历
"支付流程涉及哪些服务和中间件?" 能搜到部分 ✅ 完整链路
"这个 Bug 可能影响哪些模块?" 粗糙 ✅ 追踪调用链

建议

  • Graph RAG 是传统 RAG 的增强,不是替代
  • 知识关系密集的场景(代码库、微服务文档、API 文档)收益最大
  • 需要额外维护 Neo4j 实例和抽取流水线,投入产出需评估

上一篇:A · 多模态 RAG:图片与表格检索 下一篇:C · Agentic RAG:Agent 驱动的自主检索

相关推荐
陈随易7 小时前
MCP协议第5次更新,从打电话到微信聊天的巨大变革
前端·后端·程序员
omnijk7 小时前
前端工程化
前端
做前端的娜娜子7 小时前
前端必看!我把一段"能跑不敢动"的报表代码用 AI 重构成了组件(附完整 Prompt)
前端·ai编程
hunterandroid7 小时前
[鸿蒙从零到一] ArkUI 动画与转场实战:状态驱动、组件过渡与页面衔接
前端
何时梦醒7 小时前
React + TypeScript + Vite 实战:从零构建 Color Picker 应用
前端·javascript·架构
谁在黄金彼岸8 小时前
Nuxt.js 详解(一):Vue 开发者为什么要关注 Nuxt
前端
英勇无比的消炎药8 小时前
TinyRobot v0.5.0 深度解读(三):Layout 组件——如何组织复杂工作区的页面布局
前端·vue.js
默_笙8 小时前
😋 我让 DeepSeek-R1 在浏览器本地跑了起来,后端同事说"你认真的?"
前端·javascript
英勇无比的消炎药8 小时前
TinyRobot v0.5.0 深度解读(四):CLI 脚手架——从零搭建 AI 应用的工程化实践
前端·vue.js·github