Use casesAgentic AI

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:

OperationWhat it answers
Weighted traversalEvaluate multi-step plans without LLM calls
Shortest pathMost efficient route to a goal
CentralityWhich intermediate states are critical
Community detectionWhich 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

  1. Start the shared data layer: Memgraph + Postgres, federated by MemGQL.
  2. Seed the reasoning graph (a customer-support agent’s plan space).
  3. Read shared context through the one MemGQL endpoint (multi-agent coordination).
  4. 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 created

Windows (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 created

Or 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 | iex

This 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.0

MemGQL 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;
planexpected_value
Ticket received → Assess severity → Auto-resolve → Resolved0.8
Ticket received → Assess severity → Escalate to human → Resolved0.513
Ticket received → Assess severity → Request more info → Assess severity → Auto-resolve → Resolved0.149
Ticket received → Assess severity → Request more info → Assess severity → Escalate to human → Resolved0.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:3000

Give 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