GraphRAG Visualizer: Wissensgraph-gestütztes RAG für Dokumentenanalyse
KI & Tech9 min read10. Oktober 2025

GraphRAG Visualizer: Wissensgraph-gestütztes RAG für Dokumentenanalyse

Visuelle Oberfläche zur Exploration von mit GraphRAG indizierten Dokumentensammlungen und schneller, NLP-basierter Graph-Extraktion

GraphRAGWissensgraphenRAGNLPOpenAIDatenvisualisierungReact

Einleitung

GraphRAG Visualizer ist ein Projekt zur Visualisierung und Exploration von Wissensgraphen, die mit Microsoft GraphRAG aus Dokumentensammlungen extrahiert wurden. Das Projekt kombiniert:

  • GraphRAG Indexing Pipeline für die Extraktion von Entitäten, Beziehungen und Communities
  • GraphRAG API für lokale und globale Suchanfragen
  • GraphRAG Visualizer für die interaktive Exploration des Wissensgraphen

Während traditionelle RAG-Systeme (Retrieval-Augmented Generation) auf einfacher Vektorsuche basieren, geht GraphRAG einen Schritt weiter: Es extrahiert strukturierte Wissensgraphen aus Dokumenten und ermöglicht so tiefere semantische Zusammenhänge und bessere Antworten auf komplexe Fragen.

Graph-Struktur einer Entity mit ihren Beziehungen

Problem Statement: Warum GraphRAG?

Limitationen von Traditional RAG

Klassische RAG-Systeme funktionieren nach einem einfachen Prinzip:

  1. Chunking: Dokumente werden in kleine Textabschnitte unterteilt
  2. Embedding: Jeder Chunk wird in einen Vektor umgewandelt
  3. Retrieval: Bei einer Anfrage werden die semantisch ähnlichsten Chunks abgerufen
  4. Generation: Ein LLM generiert eine Antwort basierend auf den abgerufenen Chunks

Das Problem: Diese Methode versagt bei Fragen, die globales Wissen über den gesamten Dokumentenkorpus erfordern.

Beispiel:

"Was sind die Hauptthemen in diesen 100 Forschungspapieren?"

Ein traditionelles RAG-System würde nur wenige semantisch ähnliche Chunks abrufen – aber die Frage erfordert eine Synthese über alle Dokumente hinweg.

GraphRAG's Lösung

GraphRAG adressiert diese Limitation durch:

  1. Knowledge Graph Extraction: Entitäten und Beziehungen werden aus dem Text extrahiert
  2. Community Detection: Verwandte Entitäten werden in thematische Cluster gruppiert
  3. Hierarchical Summarization: Für jede Community werden Zusammenfassungen generiert
  4. Global Search: Anfragen können über alle Community-Reports beantwortet werden

GraphRAG


traditional RAG


Architektur & Technologie-Stack

Systemübersicht

Mein GraphRAG Architektur

Verwendete Technologien

KomponenteTechnologieBeschreibung
IndexingMicrosoft GraphRAGKnowledge Graph Extraction Pipeline
LLMOpenAI GPT-4o-miniCommunity Report Generation
EmbeddingOpenAI text-embedding-3-smallQuery Embedding (für Local/Global Search)
APIgraphrag-apiFastAPI Backend für Search Queries
Frontendgraphrag-visualizerReact-basierte Visualisierung
Graph Renderingreact-force-graph2D/3D Force-Directed Graph

GraphRAG Indexing: Standard vs. Fast Method

GraphRAG bietet zwei Indexierungsmethoden mit unterschiedlichen Trade-offs:

Standard Method (graphrag index)

Die Standard-Methode verwendet ein LLM für alle Reasoning-Tasks:

  • Entity Extraction: LLM extrahiert benannte Entitäten mit Beschreibungen
  • Relationship Extraction: LLM beschreibt Beziehungen zwischen Entitätspaaren
  • Entity/Relationship Summarization: LLM fasst alle Instanzen zusammen
  • Community Report Generation: LLM generiert Zusammenfassungen für jede Community

