一、GraphRAG vs 传统 RAG
| 维度 | 传统 RAG | GraphRAG |
| 检索方式 | 纯向量相似度 | 图遍历 + 向量混合 |
| 多跳推理 | 不支持 | 通过图关系推理 |
| 实体关系 | 隐含在文本中 | 显式存储为图结构 |
| 全局理解 | 局限于单个 chunk | 通过图获得全局视角 |
| 适用场景 | 简单问答 | 复杂推理、关系查询 |
二、架构设计
┌──────────────────────────────────────────────────────┐│ GraphRAG 系统 │├──────────────────────────────────────────────────────┤│ ││ 文档输入 → 实体抽取 → 图谱构建 → 索引建立 ││ ││ 用户查询 → 实体识别 → 图检索 + 向量检索 → 融合生成 ││ │├──────────────────────────────────────────────────────┤│ 存储层 ││ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ ││ │ Apache AGE │ │ pgvector │ │ 关系表 │ ││ │ (知识图谱) │ │ (文档向量) │ │ (元数据) │ ││ └──────────────┘ └──────────────┘ └───────────┘ ││ ││ AI 层 ││ ┌─────────────────────────────────────────────┐ ││ │ tencentdb_ai(实体抽取 / 关系识别 / 生成) │ ││ └─────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────┘
三、数据库准备
— 创建扩展CREATE EXTENSION IF NOT EXISTS vector;CREATE EXTENSION IF NOT EXISTS age;– 设置 search_pathSET search_path = ag_catalog, "$user", public;– 创建知识图谱SELECT create_graph('knowledge_graph');– 文档存储表CREATE TABLE graphrag.documents ( id BIGSERIAL PRIMARY KEY, title TEXT, content TEXT NOT NULL, embedding vector(1024), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW());CREATE INDEX ON graphrag.documentsUSING hnsw (embedding vector_cosine_ops);– 实体表(辅助索引)CREATE TABLE graphrag.entities ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL, entity_type TEXT NOT NULL, description TEXT, embedding vector(1024), source_doc_id BIGINT REFERENCES graphrag.documents(id), UNIQUE(name, entity_type));CREATE INDEX ON graphrag.entitiesUSING hnsw (embedding vector_cosine_ops);
四、核心流程
注意:说明:
注意:向量维度需与你使用的大模型输出维度一致。常见模型维度:OpenAI text-embedding-3-small(1536维)、BGE-M3(1024维)、ChatGLM Embedding(1024维)。
五、实体抽取
— 使用大模型从文档中抽取实体和关系CREATE OR REPLACE FUNCTION graphrag.extract_entities(doc_content TEXT)RETURNS JSONB AS $$DECLARE result TEXT;BEGIN SELECT tencentdb_ai.chat_completions( '<your-llm-model>', '请从以下文本中抽取实体和关系,以 JSON 格式返回。' || '格式:{"entities": [{"name": "实体名", "type": "类型", "description": "描述"}], ' || '"relations": [{"source": "源实体", "target": "目标实体", "relation": "关系类型", "description": "描述"}]}' || E'\\n\\n文本:' || doc_content ) INTO result; RETURN result::JSONB;END;$$ LANGUAGE plpgsql;
六、图谱构建(含安全校验)
来自 LLM 的 entity.type / relation.relation 会作为 Cypher 标签拼入查询,必须使用白名单校验,禁止任意字符串进入 Cypher:
— 允许的实体类型与关系类型白名单CREATE TABLE IF NOT EXISTS graphrag.allowed_entity_types (type TEXT PRIMARY KEY);CREATE TABLE IF NOT EXISTS graphrag.allowed_relation_types (type TEXT PRIMARY KEY);INSERT INTO graphrag.allowed_entity_types(type) VALUES ('Person'), ('Company'), ('Product'), ('Technology'), ('Concept')ON CONFLICT DO NOTHING;INSERT INTO graphrag.allowed_relation_types(type) VALUES ('WORKS_AT'), ('USES'), ('HAS_FEATURE'), ('RELATED_TO'), ('PART_OF')ON CONFLICT DO NOTHING;– 将抽取的实体存入图CREATE OR REPLACE FUNCTION graphrag.build_graph(doc_id BIGINT)RETURNS VOID AS $$DECLARE doc_content TEXT; extracted JSONB; entity JSONB; relation JSONB; e_type TEXT; r_type TEXT;BEGIN SELECT content INTO doc_content FROM graphrag.documents WHERE id = doc_id; extracted := graphrag.extract_entities(doc_content); — 创建实体节点(白名单校验类型) FOR entity IN SELECT * FROM jsonb_array_elements(extracted->'entities') LOOP e_type := entity->>'type'; IF NOT EXISTS (SELECT 1 FROM graphrag.allowed_entity_types WHERE type = e_type) THEN RAISE NOTICE 'Skip entity with disallowed type: %', e_type; CONTINUE; END IF; PERFORM * FROM cypher('knowledge_graph', format($$ MERGE (n:%I {name: %L}) SET n.description = %L, n.doc_id = %s $$, e_type, entity->>'name', entity->>'description', doc_id)) AS (v agtype); END LOOP; — 创建关系(白名单校验关系类型) FOR relation IN SELECT * FROM jsonb_array_elements(extracted->'relations') LOOP r_type := relation->>'relation'; IF NOT EXISTS (SELECT 1 FROM graphrag.allowed_relation_types WHERE type = r_type) THEN RAISE NOTICE 'Skip relation with disallowed type: %', r_type; CONTINUE; END IF; PERFORM * FROM cypher('knowledge_graph', format($$ MATCH (a {name: %L}), (b {name: %L}) MERGE (a)-[r:%I]->(b) SET r.description = %L $$, relation->>'source', relation->>'target', r_type, relation->>'description')) AS (r agtype); END LOOP;END;$$ LANGUAGE plpgsql;
关键点:
·节点标签 / 关系类型:使用 %I 安全标识符 + 白名单双重校验。
·属性值:使用 %L 安全转义。
·不通过白名单:直接跳过并打日志,不允许任意字符串落入 Cypher。
七、GraphRAG 检索
— 混合检索:图遍历 + 向量搜索CREATE OR REPLACE FUNCTION graphrag.hybrid_retrieve(query TEXT, top_k INT DEFAULT 5)RETURNS TABLE(source TEXT, content TEXT, score FLOAT) AS $$BEGIN — 向量检索文档 RETURN QUERY SELECT 'vector'::TEXT, d.content, (1 – (d.embedding <=> tencentdb_ai.get_embedding('bge-m3', query)))::FLOAT FROM graphrag.documents d ORDER BY d.embedding <=> tencentdb_ai.get_embedding('bge-m3', query) LIMIT top_k; — 图检索相关实体 RETURN QUERY SELECT 'graph'::TEXT, (a->>'name' || ' –[' || r->>'relation' || ']–> ' || b->>'name')::TEXT, 0.8::FLOAT FROM cypher('knowledge_graph', format($$ MATCH (a)-[r]->(b) WHERE a.name CONTAINS %L OR b.name CONTAINS %L RETURN properties(a) as a, properties(r) as r, properties(b) as b LIMIT %s $$, query, query, top_k)) AS (a agtype, r agtype, b agtype);END;$$ LANGUAGE plpgsql;
八、生成回答
— GraphRAG 问答CREATE OR REPLACE FUNCTION graphrag.answer(question TEXT)RETURNS TEXT AS $$DECLARE context TEXT; answer TEXT;BEGIN SELECT string_agg('[' || source || '] ' || content, E'\\n') INTO context FROM graphrag.hybrid_retrieve(question, 5); SELECT tencentdb_ai.chat_completions( '<your-llm-model>', '基于以下知识图谱信息和文档内容回答问题。图谱信息标记为 [graph],文档内容标记为 [vector]。' || E'\\n\\n上下文:\\n' || COALESCE(context, '无') || E'\\n\\n问题:' || question ) INTO answer; RETURN answer;END;$$ LANGUAGE plpgsql;
九、使用示例
— 导入文档并构建图谱INSERT INTO graphrag.documents (title, content, embedding)VALUES ( 'PostgreSQL 与 AI', '腾讯云 PostgreSQL 通过 tencentdb_ai 插件支持在 SQL 中直接调用大模型…', tencentdb_ai.get_embedding('bge-m3', '腾讯云 PostgreSQL 通过 tencentdb_ai 插件支持在 SQL 中直接调用大模型'));– 构建图谱SELECT graphrag.build_graph(1);– GraphRAG 问答SELECT graphrag.answer('PostgreSQL 支持哪些 AI 能力?');
十、实践
1. 实体去重:使用 MERGE 避免重复实体。
2. 增量更新:新文档只增量构建,不全量重建。
3. 图索引:为频繁查询的属性创建索引。
4. 社区发现:利用图算法做文档聚类。
5. 混合召回:图上下文 + 向量文档互补。
6. 白名单保护:实体类型 / 关系类型必须经过白名单,杜绝来自 LLM 的任意字符串注入。
十一、相关文档
·Apache AGE 图数据库使用指南。
·pgvector 向量扩展使用指南。
·tencentdb_ai 插件功能介绍。