Skip to content

GNN Routing Example

Use graph neural networks for intelligent routing.

Setup

from gmas.core import AgentProfile
from gmas.builder import build_property_graph
from gmas.execution import MACPRunner, create_openai_caller
import torch
import torch.nn.functional as F
from torch_geometric.nn import GATConv

Create Graph

agents = [
    AgentProfile(agent_id=f"agent_{i}", display_name=f"Agent {i}")
    for i in range(5)
]

graph = build_property_graph(
    agents,
    workflow_edges=[
        ("agent_0", "agent_1"),
        ("agent_0", "agent_2"),
        ("agent_1", "agent_3"),
        ("agent_2", "agent_3"),
        ("agent_3", "agent_4"),
    ],
    query="Example query",
)

Convert to PyG

pyg_data = graph.to_pyg_data()
print(pyg_data)
# Data(x=[6, 768], edge_index=[2, 10])  # 5 agents + 1 task node

Define GNN Router

class GNNRouter(torch.nn.Module):
    def __init__(self, in_channels: int = 768, hidden_channels: int = 128):
        super().__init__()
        self.conv1 = GATConv(in_channels, hidden_channels, heads=4)
        self.conv2 = GATConv(hidden_channels * 4, hidden_channels, heads=1)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index).relu()
        x = self.conv2(x, edge_index)
        return x

    def predict_adjacency(self, x, edge_index, num_nodes: int) -> torch.Tensor:
        """Compute pairwise agent similarity as new adjacency."""
        node_embs = self.forward(x, edge_index)
        # Remove task node (first row/col) for agent-only matrix
        agent_embs = node_embs[1:]  # skip task node
        scores = torch.mm(agent_embs, agent_embs.T)
        return torch.sigmoid(scores)

model = GNNRouter()

Update Graph with GNN Predictions

# Generate new adjacency from GNN
num_agents = len(agents)
new_adjacency = model.predict_adjacency(
    pyg_data.x,
    pyg_data.edge_index,
    num_nodes=num_agents,
)

# Optional: create score and probability matrices
scores = new_adjacency.clone()
probabilities = F.softmax(new_adjacency.flatten(), dim=0).reshape(new_adjacency.shape)

# Update the graph's routing
graph.update_communication(
    A_com=new_adjacency,
    s_tilde=scores,
    p_matrix=probabilities,
)

print(f"New adjacency matrix:\n{graph.A_com}")

Execute with GNN-Routed Graph

# Define an LLM caller
def llm_caller(prompt: str) -> str:
    # Your LLM API call here
    return "response"

runner = MACPRunner(llm_caller=llm_caller)
result = runner.run_round(graph)

print(f"Execution order: {result.execution_order}")
print(f"Final answer: {result.final_answer}")

Complete Pipeline

Putting it all together:

# 1. Create agents and graph
agents = [
    AgentProfile(agent_id=f"agent_{i}", display_name=f"Agent {i}")
    for i in range(5)
]
graph = build_property_graph(
    agents,
    workflow_edges=[
        ("agent_0", "agent_1"),
        ("agent_0", "agent_2"),
        ("agent_1", "agent_3"),
        ("agent_2", "agent_3"),
        ("agent_3", "agent_4"),
    ],
    query="Analyze the benefits of renewable energy",
)

# 2. Convert to PyG
pyg_data = graph.to_pyg_data()

# 3. Run GNN to get new routing
model = GNNRouter()
new_adjacency = model.predict_adjacency(
    pyg_data.x, pyg_data.edge_index, num_nodes=len(agents)
)

# 4. Update graph
graph.update_communication(A_com=new_adjacency)

# 5. Execute
runner = MACPRunner(llm_caller=llm_caller)
result = runner.run_round(graph)
print(result.final_answer)