Vorteile:

  • Hochwertige, semantisch reiche Beschreibungen
  • Bessere Graph-Qualität für Exploration

Nachteile:

  • Hohe LLM-Kosten (~75% der Indexierungskosten)
  • Langsame Verarbeitung

Fast Method (graphrag index --method fast)

Die Fast-Methode ersetzt LLM-Reasoning durch klassische NLP-Techniken:

  • Entity Extraction: Noun Phrases werden mit NLTK/spaCy extrahiert (keine Beschreibungen)
  • Relationship Extraction: Beziehungen basieren auf Text-Unit Co-Occurrence
  • No Summarization: Nicht notwendig
  • Community Report Generation: Nur dieser Schritt verwendet noch das LLM

Vorteile:

  • Deutlich geringere Kosten
  • Schnellere Verarbeitung

Nachteile:

  • Weniger semantisch reiche Beschreibungen
  • "Rauschigerer" Graph

Meine Konfiguration: Fast Method mit OpenAI

Für dieses Projekt habe ich die Fast Method gewählt, um Kosten zu minimieren und schnelle Iterationen zu ermöglichen:

// LLM settings
models:
  default_chat_model:
    type: openai_chat
    api_base: https://api.openai.com/v1
    model: gpt-4o-mini
    api_key: ${OPEN_AI_KEY}
    model_supports_json: true
    concurrent_requests: 3
    async_mode: threaded
    retry_strategy: native
    max_retries: 2
    tokens_per_minute: 100000
    requests_per_minute: 200
    completion_params:
      temperature: 0.0
      max_tokens: 1536
    encoding_model: cl100k_base

  default_embedding_model:
    type: openai_embedding
    api_base: https://api.openai.com/v1
    model: text-embedding-3-small
    api_key: ${OPEN_AI_KEY}
    concurrent_requests: 3
    async_mode: threaded

// Input settings
input:
  type: file
  file_type: text
  base_dir: "input"

chunks:
  size: 1200
  overlap: 100
  group_by_columns: [id]

// Workflow settings
embed_text:
  enabled: true

extract_graph_nlp:
  text_analyzer:
    extractor_type: regex_english # Fast NLP extraction

cluster_graph:
  max_cluster_size: 10

community_reports:
  model_id: default_chat_model
  graph_prompt: "prompts/community_report_graph.txt"
  text_prompt: "prompts/community_report_text.txt"
  max_length: 2000
  max_input_length: 8000

Wichtige Konfigurationspunkte:

  1. embed_text: enabled: true – LanceDB Vector Store wird bei default immer erstellt, auch wenn disabled
  2. extract_graph_nlp.extractor_type: regex_english – Verwendet regex-basierte Noun-Phrase-Extraktion anstelle von LLM
  3. community_reports – Der einzige Schritt, der das LLM verwendet

Indexing Pipeline im Detail

Datenfluss

Daten Fluss

Kostenabschätzung (Fast Method)

Für 2 Text-Dateien (~100 KB):

SchrittToken-VerbrauchKosten (gpt-4o-mini)
NLP-Schritte0$0.00
Community Reports~40-70k Input, ~5-10k Output~$0.01-0.03
Gesamt~$0.02

Zum Vergleich: Die Standard-Methode würde für dasselbe Corpus etwa $0.20-0.50 kosten.


Output: Parquet-Dateien

Nach erfolgreichem Indexing werden folgende Parquet-Dateien generiert:

DateiInhaltErforderlich für Visualizer
entities.parquetExtrahierte Entitäten (Noun Phrases)✓ Erforderlich
relationships.parquetBeziehungen zwischen Entitäten✓ Erforderlich
documents.parquetMetadaten der EingabedokumenteOptional
text_units.parquetText-Chunks mit Entity-ReferenzenOptional
communities.parquetCommunity-Cluster-ZuordnungenOptional
community_reports.parquetLLM-generierte Community-ZusammenfassungenOptional

