skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
neo4j-contrib/neo4j-skills983 installs

neo4j-graphrag-skill

Build GraphRAG retrieval pipelines on Neo4j using the neo4j-graphrag Python package (v1.22.0+). Covers retriever selection (VectorRetriever, HybridRetriever, VectorCypherRetriever, HybridCypherRetriever, Text2CypherRetriever, ToolsRetriever), external vector DB retrievers (Weaviate, Pinecone, Qdrant), retrieval_query Cypher fragments, query_params, filters, GraphRAG pipeline wiring (GraphRAG + LLM + prompt), all LLM providers (OpenAI, Anthropic, Gemini/VertexAI, Bedrock, Cohere, Mistral, Ollama), embedder setup, index creation, token usage tracking, Cypher 25 SEARCH clause, and LangChain/LlamaIndex integration. Does NOT handle KG construction — use neo4j-document-import-skill. Does NOT handle plain vector search — use neo4j-vector-index-skill. Does NOT handle GDS analytics — use neo4j-gds-skill. Does NOT handle agent memory — use neo4j-agent-memory-skill.

How do I install this agent skill?

npx skills add https://github.com/neo4j-contrib/neo4j-skills --skill neo4j-graphrag-skill
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides instructions for building GraphRAG pipelines using the official Neo4j GraphRAG Python package. It covers retriever selection, index creation, and integration with major LLM providers. No security issues were detected; the skill follows best practices for Neo4j integration and includes built-in security features for LLM-generated Cypher queries.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Neo4j GraphRAG Skill

When to Use

  • Building GraphRAG retrieval pipelines with neo4j-graphrag Python package
  • Choosing between VectorRetriever, HybridRetriever, VectorCypherRetriever, HybridCypherRetriever
  • Writing retrieval_query Cypher fragments for graph-augmented context
  • Wiring retriever + LLM into a GraphRAG pipeline
  • Using LLM-routed multi-retriever with ToolsRetriever
  • Debugging low retrieval quality
  • Integrating Neo4j with LangChain, LlamaIndex, or Haystack

When NOT to Use

  • KG construction from documents → neo4j-document-import-skill
  • Plain vector/semantic search without graph traversal → neo4j-vector-index-skill
  • Hybrid search that combines vector with fulltext or other ranked sources → neo4j-vector-index-skill
  • GDS algorithms (PageRank, Louvain, node embeddings) → neo4j-gds-skill
  • Agent long-term memory → neo4j-agent-memory-skill
  • Writing raw Cypher queries → neo4j-cypher-skill

Retriever Selection

Has fulltext index?
  YES → Hybrid variants (HybridRetriever / HybridCypherRetriever)
  NO  → Vector variants (VectorRetriever / VectorCypherRetriever)

Need graph traversal after vector lookup?
  YES → Cypher variants (VectorCypherRetriever / HybridCypherRetriever)
  NO  → plain variants

Natural-language-to-Cypher?        → Text2CypherRetriever (no embedder needed)
LLM should route between retrievers? → ToolsRetriever
Vectors stored in external DB?      → WeaviateNeo4jRetriever / PineconeNeo4jRetriever / QdrantNeo4jRetriever
RetrieverVectorFulltextGraphBest For
VectorRetriever✓——Baseline semantic search
HybridRetriever✓✓—Better recall, no graph expansion
VectorCypherRetriever✓—✓GraphRAG without fulltext
HybridCypherRetriever✓✓✓Production GraphRAG — default
Text2CypherRetriever——✓NL→Cypher, no embedder
ToolsRetrievervariesvariesvariesLLM-routed multi-retriever
WeaviateNeo4jRetriever✓—✓Vectors in Weaviate
PineconeNeo4jRetriever✓—✓Vectors in Pinecone
QdrantNeo4jRetriever✓—✓Vectors in Qdrant

Install

