# Agentic AI: Reasoning Graphs on a Shared Data Layer

> Agents That Plan. Not Prompt.

On Memgraph ([memgraph.com/agentic-ai](https://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

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**: https://docs.docker.com/get-docker/

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](https://github.com/memgraph/memgraph-platform/tree/main/code-examples)
repository.

macOS / Linux:

```bash
./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:

```powershell
.\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:

```powershell
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:

```bash
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:

```cypher
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:

```cypher
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:

```cypher
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:

```cypher
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:

```cypher
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:

```cypher
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:

```cypher
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`):

```cypher
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:

```bash
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`](https://github.com/memgraph/memgraph-platform/blob/main/code-examples/agentic-graphrag.sh)
for a working MCP setup):

```json
{
  "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

```bash
./agentic-ai.sh clean          # .\agentic-ai.ps1 clean  on Windows
# and, if you started Lab:
docker rm -f memgql-lab
```
