GraphRAG Teil 2:-Mindestlebend GraphRAG (Deutsch (German))

GraphRAG Teil 2:-Mindestlebend GraphRAG

Saturday, 27 December 2025

//

13 minute read

Im TeilWir haben untersucht, warum GraphRAG wichtig ist. Mindesthaltbarkeit von GraphRAG mit drei Extraktionsmodi

-Modus ruft LLM am besten für -Modus an
Heuristisch (-Default)- -M0- pro Stück Schnellindexierung strukturierter Markdown - -
Hybrid Ausgewogenheit von Geschwindigkeit und Qualität
LLM Höchste Entitätsqualität

Alle Betriebsarten verwenden

  • EnteDB für einen einheitlichen Speicher in einer einzigen Datei
  • BM-25-Hybridsuche über RRF-Fusion
  • Ollama für Synthese und optionale Batch-Klassifikation

Serie Navigation .:

Code-Code Meistlylucid-.-GraphRag auf GitHub

Architektur im Überblick

flowchart LR
    subgraph Indexing
        MD[Markdown Files] --> CH[Chunker]
        CH --> EMB[BERT Embeddings]
        CH --> EXT[Entity Extractor]
        EXT --> |heuristics + links| ENT[Entities]
        ENT --> REL[Relationships]
        REL --> COM[Communities]
    end
    
    subgraph Storage
        EMB --> DB[(DuckDB)]
        ENT --> DB
        REL --> DB
        COM --> DB
    end
    
    subgraph Query
        Q[Query] --> CLASS{Classify}
        CLASS --> |local| HS[Hybrid Search]
        CLASS --> |global| CS[Community Search]
        CLASS --> |drift| BOTH[Both + Synthesis]
        HS --> LLM[Ollama]
        CS --> LLM
        BOTH --> LLM
    end
    
    DB --> HS
    DB --> CS
    
    style MD stroke:#22c55e,stroke-width:2px
    style DB stroke:#3b82f6,stroke-width:2px
    style LLM stroke:#a855f7,stroke-width:2px

Warum DuckDB.??

Microsoft®' s GraphRAG verwendet separaten Speicher für Vektoren -( , LanceDB , ), , Entities , ( , Parquet ,), , und Beziehungen .( , mehr Parkett , ). , DuckDB vereinfacht dies

  • Einzeln .duckdb Datei für alles
  • Native HNSW Vektorsuche über VSS-Erweiterung
  • SQL für Vektorsuche und Graphentransversal
  • Komplexität der Bereitstellung von Null

DuckDB ist nicht eine Graphen-Datenbank, und das ist der Punkt. Dies ist ,' , Neo , 4 , . , Traversen sind flach , , , SQL , und bewusst ,. , dass die Beschränkung hält das System debuggable und billig .

Speicherschema

Das Schema verwendet Beistelltische für Provenienz Wir können Fragen stellen, welche Brocken Entity X.?" direkt erwähnen.

