GraphRAG: Varför Vector Search bryter ner på Corpus nivå (Svenska (Swedish))

GraphRAG: Varför Vector Search bryter ner på Corpus nivå

Friday, 26 December 2025

//

21 minute read

Ditt RAG-system är bra på "behövande" frågor: hämta några relevanta bitar och syntetisera ett svar. Det kämpar med två vanliga frågetyper:

  • Känslighetsskapande: "Vilka är huvudteman i denna corpus?"
  • Anslutande: "Hur relaterar X till Y över olika dokument?"

De är inte besvarade av någon enda bit. De kräver Täckning + klustring + koppling.

Varför vektorsökning misslyckas här:

  • Det rankar bitar oberoende av likhet med frågan
  • Likhet optimerar relevansen, inte global täckning
  • Inbäddningar fånga "vad låter liknande", inte "vad ansluter till vad"

Du kan brute-force detta med uppmaning och efterbehandling, men du slutar med att bygga upp en graf-formad lösning.

Den viktigaste insikten: GraphRAG ändrar hämtningsenheten. För corpus-frågor vill du inte ha "top-K liknande bitar", du vill ha sammankopplade konceptgemenskaper (och deras sammanfattningar), så modellen ser struktur, inte fragment.

DiagramHÄMTNING kommer från Microsoft Research's papper och finns som en genomförande med öppen källkod. Det håller vektor söka efter specifika frågor, men lägger till en kunskapsgraf och community sammanfattningar för corpus-nivå resonemang.

När du inte ska använda GraphRAG

Innan du dyker in, låt oss vara tydliga om när detta är overkill:

  • Små dokumentuppsättningar (under ~50 dokument): använd bara vektorsökning
  • Endast "hur gör jag" frågor: GraphRAG kommer inte att hjälpa
  • Enhetligt innehåll (inga enheter): ingen grafstruktur att utnyttja
  • Kostnadsbegränsad: indexering kräver många LLM samtal

Om dina användare bara ställer specifika frågor, håll dig till Semantisk sökning. GraphRAG lyser när användare behöver storbild, och det är en mindre publik än vad leverantörerna föreslår.

Inledning

Serienavigering: Detta är del 6 i RAG-serien:

Under hela denna serie har vi byggt allt mer sofistikerade RAG-system. Vi började med grundläggande vektorsökning, add hybrid sökord + semantisk hämtning, och integrerad automatisk indexering. Men alla dessa metoder har en grundläggande begränsning: de hittar liknande bitar, inte sammankopplade begrepp. För corpus-nivå frågor (teman som spänner över många dokument) du behöver struktur.

Den rekommenderade sökvägen: Om du redan har Qdrant-baserad lokal sökning fungerar (som vi gör), prototyp med Python sidvagn för att validera värde, hålla vektorer för lokal sökning, och lägga till en lätt graf för globala / DRIFT frågor. Gå bara "full GraphRAG" när du har bevisat användare ställa dessa frågor.

Problemet med ren Vector RAG

Låt mig visa er vad jag menar med ett konkret exempel.

Vad Vector RAG gör bra

Fråga: "Hur använder jag HTMX med Alpine.js?"

Vector RAG process:

  1. Lägg in frågan: [0.234, -0.891, 0.567, ...]
  2. Hitta liknande bitar i Qdrant
  3. Returnera topp-K matcher om HTMX och Alpine.js
  4. LLM syntar svar från dessa bitar

Detta fungerar eftersom frågan och det relevanta innehållet är Semantiskt liknande. Inbäddningarna fångar den likheten.

// This is what our current SemanticSearchService does
var embedding = await _embeddingService.GetEmbeddingAsync(query);
var results = await _qdrantService.SearchAsync(
    collectionName: "blog_posts",
    queryVector: embedding,
    limit: 10
);
// Returns chunks about HTMX, Alpine.js, frontend patterns

Där Vector RAG kämpar

