GraphRAG implementation patterns for hybrid search, Text2Cypher, and agentic retrieval. Use when implementing RAG workflows with Neo4j.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: graphrag-patterns
description: GraphRAG implementation patterns for hybrid search, Text2Cypher, and agentic retrieval. Use when implementing RAG workflows with Neo4j.
allowed-tools: Read, Grep, Glob, Edit, Write
---
# GraphRAG Patterns
## Hybrid Search (Vector + Keyword)
Combine vector similarity with full-text search for better recall:
```python
from langchain_neo4j import Neo4jVector
def create_hybrid_retriever(driver, embeddings):
return Neo4jVector.from_existing_graph(
embeddings,
driver=driver,
index_name="article_embeddings",
keyword_index_name="article_fulltext",
search_type="hybrid", # Combines vector + keyword
node_label="Article",
text_node_properties=["content", "summary"],
embedding_node_property="embedding",
)
```
## Text2Cypher with Few-Shot Examples
Always provide examples for better query generation:
```python
FEW_SHOT_EXAMPLES = [
{
"question": "What articles discuss requirements traceability?",
"cypher": '''
MATCH (a:Article)
WHERE a.content CONTAINS 'traceability'
RETURN a.title, a.summary
LIMIT 10
'''
},
{
"question": "Which chapters have the most articles?",
"cypher": '''
MATCH (c:Chapter)-[:CONTAINS]->(a:Article)
RETURN c.title, count(a) as article_count
ORDER BY article_count DESC
'''
},
]
from langchain_neo4j import GraphCypherQAChain
chain = GraphCypherQAChain.from_llm(
llm=llm,
graph=graph,
cypher_prompt=CYPHER_PROMPT,
example_selector=SemanticSimilarityExampleSelector.from_examples(
FEW_SHOT_EXAMPLES,
embeddings,
k=3,
),
validate_cypher=True,
)
```
## Agentic Router Pattern
Route queries to the best retrieval strategy:
```python
from langchain_core.prompts import ChatPromptTemplate
ROUTER_PROMPT = ChatPromptTemplate.from_template('''
Classify the query into one of these retrieval strategies:
- VECTOR: Semantic similarity search (concepts, topics, "similar to")
- CYPHER: Structured queries (counts, relationships, specific filters)
- HYBRID: Complex queries needing both approaches
Query: {query}
Strategy:''')
async def route_query(query: str, llm) -> str:
response = await llm.ainvoke(ROUTER_PROMPT.format(query=query))
return response.content.strip().upper()
```
## Graph-Enriched Retrieval
Augment vector results with graph context:
```python
async def graph_enriched_search(driver, query: str, embeddings) -> list[dict]:
# Step 1: Vector search for relevant articles
vector_results = await vector_search(driver, query, embeddings, limit=5)
# Step 2: Expand with graph traversal
article_ids = [r["id"] for r in vector_results]
enrichment_query = '''
MATCH (a:Article) WHERE a.id IN $ids
OPTIONAL MATCH (a)<-[:CONTAINS]-(c:Chapter)
OPTIONAL MATCH (a)-[:RELATED_TO]->(related:Article)
RETURN a, c.title as chapter, collect(DISTINCT related.title) as related_articles
'''
enriched = await execute_read_query(driver, enrichment_query, {"ids": article_ids})
return enriched
```
## RAGAS Evaluation Metrics
Evaluate retrieval quality:
```python
from ragas.metrics import (
context_precision,
context_recall,
faithfulness,
answer_relevancy,
)
from ragas import evaluate
def evaluate_retrieval(questions, ground_truths, contexts, answers):
dataset = Dataset.from_dict({
"question": questions,
"ground_truth": ground_truths,
"contexts": contexts,
"answer": answers,
})
results = evaluate(
dataset,
metrics=[
context_precision,
context_recall,
faithfulness,
answer_relevancy,
],
)
return results
```
## Stepback Prompting
For complex queries, generate a broader question first:
```python
STEPBACK_PROMPT = '''
Given a specific question, generate a more general "stepback" question
that would help gather broader context before answering the specific question.
Specific question: {question}
Stepback question:'''
async def stepback_retrieval(query: str, retriever, llm):
# Generate stepback question
stepback_q = await llm.ainvoke(STEPBACK_PROMPT.format(question=query))
# Retrieve for both questions
specific_docs = await retriever.ainvoke(query)
stepback_docs = await retriever.ainvoke(stepback_q.content)
# Combine and deduplicate
all_docs = {doc.page_content: doc for doc in specific_docs + stepback_docs}
return list(all_docs.values())
```
No comments yet. Be the first to comment!