erDiagram
    documents ||--o{ chunks : contains
    chunks ||--o{ entity_mentions : has
    chunks ||--o{ relationship_mentions : has
    entities ||--o{ entity_mentions : mentioned_in
    entities ||--o{ relationships : source
    entities ||--o{ relationships : target
    relationships ||--o{ relationship_mentions : mentioned_in
    communities ||--o{ community_members : contains
    entities ||--o{ community_members : belongs_to
    
    chunks {
        varchar id PK
        varchar document_id FK
        text text
        float[] embedding
    }
    
    entities {
        varchar id PK
        varchar name
        varchar type
        int mention_count
    }
    
    entity_mentions {
        varchar entity_id FK
        varchar chunk_id FK
    }

Schlüsselentscheidung für das Design Nein VARCHAR[] für ProvenienzBeifügen von Tabellenentity_mentions, relationship_mentionsErmöglichen Sie effiziente Abfragen wie z.B. alle Brocken, die Docker nennen

Vektorensuche - Das HNSW Gotcha

Der HNSW Index von DuckDB-' löst nur mit array_cosine_distance + ORDER BY + LIMIT:

// GraphRagDb.cs - SearchChunksAsync
cmd.CommandText = $"""
    SELECT id, document_id, text, chunk_index, 
           array_cosine_distance(embedding, $1::FLOAT[{_dim}]) as distance
    FROM chunks 
    WHERE embedding IS NOT NULL
    ORDER BY distance
    LIMIT $2
    """;
// Convert distance to similarity: 1.0f - distance

Verwendung array_cosine_similarity wird den Index nicht verwenden Es hat den HNSW Index ausgelöst. Auf nicht--'trivial corpora,' wird dadurch eine indizierte Abfrage in einen vollständigen Tabellenscan umgewandelt.

Entitätenextraktion

Dies ist, wo wir von Microsoft diverge nieren. LLM---per---Cunk-Extraktion Pässe verwendet in Microsoft-Referenz GraphRAG Pipeline, verwenden wir IDF---basierte statistische ExtraktionDas Ziel ist es, perfekte Entitäten zu erreichen. stabile corpus-Signale Das erfordert ein LLM, um zu produzieren . Dieses tradet einige Rückrufe für Determinismus., und berechenbare Kosten eine bewusste Wahl für technische Corpora:

flowchart TB
    subgraph "Phase 1: Signal Collection"
        TEXT[All Chunks] --> IDF[Compute IDF Scores]
        TEXT --> STRUCT[Structural Signals]
        STRUCT --> HEAD[Headings]
        STRUCT --> CODE[Inline Code]
        STRUCT --> LINKS[Links]
        IDF --> RARE[High-IDF = Rare Terms]
        RARE --> CAND[Candidates]
        HEAD --> CAND
        CODE --> CAND
        LINKS --> |explicit rels| LINKREL[Link Relationships]
    end
    
    subgraph "Phase 2: Dedup"
        CAND --> EMBED[BERT Embeddings]
        EMBED --> SIM[Similarity > 0.85]
        SIM --> MERGE[Merge Duplicates]
    end
    
    subgraph "Phase 3: Classify"
        MERGE --> LLM{LLM Available?}
        LLM --> |yes| BATCH[Single Batch Call]
        LLM --> |no| HEUR[Heuristic Types]
    end
    
    style IDF stroke:#f59e0b,stroke-width:2px
    style BATCH stroke:#a855f7,stroke-width:2px

Warum IDF-,-nicht festkodierte Listen

Der naive Ansatz ist ein hartkodierter HashSet<string> KnownTech = { "Docker", "Kubernetes", ... }Diese Pausen für ,MSK'

  • Neue Technologien müssen die Liste aktualisieren
  • Domänenspezifische Begriffe unterschiedliche Korpusarten unterschiedliche Einheiten
  • Schreibfehler und Abweichungen

IDF-Frequenz des inversen Dokuments Löset dieses statistisch ,.' Ein Begriff ,''s IDF ist ,mesK2'

$$-Texte, {-IDF-}(-t)-=--Log-MSC6-frac-{-N.}{-df-MS K9-t-MSSK10

Worum es geht

  • Gesamte Stückzahl
  • Dokumente, die den Begriff $ enthalten

Hohe IDF-Werte Seltener Begriff Wahrscheinlich hat eine Entität, die sich in 5 von 100 befindet, eine höhere IDF als ", die bei 100 aus 100. erscheint.

Für mehr auf TF.-.IDF und BM.25,. Siehe meinen Beitrag auf hybride Suche mit BM-25.

Strukturelle Signale

Markdown-Struktur sagt uns, was - ' - wichtig ist

  • Bezeichnung (## Docker SetupEntität
  • Inlinecode (`docker-compose`Entität
  • Verknüpfungen ([Docker](https://docker.com)Verhältnis zwischen der Einheit und dem Unternehmen
// EntityExtractor.cs - structural signal extraction
private void ExtractStructuralEntities(string chunk, string chunkId)
{
    // Headings: ## Docker Compose Setup → "Docker Compose Setup"
    foreach (Match m in Regex.Matches(chunk, @"^#{1,3}\s+(.+)$", RegexOptions.Multiline))
    {
        var heading = m.Groups[1].Value.Trim();
        AddCandidate(heading, chunkId, weight: 2.0); // Higher weight
    }
    
    // Inline code: `docker-compose` → "docker-compose"
    foreach (Match m in Regex.Matches(chunk, @"`([^`]+)`"))
    {
        AddCandidate(m.Groups[1].Value, chunkId, weight: 1.5);
    }
}

Verbindung Gewinnung von Verbindungen mit hohem Gehalt an Qualitäts-Beziehungen

Markdown-Links bieten ausdrücklich Beziehungen, die nicht erfordern LLM-Inferenz

// EntityExtractor.cs - ExtractLinks  
foreach (Match m in Regex.Matches(chunk, @"\[([^\]]+)\]\((/blog/[^)]+)\)"))
{
    var linkText = m.Groups[1].Value;  // "semantic search"
    var slug = m.Groups[2].Value;       // "/blog/semantic-search-with-qdrant"
    yield return new Relationship(linkText, $"blog:{slug}", "references", chunkId);
}

Deduplikation über BERT-Embeddings

Wir verwenden Entitätsnamen wie "-Docker-Komposition",-Docker-Komposite--kompose",- und "-Dacker-Compose"-komposite BERT-Einbettungen zum Nachweis semantischer Ähnlichkeiten

// EntityExtractor.cs - DeduplicateAsync
var embeddings = await _embedder.EmbedBatchAsync(candidates.Select(c => c.Name), ct);

for (int i = 0; i < candidates.Count; i++)
{
    for (int j = i + 1; j < candidates.Count; j++)
    {
        var similarity = CosineSimilarity(embeddings[i], embeddings[j]);
        if (similarity > 0.85)
        {
            // Merge into canonical entity (keep higher mention count)
            canonical.MentionCount += duplicate.MentionCount;
            canonical.ChunkIds.UnionWith(duplicate.ChunkIds);
        }
    }
}

Dieser Schritt ist in einem gebundenen Kandidaten-Set , aber die Anzahl der Kandidaten wird durch IDF Filterung und strukturelle Signale begrenzt , - , nicht Korpusgröße , . , Für Details auf BERT Einbettungen ,, , siehe semantische Suche mit ONNX und BERT.

Extraktionsmodi

Das CLI unterstützt drei Extraktionsmodi über --extraction-mode:

Heuristischer Modus

dotnet run --project Mostlylucid.GraphRag -- index ./Markdown --extraction-mode heuristic

Verwendet IDF Struktursignale zur Entitätserkennung mit optionaler LLM Batch-Klassifikation Null Anrufe per ,-'cunk LLM Nur Anrufe pro Einheiten der Typenklassifizierung (MSK)

Hybrid-Modus empfohlen

dotnet run --project Mostlylucid.GraphRag -- index ./Markdown --extraction-mode hybrid

Das Beste aus beiden Welten

  1. Heuristische ErkennungIDF - Struktursignale finden Entitätskandidaten
  2. LLM-VerbesserungEin Aufruf pro Dokument validiert Entitäten und extrahiert semantische Beziehungen
flowchart LR
    subgraph "Per Document"
        CHUNKS[Document Chunks] --> HEUR[Heuristic Extraction]
        HEUR --> CAND[30 Candidates]
        CAND --> LLM[Single LLM Call]
        LLM --> ENT[Validated Entities]
        LLM --> REL[Semantic Relationships]
    end
    
    style HEUR stroke:#22c55e,stroke-width:2px
    style LLM stroke:#a855f7,stroke-width:2px

Für Dokumente mit einem Hybrid-Modus macht LLM-Aufrufe Für volle LLM-Modus, erhalten Sie :

  • Deterministische Entity-Berichterstattung aus der Heuristik
  • LLM---Qualität Beziehungsextraktion (-Semantik ,-nicht nur co---Ereignis
  • Beschreibungen und validierte Typen

LLM-Modus (-Microsoft-Style-)-Style

dotnet run --project Mostlylucid.GraphRag -- index ./Markdown --extraction-mode llm

Vollständiger Ansatz von Microsoft GraphRAG LLM-Aufrufe pro Stück Die meisten teuren ,, aber höchste Qualität für unstrukturierten Text

Wann jedes Mal verwendet werden soll

-Modus ruft LLM am besten für -Modus an
Heuristisch , , , ~1 , pro Einheiten , 50 , schnell indizierend , , , gut ,- , strukturierter Markdown
Hybrid Ausgewogenheit der Abdeckung und Qualität
LLM Nicht strukturierte Prosa, maximale Qualität

Für die technische Dokumentation - Start mit Hybrid Es gibt Ihnen semantische Beziehungen ohne die Per--... heuristisch bei reiner Geschwindigkeit: llm für narrative Texte

Hybride Suche - :-BM-25-BERT

Hybride Suche kombiniert zwei komplementäre Ansätze

Dichte (-BERT-): Versteht die Bedeutung von .-Dockercontainern, die mit " zusammenhängt Sparse (-BM-25):- Passt genau zu den Begriffen ., ", HNSW", nur zu den Bedingungen ", PSW".,

flowchart LR
    Q[Query] --> BERT[BERT Embedding]
    Q --> BM25[BM25 Tokenize]
    
    BERT --> DENSE[Dense Search<br/>HNSW Index]
    BM25 --> SPARSE[Sparse Search<br/>TF-IDF Scoring]
    
    DENSE --> RRF[RRF Fusion]
    SPARSE --> RRF
    
    RRF --> TOP[Top K Results]
    TOP --> ENR[Enrich with<br/>Entities + Rels]
    
    style RRF stroke:#f59e0b,stroke-width:2px

Was ist BM-25??

BM.25 (Best MatchErgebnisse von Dokumenten basierend auf Query Term Frequency).Die Formel...

]$$-Text ♪{-Scorer}(-Streamer,-Recorder )-Tracker_]{ ® T=1}^ TM\ TMD( TMX_ TMSSK7 TM \ TMCT { T( hm, TMS) TMKSK15 ktM( MX_1 TMSCDt + T1)}{ ( TMCSK21 TMK22 TMSB) TM-+ kt_1 nm\ TMcdt M(1 TMSV- .

Wichtige Intuitionen

  • IDF-BezeichnungSeltene Wörter spielen eine Rolle mehr
  • TF-SättigungDas Wort, das erscheint, ist mehr relevant als 1x.
  • LängennormalisierungLange Dokumente erhalten keinen unfairen Vorteil

Für eine vollständige BM-Implementierung von , siehe hybride Suche und Indexierung.

Reziproker Rang Fusion

RRF verschmilzt Rankings aus unterschiedlichen Retrieval-Systemen... jede Rangposition bekommt eine Punktzahl.

,$$, Text , {, RRF, }(, D), MSC4, Summe_{-R , -R,}-R und {1}{-R

Wo verhindert, dass das oberste Ergebnis übergewichtig ist, erscheinen die Dokumente in beides Rankings werden aufgewertet

// SearchService.cs - RRF fusion
const int k = 60;

foreach (var (chunk, rank) in denseResults.Select((c, i) => (c, i)))
    scores[chunk.Id] = 1.0 / (k + rank + 1);

foreach (var (chunk, rank) in sparseResults.Select((c, i) => (c, i)))
{
    var rrfScore = 1.0 / (k + rank + 1);
    if (scores.TryGetValue(chunk.Id, out var existing))
        scores[chunk.Id] = existing + rrfScore;  // Boost for appearing in both!
    else
        scores[chunk.Id] = rrfScore;
}

Beispiel: Ein Dokument, das in dichter und in spärlicher Höhe auf Platz 1 der #1 rangiert

  • Dichte: :, Stärke: =, Dicke:
  • Sparse , : , \(1/(60+3) ,= , 0.0159\) ,
  • Kombination aus MSK und 0.0323 Höher als entweder allein

Abfrage-Modi

flowchart TB
    Q[Query] --> CLASS[Classify Query]
    
    CLASS --> |"How do I use X?"| LOCAL[Local Search]
    CLASS --> |"What are the themes?"| GLOBAL[Global Search]  
    CLASS --> |"How does X relate to Y?"| DRIFT[DRIFT Search]
    
    LOCAL --> HS[Hybrid Search] --> CTX1[Chunk + Entity Context]
    GLOBAL --> CS[Community Summaries] --> MAP[Map-Reduce]
    DRIFT --> BOTH[Local + Communities] --> SYN[Synthesize]
    
    CTX1 --> LLM[LLM Answer]
    MAP --> LLM
    SYN --> LLM
    
    style LOCAL stroke:#22c55e,stroke-width:2px
    style GLOBAL stroke:#3b82f6,stroke-width:2px
    style DRIFT stroke:#a855f7,stroke-width:2px

Abfrageklassifikation

// QueryEngine.cs
private static QueryMode ClassifyQuery(string query)
{
    var q = query.ToLowerInvariant();
    if (q.Contains("main theme") || q.Contains("summarize") || q.Contains("overview"))
        return QueryMode.Global;
    if (q.Contains("relate") || q.Contains("connect") || q.Contains("compare"))
        return QueryMode.Drift;
    return QueryMode.Local;
}

Dieser Klassifikator ist bewusst einfach und leicht durch ein kleines Intent-Modell später zu ersetzen. Wenn keine Entities zusammenpassen, degradiert das System sauber zum reinen Hybrid Retrieval.

Verwendung von CLI

Indexierung

# Heuristic mode (default) - fast, no per-chunk LLM
dotnet run --project Mostlylucid.GraphRag -- index ./test-markdown

# LLM mode - Microsoft-style classification
dotnet run --project Mostlylucid.GraphRag -- index ./test-markdown --extraction-mode llm
GraphRAG Indexer
  Source: test-markdown
  Database: graphrag.duckdb
  Model: llama3.2:3b
  Extraction: Heuristic (IDF + signals)

Initializing...
Indexing docker-development-deep-dive.md: 0%
Indexing docker-swarm-cluster-guide.md: 40%
Indexing dockercomposedevdeps.md: 80%
Indexing complete: 100%
Classifying entities...: 0%
Extracted 168 entities, 315 rels (4 LLM calls): 100%
Found 10 communities: 100%
Summarizing c_0_2 (12 entities): 20%
Summarizing c_0_8 (4 entities): 80%

────────────────── Indexing Complete ───────────────────
┌───────────────┬───────┐
│ Metric        │ Count │
├───────────────┼───────┤
│ Documents     │ 5     │
│ Chunks        │ 62    │
│ Entities      │ 168   │
│ Relationships │ 312   │
│ Communities   │ 10    │
└───────────────┴───────┘

Abfragen

dotnet run --project Mostlylucid.GraphRag -- query "How do I use Docker Compose?"
──────────────────── Local Search ────────────────────

Query: How do I use Docker Compose?

╭─Answer────────────────────────────────────────────────╮
│ To run the services defined in the                    │
│ devdeps-docker-compose.yml file, you need to run the  │
│ following command in the same directory as the file:  │
│                                                       │
│ docker compose -f .\devdeps-docker-compose.yml up -d  │
│                                                       │
│ This command will start the containers in detached    │
│ mode.                                                 │
╰───────────────────────────────────────────────────────╯

Related Entities: Docker, container, services, image

Sources: 5 chunks (top score: 0.016)

Statistik

dotnet run --project Mostlylucid.GraphRag -- stats
─────────────── GraphRAG Database Stats ────────────────
┌───────────────┬───────┐
│ Metric        │ Count │
├───────────────┼───────┤
│ Documents     │     5 │
│ Chunks        │    62 │
│ Entities      │   168 │
│ Relationships │   312 │
│ Communities   │    10 │
└───────────────┴───────┘

Database size: 7.76 MB

Kostenvergleich

Für Blog-Posts von (~500, Brocken, , und anderen Dokumenten von MKK4

Einsatz von |, MSFT GraphRAG, Heuristisches und Hybrides |, LLM, |, |-----------|---------------|-----------|--------|-----| ,| , Entitätsextraktion , | , , 1,000 , ruft , | , -0 ,-| , –0 , | ,„1,000" -Aufrufe ,| Weitere Informationen finden Sie unter: http:www.cordis.lu/ |-Klassifikation Einschließlich |-Bremsen (MSK) und |-Brnen (MSK) Zusammenfassungen aus der Gemeinschaft ,| , ~20 , | , 20 , | , -20 ,-| , ~20 ,"| | LLM-Aufrufe insgesamt | ~1,020 | ~24 | ~120 | ~1,024 | | Beziehungsqualität Semantische Semantik-Semantik - Semantisch Semanisch Semantisches Semanisches Semantischer Semantic Semanische semantische | | Kosten für -4o-omini-)o | ~$5-10 | ~$0.15 | ~$0.75 | ~$5-10 | | Kosten Weitere Informationen: http://europa.eu.int/en/comm/index_de.html

Hybrid-Modus ist der süße Punkt für den meisten technischen Inhalt erhalten Sie semantische Beziehungen . . ( . nicht nur co .- .occurrence . ) . bei ~10% . von MSFT .

Rough order---of---MagnitudenschätzungDie genauen Kosten hängen von der Größe des Stücks und der prompten Form ab.

Handelshemmnisse

Weitere Informationen finden Sie unter: http:www.cordis.lu/ |--------|-----------|--------|-----|---------------| Struktur der IDF-Struktur der |, IDF Struktur der +, IDP-Struktur des +, LLM pro Stück ,| , Beziehungen , | , Co , - , LLM , - , | , co ,- , lLM . - , bezeichnet | LLM-Aufrufe für (100, ), MSC4, MCSK5, MSR6, |, MSSK8, MSV9 und ~1,020 Beziehungsqualität niedrig hoch hoch hoch Funktioniert offline |. Ja |. Ja (.Ollama.).|.Ja (.OLLAMA.). API erforderlich |. Die beste Lösung für die Geschwindigkeit von |, -, kritisch Empfohlen Nicht strukturierter Text

Konzeptionell ist dies die gleiche Pipeline wie DocSummarizerBauen Sie zuerst die Struktur, dann lassen Sie ein LLM es erzählen.

Wo dies zusammenbricht Fiction oder erzählerischen Text ohne strukturelle Markup-Beschriftung.-Implizite Beziehungen ohne lexikalisches Signal.-Hoch mehrdeutige Entity-Namen, die Weltwissen erfordern, um zu disambiguieren.-Für diese Fälle verwenden Sie LLM-Modus oder Microsoft-'s volle Annäherung

ANHANG

Die Implementation ist minimal, die Linien über diese Dateien hinweg.

Mostlylucid.GraphRag/
├── Storage/GraphRagDb.cs              # DuckDB with HNSW + provenance
├── Services/EmbeddingService.cs       # ONNX BERT wrapper
├── Services/OllamaClient.cs           # LLM client
├── Extraction/
│   ├── IEntityExtractor.cs            # Extractor interface
│   ├── EntityExtractor.cs             # Heuristic mode
│   ├── HybridEntityExtractor.cs       # Hybrid mode (recommended)
│   └── LlmEntityExtractor.cs          # Full LLM mode
├── Search/SearchService.cs            # BM25 + BERT hybrid
├── Graph/CommunityDetector.cs         # Leiden + summarization
├── Query/QueryEngine.cs               # Local/Global/DRIFT
├── Indexing/MarkdownIndexer.cs        # Chunking
├── GraphRagPipeline.cs                # Orchestration
├── Models.cs                          # Shared types + ExtractionMode enum
└── Program.cs                         # CLI

Quelle: Eurostat. Mostlylucid.GraphRag/

Verwandte Beiträge

Externe Mittel

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.