Objective
Plain vector RAG retrieves one relevant passage, so it stumbles on questions that need to connect several facts: "which feature does the engineer who owns the billing service also work on?" That's a multi-hop question — it needs the relationships between entities, not just similar text. GraphRAG answers it by pairing semantic retrieval (find the right starting entity by meaning) with a graph walk (follow the edges). Here you'll build both surfaces in one engine: an embedded lookup table to find the entry point, and a Cypher knowledge graph to hop across. The same pattern works from any framework or a voice agent — see Use it from your agent at the end.
Step 1: Create a semantic entry-point index (SQL + vectors)
A small table maps natural-language descriptions to graph node names, so the agent can find where to start the walk by meaning.
CREATE TABLE IF NOT EXISTS recipe_graphrag_index (
node_id INTEGER PRIMARY KEY,
node_name TEXT, -- matches a node name in the graph
node_kind TEXT, -- 'person' | 'service' | 'feature'
blurb TEXT, -- description used for semantic match
embedding VECTOR(384)
);
Step 2: Seed the entry-point index
Describe each entity in plain language so a loosely-worded question can still find it.
INSERT INTO recipe_graphrag_index (node_id, node_name, node_kind, blurb) VALUES
(1,'Priya','person','Priya is a backend engineer who owns the billing and payments service.'),
(2,'Marco','person','Marco is a frontend engineer focused on the checkout user interface.'),
(3,'BillingService','service','The billing service handles invoices, subscriptions, and payment processing.'),
(4,'CheckoutUI','feature','The checkout UI is the page where customers enter payment details.'),
(5,'DunningFeature','feature','Dunning automatically retries failed payments and emails customers.');
Step 3: Embed the entry-point index
The embedding model runs in-database; this is how the agent maps a question to a starting node.
UPDATE recipe_graphrag_index SET embedding = EMBED(blurb);
Step 4: Find the starting node by meaning
Given "who handles failed payments?", retrieve the closest entity — the entry point for the graph walk.
SELECT node_name, node_kind, blurb,
COSINE_SIMILARITY(embedding, EMBED('who is responsible for charging customers and retrying failed payments?')) AS relevance
FROM recipe_graphrag_index
ORDER BY relevance DESC
LIMIT 2;
Step 5: Build the knowledge graph (Cypher)
Create the people, services, and features, and the edges between them — the structure RAG can't represent.
MERGE (priya:Person {name: 'Priya'})
MERGE (marco:Person {name: 'Marco'})
MERGE (billing:Service {name: 'BillingService'})
MERGE (checkout:Feature {name: 'CheckoutUI'})
MERGE (dunning:Feature {name: 'DunningFeature'})
MERGE (priya)-[:OWNS]->(billing)
MERGE (marco)-[:OWNS]->(checkout)
MERGE (billing)-[:HAS_FEATURE]->(dunning)
MERGE (billing)-[:INTEGRATES_WITH]->(checkout)
MERGE (marco)-[:CONTRIBUTES_TO]->(dunning);
Step 6: Answer a multi-hop question with a graph walk
Starting from the node we found semantically, walk OWNS → HAS_FEATURE to reach the answer two hops away.
MATCH (p:Person {name: 'Priya'})-[:OWNS]->(s:Service)-[:HAS_FEATURE]->(f:Feature)
RETURN p.name AS owner, s.name AS service, f.name AS feature;
Step 7: Hop further — who else contributes to that feature?
A three-entity question that vector RAG can't answer: find everyone connected to the feature Priya's service owns.
MATCH (s:Service {name: 'BillingService'})-[:HAS_FEATURE]->(f:Feature)<-[:CONTRIBUTES_TO]-(other:Person)
RETURN f.name AS feature, other.name AS contributor;
Cleanup (Optional)
DROP TABLE IF EXISTS recipe_graphrag_index;
MATCH (n:Person) DETACH DELETE n;
MATCH (n:Service) DETACH DELETE n;
MATCH (n:Feature) DETACH DELETE n;
Expected Outcomes
- Step 4 maps "who retries failed payments?" to Priya and DunningFeature — the semantic entry points.
- Step 6 returns Priya → BillingService → DunningFeature: a two-hop answer that connects an owner to a feature through a service.
- Step 7 finds Marco as a contributor to DunningFeature even though he doesn't own the billing service — a relationship pure vector RAG would miss entirely.
You now have GraphRAG: semantic retrieval picks the entry point, the graph walk supplies the connected, multi-hop answer.
Use it from your agent (framework-agnostic — this is the whole point)
GraphRAG is just a vector index + a graph, both in one engine, so any agent uses it with no framework lock-in:
- REST / SDK —
POST /v1/query/execute(any language), or@synapcores/sdkclient.executeQuery(...). Your agent runs the Step-4 SQL to pick the entry node, then sends the Step-6/7 Cypher to walk the graph and assemble the answer. - MCP (native, on by default) — point any MCP client (Claude Code, Cursor, a custom loop, a voice runtime) at
ws://<your-instance>/mcp?token=<jwt>(JWT from onePOST /v1/auth/login→access_token). Thequerytool runs the semantic lookup; theexecutetool runs Cypher for the graph walk — multi-hop reasoning as two tool calls, no graph framework required. - Any framework — OpenClaw, LangChain / LlamaIndex graph retrievers, a custom loop, or a voice agent all use the same vector index + graph. The database is the brain; the framework is swappable.
Key Concepts Learned
- Vector RAG finds a passage; GraphRAG finds connected facts by walking edges.
- Use embeddings to pick the entry node by meaning, then Cypher to hop across relationships — one engine, two surfaces.
- Multi-hop patterns (
OWNS → HAS_FEATURE, contributor-of-a-feature) answer questions vector search structurally cannot. - Because it's plain data ops (SQL + Cypher / REST / MCP), GraphRAG works for any agent — the agent-agnostic backend pattern this cluster builds on.