cd /news/artificial-intelligence/how-to-build-your-first-ai-genai-age… · home topics artificial-intelligence article
[ARTICLE · art-108561] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

How to Build Your First AI, GenAI & Agentic AI Project

A developer has published a tutorial on building a first AI, GenAI, and agentic AI project, focusing on a local CLI tool that summarizes server logs and executes cleanup commands. The project uses plain Python with the OpenAI SDK, avoiding heavy abstractions like LangChain, and supports local models via Ollama. The tutorial demonstrates how to create an agent that takes actions based on LLM-generated insights.

read5 min views1 publishedAug 24, 2026

Every tutorial on the internet right now starts with a ten-paragraph essay defining what an LLM is, as if you haven't been forced to use GitHub Copilot or ChatGPT for the last two years. Let's skip that.

The problem isn't understanding what Generative AI is anymore. The problem is that when you sit down to actually build something beyond a wrapper that sends "Hello" to the OpenAI API, the terminology gets murky fast. What makes something "GenAI"? When does an app cross the line into being an "Agent"?

We are going to build a small local CLI tool that takes a messy, unstructured text file of raw server logs, generates a summary using an LLM, and then—here's the agentic part—automatically writes and executes a cleanup script based on what it found.

No LangChain abstractions that hide what's actually happening. Just Python, the raw openai

library (pointing to whatever model you have), and standard subprocess calls.

When I first started looking at agentic workflows, I tried LangChain first. It was more trouble than it was worth. I spent three hours debugging why some abstracted chain was eating my prompt variables before realizing the documentation I was reading was for a version released three weeks prior that was already deprecated.

We are going to write plain Python.

Create a new directory and set up a virtual environment. We'll need the OpenAI SDK and python-dotenv

for managing API keys. If you don't want to pay OpenAI for messing around, swap out the base URL for a local Ollama instance running llama3

or mistral

. The code works the same either way.

mkdir log-agent
cd log-agent
python3 -m venv venv
source venv/bin/activate
pip install openai python-dotenv

Create a .env

file in the root:

OPENAI_API_KEY=your_key_here

Now let's create a dummy log file to work with. Call it server.log

:

[2026-03-05 10:12:01] INFO: Server started on port 8080
[2026-03-05 10:14:32] ERROR: Connection refused to database at 10.0.0.4:5432
[2026-03-05 10:15:00] WARNING: High memory usage detected: 92%
[2026-03-05 10:20:12] ERROR: Out of disk space on /var/log. Current free: 0MB
[2026-03-05 10:21:00] INFO: Attempting log rotation... failed.

Standard Generative AI takes an input and generates text. You give it the log file, it writes a nice summary. That's neat, but it still requires a human to read the summary and fix the problem.

Agentic AI closes the loop. It gives the model the ability to take actions based on what it generates. We do this using tool use (sometimes called function calling). We will define a Python function that can run shell commands, tell the LLM about it, and let the model decide if it needs to run it.

Here is the core script. Save this as agent.py

:

import os
import json
import subprocess
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()
client = OpenAI()

def execute_cleanup_command(command: str) -> str:
    """Executes a bash command to clean up disk space or restart services."""
    print(f"\n[AGENT ACTION] About to run command: {command}")
    confirmation = input("Allow this action? (y/n): ")
    if confirmation.lower() != 'y':
        return "Action denied by user."

    try:
        result = subprocess.run(
            command, shell=True, check=True, 
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
        )
        return f"Success:\n{result.stdout}"
    except subprocess.CalledProcessError as e:
        return f"Error executing command:\n{e.stderr}"

available_tools = {
    "execute_cleanup_command": execute_cleanup_command
}

def run_log_agent(log_path: str):
    if not os.path.exists(log_path):
        print(f"File not found: {log_path}")
        return

    with open(log_path, 'r') as f:
        log_content = f.read()

    system_prompt = """
    You are a DevOps assistant. Analyze the provided server logs. 
    If you find critical issues like disk space errors, you have access to a tool 
    to execute bash commands to fix them. Only use the tool if strictly necessary.
    """

    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": f"Here are the logs to analyze:\n\n{log_content}"}
    ]

    tools = [
        {
            "type": "function",
            "function": {
                "name": "execute_cleanup_command",
                "description": "Run a safe shell command to resolve server issues like clearing logs or restarting services.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "command": {
                            "type": "string",
                            "name": "command",
                            "description": "The bash command to execute (e.g., 'truncate -s 0 /var/log/*.log')"
                        }
                    },
                    "required": ["command"]
                }
            }
        }
    ]

    print("Analyzing logs with LLM...")
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )

    response_message = response.choices[0].message
    messages.append(response_message)

    if response_message.tool_calls:
        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.arguments)

            if function_name in available_tools:
                tool_output = available_tools[function_name](
                    command=function_args.get("command")
                )

                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": function_name,
                    "content": tool_output
                })

                second_response = client.chat.completions.create(
                    model="gpt-4o-mini",
                    messages=messages
                )
                print("\nFinal Agent Response:")
                print(second_response.choices[0].message.content)
    else:
        print("\nAgent Response:")
        print(response_message.content)

if __name__ == "__main__":
    run_log_agent("server.log")

Run it with:

python agent.py

If you run the script above, it will likely spot the Out of disk space on /var/log

error and try to run a command to clear space. That's the cool part working.

Here is what will trip you up in practice, because it definitely tripped me up: The model hallucinating destructive commands.

When I first tested a variation of this agent, I gave it permission to run generic shell commands without strict system prompt guardrails. Instead of safely clearing a log file, it tried to run rm -rf /var/log/*

without checking directory paths properly.

Another subtle issue is silent parameter malformation. If you use smaller local models via Ollama (like Llama 3 8B), they sometimes mess up the JSON schema for tool arguments. You'll get an error like:

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

This happens because the model tried to output markdown code blocks inside the tool arguments field instead of raw JSON. If you're building real agents, you must wrap tool execution in try/except blocks and build a retry loop when the JSON parsing fails. Never trust the LLM to format output correctly 100% of the time.

This is also why line 14 of our script has an explicit input()

confirmation check. Never give an autonomous agent unmonitored shell access. Even if the prompt says "be careful," models drift, especially in long loops.

Take this script and add a while

loop so the agent can run in a multi-step "plan-execute-evaluate" loop rather than just a single turn. Let it read the output of the tool it just ran, decide if the problem is fixed, and if not, try a different approach.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @openai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-to-build-your-fi…] indexed:0 read:5min 2026-08-24 ·