Fråga: "Vilka är de viktigaste teknikerna jag skriver om och hur förhåller de sig till varandra?"

Vilken vektor RAG returnerar:

Result 1: "HTMX makes it easy to add AJAX to your pages..."
Result 2: "Docker Compose orchestrates multiple containers..."
Result 3: "PostgreSQL's full-text search is surprisingly capable..."
Result 4: "Alpine.js provides reactive state management..."

Det nämner Docker, PostgreSQL, HTMX, ONNX... men inte gruppera dem eller förklara hur de ansluter. Du får fragment, inte insikt.

Problemet: Denna fråga kräver aggregering och relationsförståelse Du måste:

  • Identifiera alla tekniker som nämns
  • Förstå vilka som används tillsammans
  • Gruppera dem i sammanhängande teman

Vektor likhet ensam ger dig inte detta. Om du försöker att lappa detta med uppmaning, hamnar du uppfinna en graf.

Ange GraphRAG

DiagramHÄMTNING är Microsoft Research lösning på detta problem. GrafRAG-papper identifierade de två frågetyper som RAG vid baseline hanterar dåligt (sensemaking och Muskuloskeletala systemet och bindväv) och byggde ett särskilt system för att ta itu med dem.

I stället för att bara inbädda bitar bygger GraphRAG en kunskapsdiagram som fångar entiteter och deras relationer och sedan samlar dem i samhällen med sammanfattningar.

Hur GraphRAG fungerar

Rörledning i en blick:

  • Indexering: Chunks → enheter/relationer → graf → gemenskaper → sammanfattningar
  • Fråga: Lokala = bitar + graf grannskap på global nivå = samhällssammanfattningar på DRIFT = sökvägar + sammanfattningar

GraphRAG lägger till flera komponenter i RAG-ledningen, grupperade i tre kategorier:

  1. Extraktion (enheter + relationer)
  2. Grafisk uppbyggnad (lagring av kunskapsdiagram)
  3. Sammanfattande (samhällsdetektering + hierarki)
flowchart TB
    subgraph "Traditional RAG (What We Have)"
        A[Documents] --> B[Chunks]
        B --> C[Embeddings]
        C --> D[Vector Store]
    end

    subgraph "GraphRAG Additions"
        B --> E[Entity Extraction]
        E --> F[Relationship Extraction]
        F --> G[Knowledge Graph]
        G --> H[Community Detection]
        H --> I[Community Summaries]
    end

    subgraph "Query Time"
        J[User Query] --> K{Query Type?}
        K -->|Specific| L[Local Search]
        K -->|Global| M[Global Search]
        K -->|Hybrid| N[DRIFT Search]

        D --> L
        G --> L
        I --> M
        G --> N
        I --> N
    end

    style E stroke:#f9f,stroke-width:2px
    style H stroke:#bbf,stroke-width:2px
    style I stroke:#9f9,stroke-width:2px

Steg 1: Utvinning av en enhet

En LLM läser varje bit och extrakt enheter (de saker som diskuteras):

Chunk: "Docker Compose makes it easy to define multi-container applications.
        I use it with PostgreSQL for my blog's database layer."

Extracted Entities:
- Docker Compose (technology)
- PostgreSQL (database)
- blog (project)
- database layer (concept)

Steg 2: Förhållandeutdrag

Samma LLM identifierar hur enheter relaterar till varandra:

Relationships:
- Docker Compose --[used_with]--> PostgreSQL
- blog --[has_component]--> database layer
- PostgreSQL --[implements]--> database layer

Steg 3: Kunskapsgrafkonstruktion

Alla enheter och relationer bildar en graf:

graph LR
    subgraph "Frontend Cluster"
        HTMX[HTMX]
        Alpine[Alpine.js]
        Tailwind[Tailwind CSS]
    end

    subgraph "Infrastructure Cluster"
        Docker[Docker]
        Compose[Docker Compose]
        Postgres[PostgreSQL]
        Qdrant[Qdrant]
    end

    subgraph "AI/ML Cluster"
        ONNX[ONNX Runtime]
        Embeddings[Embeddings]
        RAG[RAG]
    end

    HTMX -->|used_with| Alpine
    HTMX -->|styled_by| Tailwind
    Alpine -->|styled_by| Tailwind

    Docker -->|orchestrated_by| Compose
    Compose -->|runs| Postgres
    Compose -->|runs| Qdrant

    ONNX -->|generates| Embeddings
    Embeddings -->|stored_in| Qdrant
    RAG -->|uses| Embeddings
    RAG -->|uses| Qdrant

    style HTMX stroke:#f9f
    style Docker stroke:#bbf
    style RAG stroke:#9f9

Steg 4: Detektion av gemenskapen (Leiden Algorithm)

och Leiden-algoritm kluster tätt anslutna noder i samhällen. Detta spelar roll eftersom det ger dig stabil kluster för att sammanfatta och hämta; samhällena blir era hämtningsenheter för globala frågor.

  • Gemenskapen 1: "Frontend Stack" (HTMX, Alpine.js, Tailwind)
  • Gemenskapen 2: "Container Infrastructure" (Docker, Compose, PostgreSQL, Qdrant)
  • Gemenskapen 3: "Rag pipeline" (ONNX, inbäddningar, Qdrant, RAG)

Lägg märke till hur Qdrant uppträder i två samhällen: det överbryggar infrastruktur och AI/ML.

Steg 5: Gemenskapssammanfattningar

En LLM genererar sammanfattningar för varje gemenskap på varje hierarkinivå:

Community 1 Summary (Frontend Stack):
"The frontend approach combines HTMX for server-driven interactivity
with Alpine.js for client-side state management, styled using Tailwind CSS.
This stack prioritizes HTML-first development with minimal JavaScript,
focusing on progressive enhancement over SPA complexity."

Community 2 Summary (Container Infrastructure):
"The blog runs on Docker Compose, orchestrating PostgreSQL for persistent
storage, Qdrant for vector search, and the ASP.NET Core application.
This containerized architecture enables consistent local development
and production deployment."

Frågalägen

GraphRAG ger tre frågelägen, var och en optimerad för olika frågetyper:

Global sökning

Bäst för: "Vilka är huvudteman?" "Summarisera huvudämnena."

Använder communitysammanfattningar (inte enskilda bitar) för att svara på frågor om sensemaking:

Query: "What technologies does this blog cover most?"

Process:
1. Retrieve all community summaries
2. Map: Ask LLM to extract technology themes from each summary
3. Reduce: Combine partial answers into final response

Response:
"The writing centres on three technology clusters:
1. **Frontend Development** - HTMX, Alpine.js, Tailwind CSS for minimal-JS web UIs
2. **AI/ML Infrastructure** - RAG pipelines, ONNX embeddings, vector search with Qdrant
3. **DevOps/Containerization** - Docker, PostgreSQL, ASP.NET Core deployment"

Lokal sökning

Bäst för: "Hur konfigurerar jag X?" "Vad är Y?"

Kombinerar enhetsfokuserad graf traversal med traditionell vektorsökning:

Query: "How do I use Qdrant with ONNX embeddings?"

Process:
1. Identify entities in query: Qdrant, ONNX, embeddings
2. Retrieve graph neighborhood around those entities
3. Also retrieve vector-similar chunks
4. Combine into rich context for LLM

Response includes:
- Direct relationships (ONNX generates embeddings stored in Qdrant)
- Related entities (all-MiniLM-L6-v2 model, cosine similarity)
- Specific code examples from vector-retrieved chunks

DRIFT- sökning

Bäst för: "Hur relaterar X till Y?" "Jämför A och B."

