Multi AI-Agent systems represent a significant advancement in software development, characterized by two fundamental aspects:

The dynamic nature of these systems presents a unique challenge: understanding the flow of logic becomes increasingly complex as the system scales. A single query might trigger no tool calls, while another could initiate a cascade of nested interactions where AI agents themselves trigger additional tool calls. This complexity makes system behavior difficult to track and debug.

To address this challenge, I'm introducing AgentGraph, an open-source library that seamlessly integrates with Python or Node.js backends. This tool captures and visualizes LLM interactions and tool calls in real-time, presenting them as an interactive graph that provides clear visibility into system behavior.

Visualizing Agent Interactions

Let's examine a practical example: a database query agent with access to two tools:

  1. SQLAgent: Converts natural language queries into SQL
  2. DatabaseAgent: Executes SQL queries and returns results

Here's how the agent graph visualizes different types of interactions:

Query 1: "Hi there!"

A simple greeting that doesn't require database access results in no tool calls:

Simple greeting with no tool calls

Query 2: "How many users do I have?"

This query triggers a sequence of tool calls:

  1. SQLAgent converts the query to SQL
  2. DatabaseAgent executes the query

The main agent's graph shows:

Main agent graph

The second bubble contains the user input (also indicating that the LLM used tools), followed by the final response bubble. Clicking the second bubble reveals the tool calls:

Tool calls

The LLM first calls SQLAgent, then DatabaseAgent. Clicking on the SQLAgent row shows its subgraph:

SQLAgent subgraph

The subgraph displays the tool input (orange box), output (green box), and complete LLM chat history. While this example shows a simple tool, the visualization scales to handle complex nested tool calls. The DatabaseAgent's subgraph shows:

DatabaseAgent subgraph Since this tool doesn't use an LLM, it simply displays the input and output.

Integration Guide

Let's walk through implementing AgentGraph in a Node.js backend. You can find the complete example code here. While we'll focus on Node.js, the implementation is similar for Python backends.

To get started, install the AgentGraph package:

1npm install @trythisapp/agentgraph

Setting Up the Main Agent

The core of the integration involves wrapping your LLM calls with AgentGraph's callLLMWithToolHandling function. Here's how to set up the main agent:

1import { callLLMWithToolHandling, clearSessionId } from "@trythisapp/agentgraph";
2import { v4 as uuidv4 } from 'uuid';
3
4async function mainAgent(userInput: string, sessionId: string) {
5    let input: OpenAI.Responses.ResponseInput = [{
6        role: "system",
7        content: `You are a helpful assistant for querying a database...`
8    }, {
9        role: "user",
10        content: userInput
11    }];
12
13    try {
14        let response = await callLLMWithToolHandling(
15            "mainAgent",           // Agent name for visualization
16            sessionId,             // Unique session identifier
17            undefined,             // Tool ID (undefined for main agent)
18            async (inp) => {       // LLM call function
19                return await openaiClient.responses.create({
20                    model: "gpt-4.1",
21                    input: inp,
22                    tools: [/* tool definitions */],
23                });
24            },
25            input,                 // Input messages
26            [/* tool implementations */]
27        );
28        
29        console.log(response.output_text);
30    } finally {
31        clearSessionId(sessionId);  // Clean up session data
32    }
33}

Session Management

Each interaction requires a unique session ID to track the conversation flow:

1let sessionId = uuidv4();
2console.log(`Session ID: ${sessionId}. File is saved in ./agentgraph_output/${sessionId}.json`);

The session ID serves two purposes:

  1. Visualization: Groups related interactions in the same graph
  2. File Output: Creates a JSON file with the complete interaction trace

Always call clearSessionId(sessionId) when the session ends to clean up memory.

Defining Tools

Tools are defined using OpenAI's function calling format within the LLM call:

1tools: [{
2    type: "function",
3    strict: true,
4    name: "SQLAgent",
5    description: "Use this tool when you need to convert the natural language query into a SQL query",
6    parameters: {
7        type: "object",
8        properties: {
9            query: {
10                type: "string",
11                description: "The natural language query to convert into a SQL query"
12            }
13        },
14        required: ["query"],
15        additionalProperties: false
16    }
17}, {
18    type: "function",
19    strict: true,
20    name: "databaseAgent",
21    description: "Use this tool when you need to execute the SQL query and return the results",
22    parameters: {
23        type: "object",
24        properties: {
25            query: {
26                type: "string",
27                description: "The SQL query to execute"
28            }
29        },
30        required: ["query"],
31        additionalProperties: false
32    }
33}]

Implementing Tool Handlers

The final parameter of callLLMWithToolHandling is an array of tool implementations:

1[{
2    toolName: "SQLAgent",
3    impl: async ({ query }: { query: string }, toolId: string) => {
4        return runSQLAgent(sessionId, toolId, query);
5    }
6}, {
7    toolName: "databaseAgent", 
8    impl: async ({ query }: { query: string }) => {
9        return runDatabaseAgent(query);
10    }
11}]

Each tool implementation receives:

Creating Nested Agents

For tools that use LLMs internally (like SQLAgent), you create nested agents by calling callLLMWithToolHandling again:

1async function runSQLAgent(sessionId: string, toolId: string, query: string): Promise<string> {
2    let input: OpenAI.Responses.ResponseInput = [{
3        role: "system",
4        content: `You are an expert SQLite SQL query generator...`
5    }, {
6        role: "user",
7        content: query
8    }];
9    
10    let response = await callLLMWithToolHandling(
11        "SQLAgent",        // Nested agent name
12        sessionId,         // Same session ID
13        toolId,            // Tool ID from parent call
14        async (inp) => {
15            return await openaiClient.responses.create({
16                model: "gpt-4.1",
17                input: inp,
18                text: {
19                    format: {
20                        type: "json_schema",
21                        name: "sqlQuery",
22                        schema: {/* JSON schema */}
23                    }
24                }
25            });
26        },
27        input,
28        []                 // No tools for this agent
29    );
30
31    return response.output_text;
32}

Notice how the nested agent:

Simple Tool Implementation

For tools that don't use LLMs (like databaseAgent), the implementation is straightforward:

1async function runDatabaseAgent(query: string): Promise<string> {
2    return queryDatabase(query);  // Direct function call
3}

Viewing the Results

After running your agent, AgentGraph seamlessly handles the complete interaction flow:

  1. Automatic Tool Orchestration: When the LLM decides to invoke a tool, callLLMWithToolHandling automatically executes the corresponding tool implementation and feeds the result back to the LLM for further processing.

  2. Complete Trace Capture: Every interaction, tool call, and response is captured and saved to ./agentgraph_output/${sessionId}.json, creating a comprehensive execution trace.

  3. Interactive Visualization: The generated JSON file can be visualized using the AgentGraph visualizer, which renders your agent interactions as an interactive graph.

The visualization provides:

This integration approach provides complete visibility into your multi-agent system without requiring significant changes to your existing code structure.

Take away

As AI agent systems become increasingly sophisticated, the ability to understand and debug their behavior becomes crucial for reliable deployment. AgentGraph addresses this challenge by providing real-time visualization of multi-agent interactions, making complex decision flows transparent and debuggable.

Key benefits of using AgentGraph include:

Whether you're building simple tool-calling agents or complex multi-agent orchestration systems, AgentGraph provides the observability you need to understand, debug, and optimize your AI workflows.

Check out the AgentGraph repository and give it a ⭐ if you find it useful! Your support helps me continue developing tools that make AI development more transparent and accessible.