Agentic AI: Reasoning Graphs on a Shared Data Layer
Agents That Plan. Not Prompt.
On Memgraph (memgraph.com/agentic-ai) an agent models its problem as a reasoning graph and plans by traversal instead of by prompting:
- nodes = states / decision points
- edges = available actions
- properties = scores (expected value, success rate, feasibility)
Four graph operations replace LLM guesswork, and the path an agent takes is an inspectable, auditable trace that can be scored against alternatives:
| Operation | What it answers |
|---|---|
| Weighted traversal | Evaluate multi-step plans without LLM calls |
| Shortest path | Most efficient route to a goal |
| Centrality | Which intermediate states are critical |
| Community detection | Which sub-tasks can run in parallel |
The page also stresses multi-agent coordination over shared state. That shared layer is Memgraph Zero / MemGQL: a federated GQL engine that puts one Bolt + GQL endpoint in front of many backends, so a fleet of agents reaches the same data with no ETL. This example federates two sources:
- Memgraph hosts the reasoning graph the agents plan over (plus MAGE algorithms).
- PostgreSQL hosts customer records the agents pull as shared context.
High-level Plan
- Start the shared data layer: Memgraph + Postgres, federated by MemGQL.
- Seed the reasoning graph (a customer-support agent’s plan space).
- Read shared context through the one MemGQL endpoint (multi-agent coordination).
- Plan over the reasoning graph with the four operations, and audit the choice.
What You Need
Docker only. No API keys. Uses the Memgraph ecosystem plus stock postgres
(PostgreSQL is one of MemGQL’s supported connectors).
Run It
The scripts live in the memgraph/memgraph-platform repository.
macOS / Linux:
./agentic-ai.sh # bring up the shared layer + reasoning graph, then plan
./agentic-ai.sh clean # stop and remove everything the script createdWindows (PowerShell 5.1 or 7+), same steps, same output:
.\agentic-ai.ps1 # bring up the shared layer + reasoning graph, then plan
.\agentic-ai.ps1 clean # stop and remove everything the script createdOr run it straight from the web, without downloading it first:
iwr -UseBasicParsing https://raw.githubusercontent.com/memgraph/memgraph-platform/main/code-examples/agentic-ai.ps1 | iexThis does the same as the bare form above. clean needs the downloaded file, but
the script also prints the equivalent docker commands when you run it this way.
If Windows blocks the script, allow local scripts for the session first:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass. The script
bind-mounts two generated files into containers, so the drive it lives on (your
current directory, when run from the web) must be shared with Docker Desktop
(Settings → Resources → File sharing; C:\Users is shared by default).
Step-by-step
1. Start the shared data layer
Demo-scoped names (zero-demo-*) avoid clobbering your own containers. Only
MemGQL’s port (7688) is published; the backends are reached internally, so
agents talk to a single endpoint:
docker network create zero-demo-net
docker run -d --name zero-demo-memgraph --network zero-demo-net \
memgraph/memgraph-mage:3.12.0 --schema-info-enabled=True --log-level=TRACE --also-log-to-stderr
docker run -d --name zero-demo-postgres --network zero-demo-net \
-e POSTGRES_PASSWORD=postgres \
-v "$PWD/.memgql-work/init.sql":/docker-entrypoint-initdb.d/init.sql \
postgres:18
docker run -d --name zero-demo-memgql --network zero-demo-net --stop-timeout 2 -p 7688:7688 \
--env CONNECTOR_TYPE=multi \
--env BOLT_LISTEN_ADDR=0.0.0.0:7688 \
-v "$PWD/.memgql-work/mapping.json":/data/mapping.json \
memgraph/memgql:0.7.0MemGQL learns about each backend and opens a named connection to it:
ADD CONNECTOR mg TYPE memgraph URI 'zero-demo-memgraph:7687' GRAPH memgraph;
CONNECT mg AS mg_conn;
ADD MAPPING social FROM '/data/mapping.json';
ADD CONNECTOR pg TYPE postgres URI 'host=zero-demo-postgres user=postgres password=postgres dbname=postgres' MAPPING social;
CONNECT pg AS pg_conn;2. Seed the reasoning graph
States are nodes, actions are scored edges. The score is the expected probability
that the action moves the ticket toward resolution. Six states and seven actions,
including one loop (Request more info sends the ticket back to Assess severity),
so plans can differ in length as well as score:
MERGE (s0:State {name:"Ticket received"});
MERGE (s1:State {name:"Assess severity"});
MERGE (a:State {name:"Auto-resolve"});
MERGE (e:State {name:"Escalate to human"});
MERGE (r:State {name:"Request more info"});
MERGE (d:State {name:"Resolved"});
MATCH (s0:State{name:"Ticket received"}),(s1:State{name:"Assess severity"}) MERGE (s0)-[:ACTION {name:"triage", score:1.0}]->(s1);
MATCH (s1:State{name:"Assess severity"}),(a:State{name:"Auto-resolve"}) MERGE (s1)-[:ACTION {name:"auto_resolve", score:0.87}]->(a);
MATCH (s1:State{name:"Assess severity"}),(e:State{name:"Escalate to human"}) MERGE (s1)-[:ACTION {name:"escalate", score:0.54}]->(e);
MATCH (s1:State{name:"Assess severity"}),(r:State{name:"Request more info"}) MERGE (s1)-[:ACTION {name:"request_info", score:0.31}]->(r);
MATCH (a:State{name:"Auto-resolve"}),(d:State{name:"Resolved"}) MERGE (a)-[:ACTION {name:"close", score:0.92}]->(d);
MATCH (e:State{name:"Escalate to human"}),(d:State{name:"Resolved"}) MERGE (e)-[:ACTION {name:"human_fix", score:0.95}]->(d);
MATCH (r:State{name:"Request more info"}),(s1:State{name:"Assess severity"}) MERGE (r)-[:ACTION {name:"reassess", score:0.60}]->(s1);3. Read shared context through MemGQL
Every agent reads the same federated layer. An agent fetches customer context from Postgres, through MemGQL, with no copy:
USE CONNECTION pg_conn
MATCH (c:Customer)-[:WORKS_AT]->(co:Company)
WHERE c.tier = 'enterprise'
RETURN c.name AS customer, c.tier AS tier, co.name AS company;4. Plan over the reasoning graph
These run natively in Memgraph (MAGE and weighted shortest path).
Weighted traversal ranks whole plans by expected value, no LLM in the loop:
MATCH path=(:State {name:"Ticket received"})-[rels:ACTION *1..6]->(:State {name:"Resolved"})
RETURN [n IN nodes(path) | n.name] AS plan,
round(reduce(p=1.0, r IN rels | p * r.score) * 1000) / 1000 AS expected_value
ORDER BY expected_value DESC LIMIT 4;| plan | expected_value |
|---|---|
| Ticket received → Assess severity → Auto-resolve → Resolved | 0.8 |
| Ticket received → Assess severity → Escalate to human → Resolved | 0.513 |
| Ticket received → Assess severity → Request more info → Assess severity → Auto-resolve → Resolved | 0.149 |
| Ticket received → Assess severity → Request more info → Assess severity → Escalate to human → Resolved | 0.095 |
The top result is the chosen path; the rows below it are the scored
alternatives, including the longer plans that loop through Request more info. Narrowing the same query to the chosen path and its runner-up is the
audit trail the page describes, an inspectable trace of why this plan won:
MATCH path=(:State {name:"Ticket received"})-[rels:ACTION *1..6]->(:State {name:"Resolved"})
WITH [n IN nodes(path) | n.name] AS plan, reduce(p=1.0, r IN rels | p * r.score) AS ev
ORDER BY ev DESC LIMIT 2
RETURN plan, round(ev * 1000) / 1000 AS expected_value;Shortest path finds the most efficient route to the goal (cost = 1 - score).
It agrees with the weighted traversal: Ticket received → Assess severity → Auto-resolve → Resolved at a total cost of 0.21:
MATCH path=(:State {name:"Ticket received"})-[:ACTION *WSHORTEST (e, n | 1.0 - e.score) total_cost]->(:State {name:"Resolved"})
RETURN [x IN nodes(path) | x.name] AS route, round(total_cost * 1000) / 1000 AS cost;Centrality flags the critical intermediate state. Here Assess severity
(0.35) is far ahead of Auto-resolve and Escalate to human (0.075 each),
because every plan, including the loop, passes through it:
CALL betweenness_centrality.get() YIELD node, betweenness_centrality
RETURN node.name AS state, round(betweenness_centrality * 1000) / 1000 AS centrality
ORDER BY centrality DESC LIMIT 5;Community detection groups sub-tasks a fleet of agents can take in parallel.
On this graph it separates the intake states (Ticket received, Assess severity, Request more info) from the resolution states (Auto-resolve,
Escalate to human, Resolved):
CALL community_detection.get() YIELD node, community_id
RETURN community_id, collect(node.name) AS states ORDER BY community_id;5. Explore the shared layer visually (optional)
Point Memgraph Lab at MemGQL’s endpoint, the same one every agent uses:
docker run -d --name memgql-lab --network zero-demo-net -p 3000:3000 \
-e QUICK_CONNECT_MG_HOST=zero-demo-memgql -e QUICK_CONNECT_MG_PORT=7688 \
memgraph/lab:3.12.0
# open http://localhost:3000Give a Fleet of Agents MCP Access
Run the Memgraph MCP server against MemGQL’s endpoint (bolt://localhost:7688) so
every agent shares the same layer through MCP (see
agentic-graphrag.sh
for a working MCP setup):
{
"mcpServers": {
"memgraph-zero": {
"url": "http://localhost:8000/mcp/"
}
}
}Notes (MemGQL Is Early)
- Native analytics run in Memgraph. MAGE algorithms and weighted shortest path execute in Memgraph itself; MemGQL federates pattern queries and pushes them down to each source.
- No auth yet: keep it local.
- Two data sources in MemGQL Community (unlimited in Enterprise).
Clean Up
./agentic-ai.sh clean # .\agentic-ai.ps1 clean on Windows
# and, if you started Lab:
docker rm -f memgql-lab