GraphRAG Visualizer

Features

Der Visualizer bietet drei Hauptansichten:

1. Graph Visualization

Graph Visualisierung Ansicht

Features:

  • 2D/3D Rendering mit react-force-graph
  • Node-Färbung nach Typ (Entity, Community, Document, etc.)
  • Interaktive Hover-Hervorhebung
  • Zoom, Pan, und Focus-Navigation
  • Optionale Labels für Nodes und Links

2. Search Interface

Search Ansicht

Search Types:

  • Local Search: Findet relevante Entitäten und deren Kontext
  • Global Search: Synthesiert Antworten aus allen Community-Reports

Beispielanfrage:

"Find me all relationships between Trump and Twitter. Analyse them overall."

3. Data Tables

Data Tables Ansicht

Ermöglicht die Exploration von:

  • Entities
  • Relationships
  • Documents
  • Text Units
  • Communities
  • Community Reports

Kritische Code-Komponenten

Graph Data Processing (useGraphData.ts)

Der Hook transformiert die Parquet-Daten in ein Graph-Format für react-force-graph:

const useGraphData = (
  entities: Entity[],
  relationships: Relationship[],
  documents: Document[],
  textunits: TextUnit[],
  communities: Community[],
  communityReports: CommunityReport[],
  covariates: Covariate[],
  includeDocuments: boolean,
  includeTextUnits: boolean,
  includeCommunities: boolean,
  includeCovariates: boolean
) => {
  const [graphData, setGraphData] = useState<CustomGraphData>({
    nodes: [],
    links: [],
  });

  useEffect(() => {
    // Entity nodes
    const nodes: CustomNode[] = entities.map((entity) => ({
      uuid: entity.id,
      id: entity.title,
      name: entity.title,
      type: entity.type,
      description: entity.description,
      text_unit_ids: entity.text_unit_ids,
      neighbors: [],
      links: [],
    }));

    const nodesMap: { [key: string]: CustomNode } = {};
    nodes.forEach((node) => (nodesMap[node.id] = node));

    // Relationship links
    const links: CustomLink[] = relationships
      .map((relationship) => ({
        source: relationship.source,
        target: relationship.target,
        type: relationship.type,
        weight: relationship.weight,
        description: relationship.description,
      }))
      .filter((link) => nodesMap[link.source] && nodesMap[link.target]);

    // Build neighbor references
    links.forEach((link) => {
      const sourceNode = nodesMap[link.source];
      const targetNode = nodesMap[link.target];
      if (sourceNode && targetNode) {
        sourceNode.neighbors!.push(targetNode);
        targetNode.neighbors!.push(sourceNode);
        sourceNode.links!.push(link);
        targetNode.links!.push(link);
      }
    });

    setGraphData({ nodes, links });
  }, [entities, relationships /* ... */]);

  return graphData;
};

Parquet File Reading (parquet-utils.ts)

Die Parquet-Dateien werden clientseitig mit hyparquet gelesen:

export const readParquetFile = async (
  file: File | Blob,
  schema?: string
): Promise<any[]> => {
  const arrayBuffer = await file.arrayBuffer();
  const asyncBuffer = new AsyncBuffer(arrayBuffer);

  return new Promise((resolve, reject) => {
    const options: ParquetReadOptions = {
      file: asyncBuffer,
      rowFormat: "object",
      onComplete: (rows: Record<string, any>[]) => {
        if (schema === "entity") {
          resolve(
            rows.map((row) => ({
              id: row["id"],
              human_readable_id: parseValue(row["human_readable_id"], "number"),
              title: row["title"],
              type: row["type"],
              description: row["description"],
              text_unit_ids: row["text_unit_ids"],
            }))
          );
        }
        // ... other schemas
      },
    };
    parquetRead(options).catch(reject);
  });
};