DRIFT-sökning (Dynamic Resoning and Inference with Flexible Traversal). enligt beskrivning i GraphRAG-dokumenten, kombinerar lokal sökning med gemenskap sammanhang. Det är fortfarande använder LLM resonemang över hämtade strukturerade sammanhang (inte magisk graf inference), men strukturen hjälper LLM se anslutningar det skulle missa med platta bitar.

Query: "How do the frontend and backend technologies connect?"

Process:
1. Start with entities: HTMX, ASP.NET Core
2. Traverse graph to find connection paths
3. Include community summaries for context
4. Generate answer showing the full picture

Response:
"HTMX makes requests to ASP.NET Core endpoints, which query PostgreSQL
and Qdrant. The connection flows through the API layer, where endpoints
return HTML fragments that HTMX swaps into the DOM. Alpine.js handles
client-side state for interactive components like search typeahead."

Jämföra diagramRAG med vårt nuvarande system

Låt oss kartlägga GraphRAG koncept till vad vi redan har i Mostlylucid.SemanticSearch:

Komponent på nuvarande system på GraphRAG-likvärdig |-----------|---------------|---------------------| | Inbäddningar ONNX (all-MiniLM-L6-v2) på samma (eller OpenAI) | Vektorförråd på Qdrant på Qdrant / LanceDB | Utdrag av en enhet ingen på LLM-kraftig extraktion
| Kunskapsdiagram och ingen på grafen databas / in-minne på | Detektering av gemenskapen Obligatoriskt för Leiden-algoritmen | Fråga: Specifik | SemanticSearchService.SearchAsync() och lokal sökning | Fråga: Globalt på ej stöd för global sökning

Vårt nuvarande genomförande hanterar Lokal sökning GraphRAG skulle lägga till Global sökning och DRIFT- sökning förmåga.

// What we have today (Local Search equivalent)
public async Task<List<SearchResult>> SearchAsync(string query, int limit = 10)
{
    var embedding = await _embeddingService.GetEmbeddingAsync(query);
    return await _qdrantService.SearchAsync("blog_posts", embedding, limit);
}

// What GraphRAG would add
public async Task<string> GlobalSearchAsync(string query)
{
    // 1. Retrieve community summaries (not chunks)
    var summaries = await _graphService.GetCommunitySummariesAsync();

    // 2. Map: Extract relevant themes from each summary
    var partialAnswers = await Task.WhenAll(
        summaries.Select(s => _llm.ExtractThemesAsync(query, s))
    );

    // 3. Reduce: Combine into final answer
    return await _llm.SynthesizeAsync(query, partialAnswers);
}

Genomförandemetoder

Det finns tre sätt att lägga till GraphRAG i ett befintligt system.

Alternativ 1: Python Sidecar (Rekommenderas för undersökning)

Kör Microsofts GraphRAG som en separat tjänst:

# docker-compose.graphrag.yml
services:
  graphrag:
    build:
      context: ./graphrag
    volumes:
      - ./data/input:/app/input
      - ./data/output:/app/output
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}

  graphrag-api:
    build:
      context: ./graphrag-api
    ports:
      - "8001:8000"
    depends_on:
      - graphrag
// GraphRagClient.cs - Call from ASP.NET Core
public class GraphRagClient
{
    private readonly HttpClient _http;

    public GraphRagClient(HttpClient http)
    {
        _http = http;
        _http.BaseAddress = new Uri("http://graphrag-api:8000");
    }

    public async Task<string> GlobalSearchAsync(string query)
    {
        var response = await _http.PostAsJsonAsync("/query/global", new { query });
        var result = await response.Content.ReadFromJsonAsync<GraphRagResponse>();
        return result.Answer;
    }

    public async Task<string> LocalSearchAsync(string query)
    {
        var response = await _http.PostAsJsonAsync("/query/local", new { query });
        var result = await response.Content.ReadFromJsonAsync<GraphRagResponse>();
        return result.Answer;
    }
}

Förmåner: Använd Microsofts stridsprövade genomförande, snabbt till prototyp Minus: Pythonberoende, LLM-kostnader för indexering, processöverskridande kommunikation

