Skip to content

RAG graph

GraphRAG augments vector retrieval with a knowledge graph: entities (people, organizations, locations, concepts) and relations between them, extracted from documents and queried by graph traversal. The graph sub-package supplies storage (in-memory + Neo4j), extraction (LLM-driven), community detection (Louvain), entity resolution (name-normalising + LLM-judged merging), and a Helix retriever that expands matched entities by N hops.

A graph store satisfies:

type GraphStore interface {
    AddEntity(ctx, *Entity) error
    AddRelation(ctx, *Relation) error
    GetEntity(ctx, id) (*Entity, error)
    GetRelations(ctx, entityID) ([]*Relation, error)
    SearchEntities(ctx, query, topK) ([]*Entity, error)
    GetTriples(ctx, entityID) ([]*Triple, error)
    AddTriple(ctx, *Triple) error
    Size() int
}

Implementations

in-memory — process-local graph store

rag:
  graph:
    store:
      type: in-memory

InMemoryGraphStore holds entities, relations, and triples in maps + slices. Sufficient for prototyping and corpora up to a few hundred thousand entities. Implements Enumerable (AllEntities, AllRelations) and Merger (MergeEntities), so community detection and entity resolution work directly against it. Source: pkg/rag/graph/graph.go.

neo4j — Neo4j-backed graph store

rag:
  graph:
    store:
      type: neo4j
      uri: bolt://localhost:7687
      username: neo4j
      password: ${NEO4J_PASSWORD}
Field Type Default Description
uri string — Required. bolt:// or neo4j:// URI.
username string — Required.
password string — Required.

Uses the official neo4j-go-driver/v5. MERGE-based upserts on Entity nodes; relations stored as :RELATES edges with type and id properties. Use for production where the graph outlives one process and supports complex Cypher queries. Source: pkg/rag/graph/neo4j.go.

Building the graph

EntityExtractor — LLM-driven entity + relation extraction

rag:
  graph:
    build:
      extractor:
        model: ${LLM_REF}
      store: ${GRAPH_STORE_REF}

EntityExtractor.Extract(ctx, *rag.Document) prompts the LLM to return entities (name|type) and relations (source|target|type). GraphBuildProcessor wraps it as a Helix processor: each document flowing through the route has its entities and relations upserted into the configured graph store. Source: pkg/rag/graph/graph.go (EntityExtractor, GraphBuildProcessor).

DetectCommunities — Louvain community detection

rag:
  graph:
    communities:
      reporter:
        model: ${LLM_REF}

Partitions the entity graph using the local-moving phase of Louvain modularity optimisation. Returns []Community (largest first, deterministic). CommunityReporter walks the communities, prompting the LLM to give each one a title + summary — these become the "community reports" you can search against for high-level questions ("what are the main themes?"). CommunityRetriever then plugs into the retrieve stage to surface relevant communities by name match. Source: pkg/rag/graph/community.go.

ResolveEntities — entity de-duplication

rag:
  graph:
    resolve:
      judge: ${LLM_REF}   # optional

Normalises entity names (lowercase, alphanumerics only — so OpenAI, open ai, Open-AI collapse) and merges duplicates into the lowest-ID canonical entity via the store's Merger interface. With opts.Judge set, the LLM confirms each multi-member group before merging (guards against over-merging entities that happen to normalise the same). Returns the number of duplicates merged away. Source: pkg/rag/graph/resolve.go.

Querying the graph

GraphRetriever — N-hop entity expansion

rag:
  graph:
    retrieve:
      store: ${GRAPH_STORE_REF}
      hops: 2
      top_k: 10
Field Type Default Description
store ref — The graph store to query.
hops int 1 Graph hops to expand from matched entities.
top_k int 10 Maximum entities returned.

Retrieve(ctx, queryText, hops, topK): 1. SearchEntities for entities whose name overlaps the query. 2. Walk hops levels of relations to gather connected entities. 3. Return one SearchResult per visited entity, with the relation chain in Metadata.

GraphRetrieveProcessor wraps it as a Helix processor. Use as a sibling retriever in a fusion retriever alongside a vector retriever — the graph surfaces facts that span multiple documents (connections), the vector retriever surfaces individual passages. Source: pkg/rag/graph/graph.go (GraphRetriever, GraphRetrieveProcessor).

CommunityRetriever — surface communities by topic

rag:
  graph:
    community-retrieve:
      communities: ${COMMUNITIES_REF}
      entities: ${ENTITIES_REF}

Indexes pre-detected communities and returns each community report as a SearchResult when the query matches one of its member entity names or title/summary tokens. Pairs naturally with compact or tree-summarize synthesis for high-level questions. Source: pkg/rag/graph/community.go (CommunityRetriever).

Choosing between them

Use case Pattern
Prototype in-memory store + GraphRetriever
Production neo4j store + GraphRetriever + CommunityRetriever
Need high-level / theme questions Run DetectCommunities + CommunityReporter, query with CommunityRetriever
Many duplicate entity names Run ResolveEntities (optionally with LLM judge) before retrieving
Multi-hop questions Set hops: 2 or 3 (each hop drastically widens the search)

See also

  • retrieve — combine GraphRetriever and a vector retriever via fusion or ensemble.
  • extract — entity extraction here is a per-chunk metadata enrichment; the graph version produces a typed graph.
  • generate — compact / tree-summarize are the usual synthesizers for graph + community results.
  • RAG parity with RAGFlow — GraphRAG parity tracking.