How to Build an AI Agent for IBM i
In this step-by-step tutorial, IBM AI specialists Adam Shedivy and Devansh Kumar show how to bring agentic AI from theory to practice
Editor’s note: This article is part of the “AI With IBM i” blog. View other articles here.
You’ve gained an appreciation for the transformative capabilities of AI agents and understand how they work. (If not, see our previous article.) Now, let’s walk through how to build an agent for IBM i.
As we mentioned before, the IBM i system is a command-driven interface. We can use SQL (and CL) as the common interface for building tools that interact with the system. When building an agent for IBM i there are three questions we need to answer:
- What problem are you trying to solve?
- What data do you have access to, and what tools can you build to interact with this data?
- How do you want your agent to behave or interact with your environment?
Let’s work through a concrete example to answer each of these questions.
Question 1: What Problem Are We Solving?
Imagine you’re a system administrator who needs to check system performance throughout the day. Instead of remembering specific SQL queries or navigating through system menus, you want to simply ask, “What’s the current system performance?” and get a comprehensive answer.
Our goal: Build an agent that can retrieve and analyze system performance data by understanding natural language questions and knowing which tools to use.
Question 2: What Data and Tools Do We Have?
This is where IBM i’s architecture shines. Thanks to SQL Services, virtually all system information is accessible through SQL. For performance monitoring, we can use services like:
-- Detailed information about current partition
SELECT * FROM TABLE(QSYS2.SYSTEM_STATUS(RESET_STATISTICS=>'YES',DETAILED_INFO=>'ALL')) X
-- Statistical info about CPU usage
SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO())
Building the Foundation: An SQL Execution Function
To let our agent execute these SQL statements, we need a Python function that can connect to IBM i and run queries. We’ll use Mapepire (https://mapepire-ibmi.github.io/), an open-source database connector for Db2 for i:
import os
from typing import Any, Dict, Optional
from mapepire_python import connect
from pep249 import QueryParameters
credentials = {
"host": os.getenv("IBMI_HOST"),
"user": os.getenv("IBMI_USER"),
"password": os.getenv("IBMI_PASSWORD"),
"port": os.getenv("IBMI_PORT"),
}
def run_sql_statement(
sql: str,
parameters: Optional[QueryParameters] = None,
creds: Dict[str, Any] = credentials,
) -> str:
"""Execute SQL statement and return formatted results
Args:
sql: SQL statement to execute
parameters: Optional parameters for prepared statements
creds: Database connection credentials
Returns:
Formatted string with SQL results
"""
with connect(creds) as conn:
with conn.execute(sql, parameters=parameters) as cur:
if cur.has_results:
result = cur.fetchall()
return str(result["data"])
else:
return "SQL executed successfully. No results returned."
The run_sql_statement function handles the connection management and returns results as a string that our agent can work with.
Converting SQL Into Agent Tools
Now here’s the key concept: We need to wrap each SQL capability in a “tool” that the agent can discover and use. Think of tools as functions with descriptions attached—the agent reads these descriptions to decide when to use each tool.
Here’s how we define our first tool for system status:
system_status = "SELECT * FROM TABLE(QSYS2.SYSTEM_STATUS(RESET_STATISTICS=>'YES',DETAILED_INFO=>'ALL')) X"
@tool(
name="Get System Status",
description="Retrieve overall system performance statistics",
)
def get_system_status() -> str:
"""Retrieve overall system performance statistics"""
return run_sql_statement(system_status)
The @tool decorator (provided by our agent framework) is doing important work here: it’s registering this function with the agent and providing metadata. When the agent sees a question about system performance, it can read the description “Retrieve overall system performance statistics” and decide if this tool is relevant.
Let’s add a second tool for system activity:
system_activity = "SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO())"
@tool(
name="Get System Activity",
description="Retrieve current system activity information",
)
def get_system_activity() -> str:
"""Retrieve current system activity information"""
return run_sql_statement(system_activity)
We now have two tools that expose specific IBM i capabilities to our agent. As you build more sophisticated agents, you can create dozens of tools—each one giving the agent access to different system services, from security auditing to job management to storage analysis.
Question 3: How Should Our Agent Behave?
Finally, we need to define the agent itself—the decision-making layer that will choose which tools to use and how to respond. We’ll use Agno, an open-source agent SDK, though there are many frameworks to choose from:
from agno.agent import Agent
from agno.models.anthropic import Claude
agent = Agent(
name="Performance Metrics Assistant",
model=Claude(id="claude-sonnet-4-20250514"),
tools=[
get_system_status,
get_system_activity,
],
instructions=dedent("""
You are an expert IBM i performance metrics assistant. Your role is to help users
retrieve and analyze performance-related data from the IBM i system using SQL queries.
When asked about system performance:
- Use the available tools to gather current data
- Explain the metrics in business-friendly terms
- Highlight any concerning values
"""),
markdown=True,
)
Let’s break down what’s happening:
- model: We’re using Claude Sonnet 4, but agents are model-agnostic—you could use GPT-4, Llama or any other LLM.
- tools: This is where we pass our SQL-backed tools. The agent can now “see” these capabilities.
- instructions: This is the agent’s behavior guide. It tells the agent its role, how to act and what approach to take
See it in action
Now for the exciting part, let’s see the agent work. When a user asks a question, here’s what happens:
# User asks a question
agent.print_response("What's the current CPU utilization and system performance?")
Behind the scenes:
- The agent receives the question.
- It reviews its available tools and their descriptions.
- It decides to call get_system_status() and get_system_activity().
- It receives the SQL results from both queries.
- It synthesizes the data into a natural language response.
The user gets back something like:
“Based on current system metrics, your CPU utilization is at 45% with 12 active jobs. System ASP is at 62% capacity. Performance is healthy with average response times under 2 seconds. Memory pool allocation is balanced across subsystems.”
No SQL knowledge required. The agent handled tool selection, data retrieval and interpretation automatically.
Taking It Further: From Retrieval to Action
Our example focused on data retrieval, but agents can also take actions. Here’s how you could extend this agent:
Adding an Email Tool:
from agno.agent import Agent
from agno.tools.email import EmailTools
from agno.models.anthropic import Claude
receiver_email = "<receiver_email>"
sender_email = "<sender_email>"
sender_name = "<sender_name>"
sender_passkey = "<sender_passkey>"
agent = Agent(
name="Performance Metrics Assistant",
model=Claude(id="claude-sonnet-4-20250514"),
tools=[
get_system_status,
get_system_activity,
EmailTools(
receiver_email=receiver_email,
sender_email=sender_email,
sender_name=sender_name,
sender_passkey=sender_passkey,
enable_email_user=True,
)
],
instructions=dedent("""
You are an expert IBM i performance metrics assistant. Your role is to help users
retrieve and analyze performance-related data from the IBM i system using SQL queries.
When asked about system performance:
- Use the available tools to gather current data
- Explain the metrics in business-friendly terms
- Highlight any concerning values
"""),
markdown=True,
)
This uses Agno’s Built in EmailTools Toolkit.
Adding a Database Update Tool:
@tool(
name="Log Performance Metrics",
description="Save performance metrics to the monitoring database",
)
def log_performance_metrics(cpu_usage: float, asp_usage: float) -> str:
"""Insert performance metrics into the monitoring table"""
sql = """
INSERT INTO SAMPLE.METRICS (TIMESTAMP, CPU_PCT, ASP_PCT)
VALUES (CURRENT_TIMESTAMP, ?, ?)
"""
return run_sql_statement(sql, parameters=[cpu_usage, asp_usage])
With these additional tools, you could ask your agent: “Check system performance and email me a report if CPU is over 80%”—and it would handle the entire workflow autonomously.
Complete Example
Here’s the full script ready to run:
import os
from textwrap import dedent
from typing import Any, Dict, Optional
from mapepire_python import connect
from pep249 import QueryParameters
from agno.agent import Agent
from agno.models.anthropic import Claude
from agno.tools import tool
# Database credentials
credentials = {
"host": os.getenv("IBMI_HOST"),
"user": os.getenv("IBMI_USER"),
"password": os.getenv("IBMI_PASSWORD"),
"port": os.getenv("IBMI_PORT"),
}
def run_sql_statement(
sql: str,
parameters: Optional[QueryParameters] = None,
creds: Dict[str, Any] = credentials,
) -> str:
"""Execute SQL statement and return formatted results"""
with connect(creds) as conn:
with conn.execute(sql, parameters=parameters) as cur:
if cur.has_results:
result = cur.fetchall()
return str(result["data"])
else:
return "SQL executed successfully. No results returned."
# Define SQL queries
system_status = "SELECT * FROM TABLE(QSYS2.SYSTEM_STATUS(RESET_STATISTICS=>'YES',DETAILED_INFO=>'ALL')) X"
system_activity = "SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO())"
# Define tools
@tool(
name="Get System Status",
description="Retrieve overall system performance statistics",
)
def get_system_status() -> str:
"""Retrieve overall system performance statistics"""
return run_sql_statement(system_status)
@tool(
name="Get System Activity",
description="Retrieve current system activity information",
)
def get_system_activity() -> str:
"""Retrieve current system activity information"""
return run_sql_statement(system_activity)
# Create the agent
agent = Agent(
name="Performance Metrics Assistant",
model=Claude(id="claude-sonnet-4-20250514"),
tools=[
get_system_status,
get_system_activity,
],
instructions=dedent("""
You are an expert IBM i performance metrics assistant. Your role is to help users
retrieve and analyze performance-related data from the IBM i system using SQL queries.
When asked about system performance:
- Use the available tools to gather current data
- Explain the metrics in business-friendly terms
- Highlight any concerning values
"""),
markdown=True,
)
# Use the agent
if __name__ == "__main__":
agent.print_response("What's the current CPU utilization and system performance?")
To run this example:
- Install dependencies: pip install mapepire-python agno anthropic
- Set environment variables: IBMI_HOST, IBMI_USER, IBMI_PASSWORD, IBMI_PORT, ANTHROPIC_API_KEY
- Run: python ibmi_agent.py
Coming Up
In our next article covering AI agents on IBM i, we will go beyond the basics, and discuss how to build advanced capabilities into your agents.