pip install neo4j-graphrag[openai]        # OpenAI LLM + embeddings
pip install neo4j-graphrag[anthropic]     # Anthropic Claude
pip install neo4j-graphrag[google]        # Vertex AI / Gemini
pip install neo4j-graphrag[bedrock]       # Amazon Bedrock (boto3)
pip install neo4j-graphrag[cohere]        # Cohere
pip install neo4j-graphrag[mistralai]     # MistralAI
pip install neo4j-graphrag[ollama]        # Ollama (local)
pip install neo4j-graphrag[weaviate]      # Weaviate external retriever
pip install neo4j-graphrag[pinecone]      # Pinecone external retriever
pip install neo4j-graphrag[qdrant]        # Qdrant external retriever

Requires: Python >= 3.10, neo4j >= 5.17.0 (driver 6.x supported).


Step 2 — Choose Retriever

Pick from Retriever Selection table above.

For custom Cypher hybrid search outside the neo4j-graphrag retriever APIs, use neo4j-vector-index-skill.

Vector backend selection [v1.16+, auto]: on Neo4j 2026.01+ all four vector/hybrid retrievers auto-route through the Cypher 25 SEARCH ... WHERE clause when filters are SEARCH-compatible (simple AND comparisons) and all filter props are declared in the index WITH [n.prop] list. $or, $in, $like, or undeclared props → automatic fallback to db.index.vector.queryNodes() procedure path (with warning log). Declare filterable properties via filterable_properties=[...] on create_vector_index().


Step 3 — Create Indexes (run once)

// Vector index (all retrievers need this)
CREATE VECTOR INDEX chunk_embedding IF NOT EXISTS
FOR (c:Chunk) ON (c.embedding)
OPTIONS { indexConfig: {
  `vector.dimensions`: 1536,
  `vector.similarity_function`: 'cosine'
} };

// Fulltext index (Hybrid retrievers only)
CREATE FULLTEXT INDEX chunk_fulltext IF NOT EXISTS
FOR (c:Chunk) ON EACH [c.text];

// Confirm ONLINE before ingesting:
SHOW INDEXES YIELD name, state
WHERE name IN ['chunk_embedding', 'chunk_fulltext']
RETURN name, state;
// Both must show state = 'ONLINE'

If index not ONLINE: wait, poll every 5s. Do NOT start ingestion until ONLINE.


Step 4 — Core Pattern (HybridCypherRetriever)

from neo4j import GraphDatabase
from neo4j_graphrag.embeddings import OpenAIEmbeddings
from neo4j_graphrag.generation import GraphRAG
from neo4j_graphrag.llm import OpenAILLM
from neo4j_graphrag.retrievers import HybridCypherRetriever

driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USERNAME, NEO4J_PASSWORD))
embedder = OpenAIEmbeddings(model="text-embedding-3-large")  # OPENAI_API_KEY from env

# retrieval_query: Cypher fragment executed after the vector/fulltext lookup.
# Auto-injected variables:  node  (matched node)   score  (similarity float)
# MUST include a RETURN clause.  score must appear in RETURN.
retrieval_query = """
MATCH (node)<-[:HAS_CHUNK]-(article:Article)
OPTIONAL MATCH (article)-[:MENTIONS]->(org:Organization)
RETURN node.text AS chunk_text,
       article.title AS article_title,
       collect(DISTINCT org.name) AS mentioned_organizations,
       score
"""

retriever = HybridCypherRetriever(
    driver=driver,
    vector_index_name="chunk_embedding",
    fulltext_index_name="chunk_fulltext",
    retrieval_query=retrieval_query,
    embedder=embedder,
)

llm = OpenAILLM(model_name="gpt-4.1", model_params={"temperature": 0})

rag = GraphRAG(
    retriever=retriever,
    llm=llm,
)

response = rag.search(
    query_text="Who does Alice work for?",
    retriever_config={"top_k": 5},
)
print(response.answer)
driver.close()

VectorCypherRetriever

from neo4j_graphrag.retrievers import VectorCypherRetriever

retriever = VectorCypherRetriever(
    driver=driver,
    index_name="chunk_embedding",
    retrieval_query=retrieval_query,
    embedder=embedder,
)

response = rag.search(
    query_text="What happened at Apple?",
    retriever_config={"top_k": 10},
)

Text2CypherRetriever

Translates natural language to Cypher using an LLM. No embedder required.

