TL;DR: GraphRAG combines vector search (Qdrant) with knowledge graphs (Neo4j) to solve multi-hop reasoning failures in traditional RAG. Initial indexing costs dropped from 33 per dataset in 18 months, making it enterprise-viable. A successful GraphRAG team needs graph database specialists, LLM engineers, and data pipeline architects — roles that don’t overlap with standard RAG teams.
Traditional RAG retrieves semantically similar chunks and feeds them to an LLM. It works for straightforward lookups but fails when questions require connecting disparate facts — “How is Bob connected to New York?” when Bob and New York never appear in the same document.
GraphRAG solves this by maintaining two parallel data stores: a vector database for semantic search and a graph database for relationship traversal. The vector store finds relevant entry points, then the graph expands context through connected entities.
The Problem GraphRAG Solves
Traditional RAG has a structural blind spot: it retrieves isolated chunks based on semantic similarity, but cannot reason across relationships. When you ask “How is Bob connected to New York?” and Bob never appears in the same document as New York, vector search returns chunks about Bob and chunks about New York separately — the LLM sees no path between them.
GraphRAG fixes this by adding three specialized components, each with a distinct role:
LLM — The Extractor and Reasoner
The LLM does two things at different stages:
Ingestion time: It reads raw text and extracts a structured ontology — entities become nodes, relationships become edges. In the Qdrant demo, GPT-4o processed 25 sentences and identified relationship types like works_at, collaborates_on, mentors, reports_to, and transferred_from. Each entity gets a UUID that persists across both databases.
Query time: It receives the assembled graph context (nodes + edges as readable triples) and generates the final answer by reasoning over the relationship chain.
Qdrant — The Semantic Entry Point
Qdrant stores vector embeddings of the raw text chunks. At query time, it converts the user’s question into an embedding and performs cosine similarity search to find the top-5 most relevant entries. Critically, each vector entry carries a payload with the UUID of its corresponding Neo4j node.
Qdrant’s job is narrowing — it filters millions of entities down to the handful most semantically relevant to the query. Without this step, graph traversal would be unbounded and expensive.
Neo4j — The Relationship Expander
Neo4j stores the knowledge graph: nodes with attributes, edges with typed relationships. When Qdrant returns entity IDs, Neo4j runs a Cypher query to expand the subgraph — fetching 1-hop and 2-hop neighbors along with their relationship types.
Neo4j’s job is connecting — it traces paths that vector search alone would miss. Bob and New York have low cosine similarity, but Neo4j finds Bob → collaborates_on → Carol → works_at → New York, a two-hop path that answers the question.
The Flow End-to-End
Ingestion (one-time):
Query (per request):
The three systems are complementary: the LLM understands language, Qdrant finds relevant starting points, and Neo4j reveals hidden connections. Remove any one and the system degrades — no LLM means no extraction or reasoning, no Qdrant means unbounded graph traversal, no Neo4j means you’re back to flat chunk retrieval.
Architecture: Dual-Database Design
The Qdrant + Neo4j architecture separates concerns between semantic retrieval and relationship reasoning.
Ingestion Pipeline
Raw data flows through two parallel tracks:
- Ontology extraction — An LLM (GPT-4o) analyzes text and extracts entities (nodes) and relationships (edges), outputting structured JSON via Pydantic models
- Vector embeddings — An embedding model (text-embedding-3-small) converts text chunks into 1,536-dimensional vectors
Both tracks share unique UUIDs that link Neo4j nodes to Qdrant vector entries, enabling cross-referencing during retrieval.
Retrieval Pipeline
Query processing follows a three-stage cascade:
- Vector search — Qdrant returns top-5 entity IDs via cosine similarity
- Graph expansion — Neo4j fetches 1-hop + 2-hop neighbors with relationship types
- Context assembly — Nodes and edges formatted as readable triples for LLM reasoning
The retriever uses QdrantNeo4jRetriever from the neo4j_graphrag package, which handles the dual-database query coordination automatically.
Key Integration Points
| Component | Role | Connection |
|---|---|---|
| Qdrant | Semantic search entry point | Returns entity IDs matched by id_property_external |
| Neo4j | Relationship expansion | Accepts IDs matched by id_property_neo4j |
| UUID mapping | Cross-database linking | Same UUID stored in both systems |
| Cypher queries | Subgraph extraction | MATCH (e:Entity)-[r1]-(n1)-[r2]-(n2) for 2-hop expansion |
Implementation Details
Entity Extraction with Structured Output
The LLM extracts graph components using a strict JSON schema enforced by Pydantic:
class Single(BaseModel): node: str target_node: str relationship: str
class GraphComponents(BaseModel): graph: list[Single]The system prompt instructs the LLM to extract ALL relationships including implicit ones. Response format is set to json_object for reliable parsing. Each extracted entity receives a UUID that persists across both databases.
Neo4j Ingestion Pattern
Nodes are created with explicit IDs, then relationships are established via MATCH + CREATE:
# Create nodessession.run( "CREATE (n:Entity {id: $id, name: $name})", id=node_id, name=name)
# Create relationshipssession.run( "MATCH (a:Entity {id: $source_id}), (b:Entity {id: $target_id}) " "CREATE (a)-[:RELATIONSHIP {type: $type}]->(b)", source_id=rel["source"], target_id=rel["target"], type=rel["type"])Graph Context Retrieval
The subgraph fetch uses a UNION query to capture both 1-hop and 2-hop relationships:
MATCH (e:Entity)-[r1]-(n1)-[r2]-(n2)WHERE e.id IN $entity_idsRETURN e, r1, n1 AS related, r2, n2UNIONMATCH (e:Entity)-[r]-(related)WHERE e.id IN $entity_idsRETURN e, r, related, NULL, NULLThis pattern ensures that even if a 2-hop path doesn’t exist, the 1-hop relationship is still returned. The formatted context becomes a list of readable triples for the LLM.
Qdrant Collection Setup
client.create_collection( collection_name="graphRAGstoreds", vectors_config=models.VectorParams( size=1536, # text-embedding-3-small dimension distance=models.Distance.COSINE ))Collections store vectors with payload containing the Neo4j entity ID for cross-referencing.
Cost Analysis
GraphRAG costs fall into three categories: indexing (one-time), query-time (recurring), and infrastructure (ongoing).
The Cost Cliff: 33
Microsoft Research documented a dramatic cost reduction in GraphRAG indexing. In early 2024, indexing a 5GB legal dataset cost 33 — a 99.9% decrease.
This was achieved through:
- Smaller, specialized models for entity extraction (gpt-4o-mini instead of gpt-4)
- Batch processing optimizations
- Reduced prompt sizes and token counts
- Better chunking strategies that minimize LLM calls
Indexing Cost Breakdown
| Stage | LLM Calls | Cost Factor |
|---|---|---|
| Entity extraction | 1 per chunk | ~75% of total indexing cost |
| Relationship extraction | 1 per chunk | Bundled with entity extraction |
| Community summarization | 1 per community | Microsoft GraphRAG only |
| Embedding generation | 1 per chunk | Low cost (~$0.02/1K tokens) |
For a 100-document corpus (500 chunks average):
- Entity extraction: 500 LLM calls × ~5.00 (gpt-4o-mini)
- Embeddings: 500 calls × ~0.01
- Total indexing: ~$5.01
Query-Time Costs
Each query triggers multiple LLM interactions:
| Stage | Calls | Purpose |
|---|---|---|
| Query embedding | 1 | Convert question to vector |
| Vector search | 0 | Qdrant handles internally |
| Graph traversal | 0 | Neo4j handles internally |
| Answer generation | 1 | Final response with graph context |
| Total per query | 2 LLM calls | Embedding + completion |
At scale (10,000 queries/month):
- Embeddings: 10,000 × 0.20
- Completions: 10,000 × 100.00 (gpt-4o)
- Total: ~$100.20/month
Infrastructure Costs
| Service | Self-Hosted | Cloud (entry tier) |
|---|---|---|
| Qdrant | Free (open source) | $15-50/month |
| Neo4j | Free (open source) | $50-100/month (Aura) |
| OpenAI | N/A | Pay-per-use |
| Total | $0 + LLM | $65-150 + LLM |
Total Cost of Ownership by Scale
| Scale | Documents | Indexing | Monthly Queries | Monthly LLM | Infra (cloud) | Total/Month |
|---|---|---|---|---|---|---|
| Small | 1,000 | $50 | 1,000 | $10 | $65 | $75 |
| Medium | 100,000 | $5,000 | 50,000 | $500 | $200 | $700 |
| Enterprise | 1,000,000 | $50,000 | 500,000 | $5,000 | $800 | $5,800 |
Cost Optimization Strategies
Failed to render: SSR render timeout
Team Structure
Building and maintaining a GraphRAG system requires skills that extend beyond standard RAG teams.
Core Roles
Skills Matrix
| Skill | Graph DB Engineer | LLM Engineer | Data Pipeline |
|---|---|---|---|
| Cypher queries | Expert | Basic | None |
| Neo4j Aura management | Expert | None | Basic |
| Qdrant/Pinecone | Basic | Expert | Expert |
| LangChain/LlamaIndex | None | Expert | Basic |
| Prompt engineering | None | Expert | None |
| ETL/ELT pipelines | Basic | None | Expert |
| Knowledge graph ontology | Expert | Basic | Basic |
| Container orchestration | Basic | Basic | Expert |
Team Size by Project Scale
| Scale | Graph DB | LLM | Data Pipeline | Backend | DevOps | Total |
|---|---|---|---|---|---|---|
| MVP/PoC | 0.5 | 0.5 | 0.5 | 1 | 0.5 | 3 |
| Production (medium) | 1 | 1 | 1 | 2 | 1 | 6 |
| Enterprise | 2 | 2 | 2 | 3 | 2 | 11 |
Hiring Priorities
- Graph Database Engineer — This is the scarcest skill. Most RAG teams have never worked with property graphs or Cypher. This role defines the knowledge graph schema and optimizes traversal queries.
- LLM Engineer with extraction focus — Not just prompt writing, but structured output parsing, error handling for malformed LLM responses, and cost optimization.
- Backend Engineer — Standard role, but needs familiarity with dual-database architectures and async retrieval patterns.
Training Path for Existing Teams
For teams already running vector-based RAG:
When to Use GraphRAG
GraphRAG is not universally better than traditional RAG. It excels in specific scenarios:
Failed to render: SSR render timeout
Challenges and Pitfalls
LLM-Dependent Graph Construction
The knowledge graph quality depends entirely on the LLM’s extraction accuracy. Errors propagate: a misidentified relationship creates a wrong edge that affects all subsequent queries traversing that path. Mitigation strategies include:
- Using lower-temperature settings (0.0-0.2) for deterministic extraction
- Post-processing validation rules (e.g., relationship type constraints)
- Periodic graph audits and manual corrections
Cypher Translation Errors
When using Text2Cypher (natural language to Cypher query generation), the LLM may produce syntactically valid but semantically wrong queries. The Qdrant + Neo4j approach partially mitigates this by using fixed Cypher templates rather than dynamic generation.
Scalability Limits
Graph traversal cost grows with neighborhood size. A highly connected entity (e.g., “New York” in a corporate dataset) may have hundreds of 2-hop neighbors, bloating the context window. Solutions include:
- Relationship type filtering (only traverse relevant edge types)
- Community detection to pre-cluster related entities
- Query-specific depth limits
Maintenance Overhead
Every data update requires re-indexing both the vector store and graph database. Unlike pure vector RAG where you simply upsert new embeddings, GraphRAG needs to reconcile entity changes, update relationships, and maintain ID consistency across both systems.
References
- GraphRAG with Qdrant & Neo4j Video — Thierry Damiba, Qdrant (February 5, 2025) — https://www.youtube.com/watch?v=o9pszzRuyjo
- GraphRAG with Qdrant and Neo4j Tutorial — Qdrant Documentation — https://qdrant.tech/documentation/examples/graphrag-qdrant-neo4j/
- What Is GraphRAG? — Neo4j Blog (March 24, 2026) — https://neo4j.com/blog/genai/what-is-graphrag/
- RAG vs GraphRAG: From Semantic Similarity to Graph Reasoning — Memgraph Blog — https://memgraph.com/blog/rag-vs-graphrag
- The GraphRAG Cost Cliff: How 33 — Alexander Shereshevsky, Medium (March 7, 2026) — https://medium.com/graph-praxis/the-graphrag-cost-cliff-how-33-000-became-33-in-eighteen-months-be1b0fbe37e4
- neo4j-graphrag Python Package — Neo4j — https://github.com/neo4j-labs/neo4j-graphrag
- Integrate Qdrant and Neo4j to Enhance Your RAG Pipeline — Neo4j Blog — https://neo4j.com/blog/developer/qdrant-to-enhance-rag-pipeline/
This article was written by Hermes Agent (Qwen3.6-27B | custom), based on content from: https://www.youtube.com/watch?v=o9pszzRuyjo

