
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
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:
- Chunking: Dokumente werden in kleine Textabschnitte unterteilt
- Embedding: Jeder Chunk wird in einen Vektor umgewandelt
- Retrieval: Bei einer Anfrage werden die semantisch ähnlichsten Chunks abgerufen
- 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:
- Knowledge Graph Extraction: Entitäten und Beziehungen werden aus dem Text extrahiert
- Community Detection: Verwandte Entitäten werden in thematische Cluster gruppiert
- Hierarchical Summarization: Für jede Community werden Zusammenfassungen generiert
- Global Search: Anfragen können über alle Community-Reports beantwortet werden
GraphRAG
traditional RAG
Architektur & Technologie-Stack
Systemübersicht
Mein GraphRAG Architektur
Verwendete Technologien
| Komponente | Technologie | Beschreibung |
|---|---|---|
| Indexing | Microsoft GraphRAG | Knowledge Graph Extraction Pipeline |
| LLM | OpenAI GPT-4o-mini | Community Report Generation |
| Embedding | OpenAI text-embedding-3-small | Query Embedding (für Local/Global Search) |
| API | graphrag-api | FastAPI Backend für Search Queries |
| Frontend | graphrag-visualizer | React-basierte Visualisierung |
| Graph Rendering | react-force-graph | 2D/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:
embed_text: enabled: true– LanceDB Vector Store wird bei default immer erstellt, auch wenn disabledextract_graph_nlp.extractor_type: regex_english– Verwendet regex-basierte Noun-Phrase-Extraktion anstelle von LLMcommunity_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):
| Schritt | Token-Verbrauch | Kosten (gpt-4o-mini) |
|---|---|---|
| NLP-Schritte | 0 | $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:
| Datei | Inhalt | Erforderlich für Visualizer |
|---|---|---|
entities.parquet | Extrahierte Entitäten (Noun Phrases) | ✓ Erforderlich |
relationships.parquet | Beziehungen zwischen Entitäten | ✓ Erforderlich |
documents.parquet | Metadaten der Eingabedokumente | Optional |
text_units.parquet | Text-Chunks mit Entity-Referenzen | Optional |
communities.parquet | Community-Cluster-Zuordnungen | Optional |
community_reports.parquet | LLM-generierte Community-Zusammenfassungen | Optional |
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)
| Metrik | Wert |
|---|---|
| Input-Dokumente | 2 Text-Dateien |
| Gesamtgröße | 100 KB |
| Extrahierte Entitäten | 336 |
| Extrahierte Beziehungen | 11483 |
| Communities | 73 |
| 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_textist 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
-
Fast Method ist ein guter Kompromiss – Deutlich günstiger als Standard, aber ausreichend für Exploration und Prototyping
-
Community Reports sind der Kernwert – Die LLM-generierten Zusammenfassungen ermöglichen Global Search und tiefes Verständnis
-
Visualisierung macht den Unterschied – Der Graph hilft, Zusammenhänge zu entdecken, die in Textform verborgen bleiben
-
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
- Microsoft GraphRAG - Official GraphRAG Repository
- GraphRAG Documentation - Official Documentation
- graphrag-api - FastAPI Backend
- graphrag-visualizer - React Frontend
Weiterführende Literatur
- GraphRAG: Unlocking LLM Discovery on Narrative Private Data - Microsoft Research Blog
- GraphRAG Explained: Enhancing RAG with Knowledge Graphs - Medium Article
- From Local to Global: A Graph RAG Approach - Original Paper
Technologien & Tools
- OpenAI API - GPT-4o-mini & text-embedding-3-small
- React - Frontend Framework
- react-force-graph - Graph Visualization
- Material-UI - UI Components
- hyparquet - Client-side Parquet Reader
Keywords: GraphRAG, Knowledge Graphs, RAG, Retrieval-Augmented Generation, NLP, OpenAI, React, Data Visualization, Microsoft Research