Security (v1.16.0+): Every LLM-generated Cypher is run through EXPLAIN first. Any statement classified as write/destructive raises Text2CypherRetrievalError instead of executing — prevents prompt-injection attacks.

from neo4j_graphrag.retrievers import Text2CypherRetriever

retriever = Text2CypherRetriever(
    driver=driver,
    llm=OpenAILLM(model_name="gpt-4.1"),
    neo4j_schema=None,       # None = auto-fetch schema from DB; pass string to trim
    examples=[
        "Q: Who works at Neo4j? A: MATCH (p:Person)-[:WORKS_AT]->(c:Company {name:'Neo4j'}) RETURN p.name"
    ],
)
results = retriever.search(query_text="Which people work at Neo4j?")

ToolsRetriever (LLM-routed multi-retriever)

from neo4j_graphrag.retrievers import ToolsRetriever

tools_retriever = ToolsRetriever(
    llm=llm,
    retrievers=[vector_retriever, text2cypher_retriever],
)
# LLM decides which retriever(s) to invoke per query

# Convert any retriever to a standalone Tool:
tool = vector_retriever.convert_to_tool()

Filters (pre-filter before vector search)

results = retriever.search(
    query_text="quarterly earnings",
    top_k=5,
    filters={
        "date": {"$gte": "2024-01-01"},
        "source": {"$eq": "10-K"},
    },
)
# Operators: $eq  $ne  $lt  $lte  $gt  $gte  $between  $in  $like  $ilike

query_params (parameterized retrieval_query)

retrieval_query = """
MATCH (node)<-[:HAS_CHUNK]-(a:Article)-[:MENTIONS]->(org:Organization {name: $entity_name})
RETURN node.text, a.title, score
"""

# Pass via retriever.search directly:
results = retriever.search(
    query_text="What happened at Apple?",
    top_k=10,
    query_params={"entity_name": "Apple"},
)

# Or via GraphRAG.search:
response = rag.search(
    query_text="What happened at Apple?",
    retriever_config={"top_k": 10, "query_params": {"entity_name": "Apple"}},
)

Cypher 25 SEARCH Clause (v1.16.0, Neo4j 2026.x+)

# Enable SEARCH clause syntax in vector/hybrid retrievers (requires Neo4j 2026+)
retriever = VectorRetriever(
    driver=driver,
    index_name="chunk_embedding",
    embedder=embedder,
    use_search_clause=True,
)

Since v1.19, the vector and vector-Cypher retrievers automatically prefix SEARCH queries with CYPHER 25 and fall back to the procedure-based vector search when SEARCH is unsupported or fails.


Component Imports (v1.19 — breaking, preparing 2.0)

All components moved out of the experimental namespace. Old imports still work but emit a DeprecationWarning and will be removed in 2.0:

# v1.19+ — preferred
from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter

# deprecated (removed in 2.0)
from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter

# SimpleKGPipeline did NOT move — only valid path:
from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline

neo4j_graphrag.pipeline (v1.21+) = new lazy dataflow DSL (Pipeline, LocalInterpreter, Sink), unrelated to the experimental task-graph Pipeline behind SimpleKGPipeline. neo4j_graphrag.pipeline.kg_builder does not exist → ModuleNotFoundError.

Also since v1.19: Component / RunContext / TaskProgressNotifierProtocol live in neo4j_graphrag.components.base, and malformed components raise ComponentDefinitionError (no longer PipelineDefinitionError).


Dataflow Pipeline DSL + Observers (v1.21)

Lazy neo4j_graphrag.pipeline.Pipeline + LocalInterpreter(observers=[...]); TextSplitter.iter_chunks(). Full API → references/pipeline-dsl.md.


ORDER BY on Cypher Retrievers (v1.16.0)

results = retriever.search(
    query_text="...",
    top_k=10,
    order_by="score DESC",
)

If neo4j_schema=None: retriever fetches schema automatically. For large schemas, pass a trimmed string to reduce LLM prompt size.

Destructive-query guard [v1.16+]: Text2CypherRetriever runs EXPLAIN on the generated Cypher before execution and rejects queries that produce writes (CREATE, MERGE, DELETE, SET, REMOVE, etc.). LLM-generated writes are never executed against the graph.