Alternativ 2: NET Native (Production Path)

Bygg nyckelkomponenterna i C#. BERT-baserade extraktions- och Ollama-mönster från DocSummarizer Ordförande arbeta på samma sätt här.

Utdrag av en enhet

Be en LLM att identifiera saker (enheter) i varje del - strukturerade enheter snarare än fria-former ämnen:

public async Task<List<Entity>> ExtractEntitiesAsync(string chunk)
{
    var prompt = $"""
        Extract entities from this text. Return JSON array.
        Types: technology, concept, project, person, organization
        Text: {chunk}
        Format: [{{"name": "Docker", "type": "technology"}}]
        """;

    var response = await _ollama.GenerateAsync(prompt);
    return JsonSerializer.Deserialize<List<Entity>>(response);
}

Produktionskrav: LLM JSON utmatning kommer att Det här är inte en valfri härdning.

  • Scheme-konstruerad generation (Ollama's format: json, OpenAI:s funktion anrop)
  • Återvinning med reparationsslingor (Upptäck missbildade JSON, be LLM att fixa det)
  • Återfallsutdragning (regexmönster för gemensamma enhetstyper)

LLMs är probabilistiska; din extraktion pipeline får inte vara.

Förhållandeutdrag

När du har enheter, fråga LLM hur de ansluter:

public async Task<List<Relationship>> ExtractRelationshipsAsync(
    string chunk, List<Entity> entities)
{
    var names = string.Join(", ", entities.Select(e => e.Name));
    var prompt = $"""
        Given entities: {names}
        Extract relationships. Return JSON array.
        Text: {chunk}
        Format: [{{"source": "Docker", "target": "PostgreSQL", "rel": "runs"}}]
        """;

    return JsonSerializer.Deserialize<List<Relationship>>(
        await _ollama.GenerateAsync(prompt));
}

Grafisk lagring med normalisering av entitet

Den största praktiska smärtan är Företagets alias: "ASP.NET Core", "ASP.NET", och "aspnetcore" bör vara samma nod. Enkel normalisering hjälper:

public class KnowledgeGraph
{
    private readonly Dictionary<string, Entity> _entities = new();
    private readonly List<Relationship> _relationships = new();

    public void AddEntity(Entity entity)
    {
        var key = Normalise(entity.Name);  // "ASP.NET Core" → "aspnetcore"
        _entities[key] = entity;
    }

    private string Normalise(string name) =>
        name.ToLowerInvariant().Replace(".", "").Replace("-", "").Trim();
}

För allvarlig användning, överväga inbäddning-baserad enhet deduplicering: om två enhetsnamn har liknande inbäddningar, de är förmodligen samma sak.

Produktionssmärtor poäng (GraphRAG's värde är beroende av grafens kvalitet):

  • Synonymtabeller/aliastabeller: bevara kanoniska namn och kända alias
  • Kontroll av relationsschemat: begränsning tillåtna predikat för att förhindra hallucinerade relationstyper
  • Förtroendepoäng + beskärning: inte alla extraherade relationer är lika tillförlitliga
  • Inkrementell omindexering: när dokument uppdateras, måste du lappa grafen, inte bygga om den

Diagram Traversell

Hitta närstående enheter är en bredd-första sökning:

public List<Entity> GetNeighbors(string entityName, int depth = 1)
{
    var result = new HashSet<Entity>();
    var queue = new Queue<(string Name, int Depth)>();
    queue.Enqueue((Normalise(entityName), 0));

    while (queue.Count > 0)
    {
        var (name, d) = queue.Dequeue();
        if (d >= depth) continue;

        // Find all entities connected to this one
        var neighbours = _relationships
            .Where(r => Normalise(r.Source) == name || Normalise(r.Target) == name)
            .SelectMany(r => new[] { r.Source, r.Target });

        foreach (var neighbour in neighbours)
            if (_entities.TryGetValue(Normalise(neighbour), out var entity))
                if (result.Add(entity))
                    queue.Enqueue((Normalise(neighbour), d + 1));
    }
    return result.ToList();
}

Detektering av gemenskapen

Detta är en ansluten komponenter baslinje, inte full Leiden. Leiden optimerar modularitet (dense interna anslutningar, sparsamma externa). För en korrekt implementering, använd ett grafbibliotek eller anpassa algoritmen.

public List<Community> DetectCommunities(KnowledgeGraph graph)
{
    // Connected components: group everything reachable together
    var visited = new HashSet<string>();
    var communities = new List<Community>();

    foreach (var entity in graph.GetAllEntities())
    {
        if (visited.Contains(entity.Name)) continue;
        
        // BFS to find all connected entities
        var community = new Community();
        var queue = new Queue<string>();
        queue.Enqueue(entity.Name);

        while (queue.Count > 0)
        {
            var name = queue.Dequeue();
            if (!visited.Add(name)) continue;
            community.Entities.Add(graph.GetEntity(name));
            foreach (var neighbor in graph.GetNeighbors(name, depth: 1))
                queue.Enqueue(neighbor.Name);
        }
        communities.Add(community);
    }
    return communities;
}

Sammanfattande av gemenskapen

Varje community får en sammanfattning som beskriver dess tema. Detta är vad makt Global Search:

public async Task<string> SummarizeCommunityAsync(Community community)
{
    var entities = string.Join("\n", 
        community.Entities.Select(e => $"- {e.Name}: {e.Description}"));
    
    var prompt = $"""
        Summarize what unites these concepts (2-3 sentences):
        {entities}
        """;

    return await _ollama.GenerateAsync(prompt);
}

Alternativ 3: Hybrid (Pragmatic Middle Ground)

Detta är det rekommenderade tillvägagångssättet om du redan har fungerande vektorsökning. Behåll Qdrant för lokal sökning, lägg till ett lätt diagramlager för globala/DRIFT-frågor.

Förfrågans klassificering

Först, ta reda på vilken typ av fråga detta är:

// WARNING: Toy heuristic for illustration only.
// In production, use a classifier prompt or few-shot rules and log misroutes.
private QueryMode ClassifyQuery(string query)
{
    var q = query.ToLowerInvariant();
    
    if (q.Contains("main theme") || q.Contains("summarize") || q.Contains("what topics"))
        return QueryMode.Global;
    
    if (q.Contains("relate") || q.Contains("connect") || q.Contains("compare"))
        return QueryMode.Drift;
    
    return QueryMode.Local;
}

Lokal sökning (förstärkt)

Använd befintlig vektorsökning, eventuellt berikad med grafkontext:

private async Task<string> LocalSearchAsync(string query)
{
    // Existing semantic search (what we have today)
    var chunks = await _semanticSearch.SearchAsync(query, limit: 10);

    // NEW: Enrich with related entities from graph
    var entities = await _graphService.ExtractEntitiesFromQueryAsync(query);
    var related = await _graphService.GetEntityContextAsync(entities);

    return await _llm.GenerateAsync(query, FormatContext(chunks, related));
}

Global sökning (ny kapacitet)

Karta-reducera över community sammanfattningar (ingen vektor sökning behövs):

private async Task<string> GlobalSearchAsync(string query)
{
    var summaries = await _graphService.GetAllCommunitySummariesAsync();

    // Map: Extract relevant info from each community
    var partials = await Task.WhenAll(
        summaries.Select(s => _llm.ExtractRelevantInfoAsync(query, s)));

    // Reduce: Combine into final answer
    return await _llm.SynthesizeAsync(query, partials.Where(p => !string.IsNullOrEmpty(p)));
}

DRIFT-sökning (konnektiva frågor)

Kombinera lokala resultat med community sammanhang för "hur X relaterar till Y" frågor:

private async Task<string> DriftSearchAsync(string query)
{
    var localResults = await LocalSearchAsync(query);
    
    var entities = await _graphService.ExtractEntitiesFromQueryAsync(query);
    var communities = await _graphService.GetCommunitiesForEntitiesAsync(entities);
    var themes = string.Join("\n", communities.Select(c => c.Summary));

    return await _llm.GenerateAsync(
        $"Question: {query}\n\nDetails:\n{localResults}\n\nBroader themes:\n{themes}",
        systemPrompt: "Synthesize the details with the thematic context.");
}

Kostnads- och prestationsöverväganden

GraphRAG har betydande kompromisser jämfört med ren vektor-RAG.

Indexeringskostnader

Kostnader för utvinning av entitet/relation varierar avsevärt beroende på modell, snabb utformning och bitstorlek. ett eller två LLM samtal per bit plus ett mindre antal samtal för samhällssammanfattningar.

på drift på Vector RAG på GraphRAG på |-----------|------------|----------| | Inbäddning 1 samtal/tjunk på samma gång | Enhet/relationsutdrag Inga på 1-2 LLM samtal/chunk | Sammanfattande av gemenskapen Obligatoriskt samtal/samhällssamtal/samhällssamtal

För en corpus av 1000 blogginlägg med 5 bitar vardera (5,000 bitar totalt), vektor-endast indexering är i huvudsak bara inbäddningskostnader. GraphRAG lägger tusentals LLM kräver extraktion och summering. Den exakta kostnaden beror kraftigt på ditt modellval och snabb effektivitet; med hjälp av lokala modeller (Ollama med lama3.2 eller liknande) eliminerar API-kostnader helt, vilket är den rekommenderade metoden för experiment.

Frågekostnader

Vektor RAG och GraphRAG Local och GraphRAG Global |------------|------------|----------------|-----------------| | Vektorsökning 1 samtal 1 samtal 0 samtal | Tvärgående diagram 0 på 1-2 frågor 0 på | LLM-samtal (karta) + 1 (reducera)

Global Search är dyrare per fråga, men det svarar på frågor som Local Search helt enkelt inte kan. Du kan också cache globala svar och uppdatera dem endast när corpus ändras.

GrafRAG- fellägen

GraphRAG är inte magi.

  • Extraktionsfel: LLMs missa enheter eller hallucinata relationer
  • Entity aliasing (Entity aliasing) (Entity aliasing) (Entity aliasing) (Entity aliasing (Entity aliasing) (Entity aliasing) (Entity aliasing) (Entity aliasing (Entity aliasing) (Entity aliasing (Entity aliasing) (Entity aliasing (Entity aliasing) (Entity aliasing (Entity aliasing) (Entity aliasing) (Entity aliasing (Ent) (Entity aliasing (Entity aliasing (Entity aliasing (Ent (Entity aliasering: "ASP.NET Core" vs "ASP.NET" vs "aspnetcore" blir separata noder
  • Grafisk avdrift: När dokumenten uppdateras kan grafen bli gammal
  • Gemenskapssammanfattningar: Sammanfattningar uppdateras inte automatiskt när enheter ändras

Entitetsnormalisering är den största praktiska smärtan.

  • Canonical namn + alias
  • Fallvikning och normalisering av interpunktion
  • Valfritt inbäddande-baserad avduplicering av enhet

Integrering med vår bloggsökning

Här är hur GraphRAG kan förbättra bloggens befintliga semantiska sökning:

Nuvarande flöde

User types in search → SemanticSearchService → Qdrant → Results

Ökat flöde

Klassifiern leder frågor till olika sökstrategier. Här är hur en global fråga flöden - notera att den aldrig rör vektorbutiken:

sequenceDiagram
    participant U as User
    participant API as Search API
    participant C as Query Classifier
    participant G as Global Search
    participant KG as Knowledge Graph

    U->>API: "What topics does this blog cover?"
    API->>C: Classify query
    C-->>API: QueryMode.Global

    API->>G: GlobalSearch(query)
    G->>KG: GetCommunitySummaries()
    KG-->>G: [Frontend, Infrastructure, AI/ML]
    G->>G: MapReduce over summaries
    G-->>API: Synthesized answer

    API-->>U: "The blog covers three main areas..."

Jämför detta med en lokal fråga, som kombinerar vektorsökning med graf sammanhang för rikare svar:

sequenceDiagram
    participant U as User
    participant API as Search API
    participant C as Query Classifier
    participant L as Local Search
    participant Q as Qdrant
    participant KG as Knowledge Graph

    U->>API: "How do I use HTMX?"
    API->>C: Classify query
    C-->>API: QueryMode.Local

    API->>L: LocalSearch(query)
    L->>Q: Vector search
    Q-->>L: Relevant chunks
    L->>KG: GetEntityContext("HTMX")
    KG-->>L: Related: Alpine.js, Tailwind, ASP.NET
    L-->>API: Answer with rich context

    API-->>U: "HTMX is used with Alpine.js for..."

Den viktigaste skillnaden: globala frågor aggregerade community sammanfattningar (corpus-nivå teman), medan lokala frågor hämta specifika bitar berikade med entitetsrelationer.

Ett enklare alternativ: GraphRAG är fortfarande i hög grad ett forskningsverktyg - enhet utvinning, graf konstruktion, och community detektion ger betydande komplexitet och LLM kostnader. För de flesta användningsfall, BERT inbäddningar + BM25 nyckelord som matchar Det här är vad som funkar bättre. Källargrafens Cody använder för kodunderrättelse, och vad DocSummarizer Ordförande användning för dokumentsammanfattning. Mönstret: hybrid hämtning hanterar relevans; LLM handtag sammansättning, inte Beslutsfattande. – Du får 80 % av fördelen med 20 % av komplexiteten.

Genomförandeskiss

API:et är enkelt: klassificera förfrågan, rutt till lämplig handläggare:

[HttpGet("api/search")]
public async Task<IActionResult> Search([FromQuery] string q, [FromQuery] string mode = "auto")
{
    if (mode == "auto")
        mode = ClassifyQuery(q);

    // global/local return synthesised answers; default returns raw search results
    return mode switch
    {
        "global" => Ok(await _graphRag.GlobalSearchAsync(q)),  // synthesised answer
        "local" => Ok(await SearchWithGraphContext(q)),        // answer with citations
        _ => Ok(await _semanticSearch.SearchAsync(q))          // raw ranked results
    };
}

Vektorsökning och grafsökning kompletterar varandra. Använd vektorer för "hur gör jag" frågor, grafer för "vad är teman" frågor.

Slutsatser

GraphRAG utökar RAG från "hitta liknande bitar" till "förstå kunskapsstrukturen." Det är inte en ersättning för vektorsökning; det är en förbättring som möjliggör nya frågetyper.

Vad GraphRAG tillägger:

  • Entitets- och relationsutdragning
  • Konstruktion av kunskapsdiagram
  • Gemenskapens upptäckt och hierarkiska sammanfattningar
  • Global Sök efter frågor om sensemaking
  • DRIFT Sök efter bindvävsresonemang

När du ska använda den:

  • Du har en omfattande dokumentsamling
  • Användare frågar "vad är teman" typ frågor
  • Ditt innehåll har tydliga enheter och relationer
  • Du vill automatiskt ha ytanslutningar

Genomförande:

  1. Fråga först: behöver du verkligen detta? BERT + BM25 hybrid hämtning hanterar de flesta användningsfall
  2. Om ja, prototyp med Python sidvagn för att validera värdet
  3. Bygg .NET infödda om kostnader / latency materia
  4. Använd lokala LLM (Ollama) för att kontrollera indexeringskostnader

Resurser

GraphRAG-tjänsteman:

RAG-serien:

Enklare alternativ (BERT + BM25):

Finding related posts...
logo

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