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 驱动的自主检索

相关推荐
水月清辉4 小时前
CSS 常用语法详解
前端·css
Eric_见嘉5 小时前
打开这个 VSC 设置「组件引用位置」和数量就都清楚了
前端·typescript·visual studio code
李高钢5 小时前
Python Tornado 框架入门:从零搭建你的第一个异步 Web 应用
前端·python·tornado
宁风5 小时前
JavaScript:函数体系-1
前端·javascript
mmsx5 小时前
Android 手簿 ADB 无线调试全攻略:USB 转 WiFi 一键连接
android·前端
guwentian5 小时前
Rolldown vs esbuild vs Webpack:Rust 打包器大战我们该怎么选
前端·webpack·rust·esbuild
特立独行的猫A6 小时前
用纯 Rust 重写 Podcastfy:把网页、PDF 和一段文字,变成一档双人对话播客
前端
oooo_z6 小时前
美股历史K线数据API接口选型指南:iTick覆盖1分钟到月线全周期
服务器·前端·javascript
今日无bug6 小时前
从 0 到 1 搭建端侧 AI 项目:DeepSeek-R1 + WebGPU + React + TS + Tailwind 全栈笔记
前端·react.js·typescript
mmsx6 小时前
MapLibre 实战 08|GPS 点漂了几百米才被发现:GCJ-02 纠偏原理与"转两次"陷阱
android·前端