Custom Prompt Template

from neo4j_graphrag.generation.prompts import RagTemplate

template = RagTemplate(
    template="""Answer using ONLY the context below.
Context: {context}
Question: {query_text}
Answer:""",
    expected_inputs=["context", "query_text"],
)

rag = GraphRAG(retriever=retriever, llm=llm, prompt_template=template)

return_context and response_fallback

response = rag.search(
    query_text="...",
    retriever_config={"top_k": 5},
    return_context=True,                        # include raw retrieved chunks
    response_fallback="No relevant context.",   # skip LLM call if retriever returns nothing
)
print(response.answer)
print(response.retriever_result)    # RawSearchResult when return_context=True

Message History (multi-turn)

from neo4j_graphrag.message_history import InMemoryMessageHistory

history = InMemoryMessageHistory()
r1 = rag.search(query_text="Who is Alice?", message_history=history)
r2 = rag.search(query_text="Where does she work?", message_history=history)

External Retrievers, LLM + Embedder Providers

  • Weaviate / Pinecone / Qdrant constructors → references/retrievers.md
  • LLM classes (OpenAILLM, AnthropicLLM, GeminiLLM, VertexAILLM, BedrockLLM, …), base_url, token usage, close(); embedder classes + dims → references/providers.md

Index Setup

from neo4j_graphrag.indexes import create_vector_index

# Vector index — adjust dimensions to match your embedding model
create_vector_index(
    driver,
    name="chunk_embedding",
    label="Chunk",
    embedding_property="embedding",
    dimensions=1536,
    similarity_fn="cosine",       # or "euclidean"
)

# Fulltext index (run as Cypher)
# CREATE FULLTEXT INDEX chunk_fulltext IF NOT EXISTS
#   FOR (c:Chunk) ON EACH [c.text]

Schema Inspection

from neo4j_graphrag.schema import get_schema, get_structured_schema

schema_str = get_schema(driver, sample=1000)           # human-readable string
schema_dict = get_structured_schema(driver, sample=1000)  # dict with labels/rels/props

Common Errors

ErrorCauseFix
ModuleNotFoundError: neo4j_genaiOld package namepip uninstall neo4j-genai && pip install neo4j-graphrag
retrieval_query returns 0 rowsMissing MATCH or wrong rel directionEXPLAIN the fragment; check CALL db.schema.visualization()
KeyError: 'score' in resultsretrieval_query RETURN missing scoreAdd score to every retrieval_query RETURN clause
score variable not foundscore re-declared in retrieval_queryDo not re-declare score — it is auto-injected
Text2CypherRetrievalErrorLLM generated a write statementExpected security behavior (v1.16.0+); refine prompt or schema
TypeError: coroutineMissing await / asyncio.run()Wrap async calls: asyncio.run(pipeline.run_async(...))
Empty results from HybridRetrieverFulltext index not ONLINESHOW INDEXES YIELD name, state WHERE state <> 'ONLINE'
VectorCypherRetriever + filters raises "requires: node_label, embedding_node_property, …" (v1.19 name-mismatch bug)_fetch_index_infos sets self._embedding_node_property, constructor sets _node_embedding_propertyShim after construction: r._node_embedding_property = r._embedding_node_property or "embedding"; append filter props to r._filterable_properties
Embedding dimension mismatchIndex dims ≠ model dimsRecreate index with correct dimensions= value

Verification Checklist

  • neo4j-graphrag (not neo4j-genai) installed; neo4j >= 5.17.0 driver
  • Vector index ONLINE before ingesting embeddings or running retriever
  • Fulltext index ONLINE if using Hybrid variants
  • Embedding dims in create_vector_index match the embedder output
  • retrieval_query returns node and score in RETURN (not re-declared)
  • query_params passed via retriever_config on rag.search() (not on retriever constructor)
  • API keys in env vars; never hardcoded
  • llm.close() called when done to release resources

References

Load on demand:

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/neo4j-contrib/neo4j-skills/neo4j-graphrag-skill">View neo4j-graphrag-skill on skillZs</a>