Graph Visualization (GraphViewer.tsx)

Der Graph wird mit react-force-graph-2d gerendert:

<ForceGraph2D
  ref={graphRef}
  graphData={graphData}
  nodeAutoColorBy="type"
  nodeRelSize={NODE_R}
  autoPauseRedraw={false}
  linkWidth={(link) => (showHighlight && highlightLinks.has(link) ? 5 : 1)}
  linkDirectionalParticles={showHighlight ? 4 : 0}
  nodeCanvasObjectMode={(node) =>
    showHighlight && highlightNodes.has(node)
      ? "before"
      : showLabels
      ? "after"
      : undefined
  }
  nodeCanvasObject={(node, ctx) => {
    if (showHighlight && highlightNodes.has(node)) {
      paintRing(node as CustomNode, ctx);
    }
    if (showLabels) {
      renderNodeLabel(node as CustomNode, ctx);
    }
  }}
  onNodeHover={showHighlight ? handleNodeHover : undefined}
  onNodeClick={handleNodeClick}
  backgroundColor={getBackgroundColor()}
/>

Projekt Setup

Prerequisites

  • Python 3.10+
  • Node.js 18+
  • OpenAI API Key

1. GraphRAG Indexing

# Clone und Setup
cd graphrag-api
python -m venv venv
.\venv\Scripts\activate
pip install graphrag

# Environment Variable setzen
set OPEN_AI_KEY=sk-your-key-here

# Indexing starten (Fast Method)
cd ragtest
graphrag index --method fast

2. GraphRAG API Server

cd graphrag-api
pip install -r requirements.txt
uvicorn api:app --reload

3. Visualizer Frontend

cd graphrag-visualizer
npm install
npm start

Öffne http://localhost:3000, lade die Parquet-Dateien aus ragtest/output/ hoch, und exploriere deinen Wissensgraphen!


Ergebnisse & Beobachtungen

Graph Statistiken (Beispiel-Twitter)

MetrikWert
Input-Dokumente2 Text-Dateien
Gesamtgröße100 KB
Extrahierte Entitäten336
Extrahierte Beziehungen11483
Communities73
Indexing-Zeit (Fast)5
Geschätzte Kosten~$0.02

Performance-Beobachtungen

Fast Method:

  • NLP-Schritte (1-8) sind sehr schnell (Sekunden bis Minuten)
  • create_community_reports_text ist der zeitintensivste Schritt (~75% der Gesamtzeit)
  • LLM-Kosten werden nur für Community Reports verwendet

Visualizer Performance:

  • Graph-Rendering kann bei >1000 Nodes langsam werden
  • 2D-Rendering ist deutlich schneller als 3D
  • Labels bei vielen Nodes sollten deaktiviert werden

Fazit & Lessons Learned

Key Takeaways

  1. Fast Method ist ein guter Kompromiss – Deutlich günstiger als Standard, aber ausreichend für Exploration und Prototyping

  2. Community Reports sind der Kernwert – Die LLM-generierten Zusammenfassungen ermöglichen Global Search und tiefes Verständnis

  3. Visualisierung macht den Unterschied – Der Graph hilft, Zusammenhänge zu entdecken, die in Textform verborgen bleiben

  4. Konfiguration ist entscheidend – Chunk-Größe, max_cluster_size und Prompt-Engineering beeinflussen die Ergebnisqualität

Verbesserungspotenzial

  • Personalisierte Labels: Bessere Display-Namen statt technischer IDs
  • Adaptive Graph Rendering: Clustering oder Aggregation für große Graphen
  • Real-time Indexing: Inkrementelle Updates statt vollständiger Re-Indexierung

References & Resources

Repositories

Weiterführende Literatur

Technologien & Tools


Keywords: GraphRAG, Knowledge Graphs, RAG, Retrieval-Augmented Generation, NLP, OpenAI, React, Data Visualization, Microsoft Research