Category: Ai Agents

  • How to Build AI Agents With n8n: Step-by-Step Guide

    How to Build AI Agents With n8n

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Building AI agents used to mean stitching together Python scripts, cron jobs, and a pile of API keys. n8n changes that. It’s an open-source workflow automation tool that now ships a native AI Agent node, letting you wire large language models, tools, and memory into a visual canvas instead of a code editor. This guide walks through everything from a local Docker install to a production deployment on a VPS you actually control.

    We’ll build a working agent — not a toy demo — that can call external APIs, remember conversation context, and run on a schedule or webhook trigger. If you’re already comfortable with Docker, you can skip straight to the workflow-building section below.

    What Is n8n and Why Use It for AI Agents

    n8n (pronounced “n-eight-n”) is a fair-code workflow automation platform. Unlike Zapier or Make, you can self-host it, inspect every line of its source on GitHub, and extend it with custom JavaScript or Python code nodes when the built-in nodes aren’t enough.

    Since version 1.19, n8n ships an AI Agent node built on top of LangChain’s agent framework, but exposed through n8n’s drag-and-drop interface. That means you get:

  • Native support for OpenAI, Anthropic, Google Gemini, and local models via Ollama
  • Built-in memory nodes (buffer, window, vector store-backed)
  • Tool nodes that let the agent call HTTP endpoints, run code, query databases, or trigger other workflows
  • Full execution logs for every agent decision, which matters a lot when something goes wrong in production
  • n8n vs LangChain vs Custom Code

    If you’ve evaluated raw LangChain or LlamaIndex for agent building, the tradeoff is straightforward: those frameworks give you more flexibility but require you to own the infrastructure, error handling, retry logic, and deployment pipeline yourself. n8n gives you 80% of that flexibility with a visual debugger, built-in credential storage, and one-click deployment via Docker. For internal tooling, support bots, and workflow automation, that tradeoff usually favors n8n. For research-grade custom agent architectures, you’ll still want raw code.

    Prerequisites

    Before starting, make sure you have:

  • Docker and Docker Compose installed (see our Docker Compose beginner’s guide if you’re new to it)
  • An API key from OpenAI, Anthropic, or a self-hosted Ollama instance
  • Basic familiarity with webhooks and REST APIs
  • A VPS if you plan to deploy beyond local testing (we cover that below)
  • Setting Up n8n Locally With Docker

    The fastest way to get n8n running is Docker Compose. Create a project directory and drop in the following file.

    # docker-compose.yml
    version: "3.8"
    
    services:
      n8n:
        image: docker.n8n.io/n8nio/n8n:latest
        restart: unless-stopped
        ports:
          - "5678:5678"
        environment:
          - N8N_BASIC_AUTH_ACTIVE=true
          - N8N_BASIC_AUTH_USER=admin
          - N8N_BASIC_AUTH_PASSWORD=change_this_password
          - N8N_HOST=localhost
          - N8N_PORT=5678
          - N8N_PROTOCOL=http
          - GENERIC_TIMEZONE=America/New_York
          - N8N_ENCRYPTION_KEY=replace_with_a_long_random_string
        volumes:
          - n8n_data:/home/node/.n8n
    
    volumes:
      n8n_data:

    Bring it up with:

    docker compose up -d

    Then open http://localhost:5678 and log in with the credentials you set above. n8n will prompt you to create an owner account on first launch — do that before anything else, since the basic auth env vars only gate the login screen, not the app itself in newer versions.

    Installing n8n via Docker Compose Behind a Reverse Proxy

    If you want HTTPS locally or plan to test webhook triggers from third-party services, put Nginx or Caddy in front of n8n. Our Nginx reverse proxy for Docker guide covers the certificate and config details. For local development, an ngrok tunnel is usually faster:

    ngrok http 5678

    Use the generated HTTPS URL as your webhook endpoint when testing integrations with services that require public callbacks (Slack, Telegram, Twilio, etc.).

    Building Your First AI Agent Workflow

    Once n8n is running, create a new workflow and add these nodes in order: Chat Trigger, then AI Agent, then the tools attached to that agent.

    Configuring the AI Agent Node

    1. Add a Chat Trigger node — this gives you a built-in chat UI for testing without building a frontend.
    2. Add an AI Agent node and connect it to the trigger.
    3. Under “Chat Model,” select OpenAI Chat Model (or Anthropic, or Ollama for local inference) and paste your credential.
    4. Set the system prompt. Be specific — vague prompts produce agents that hallucinate tool usage:

    You are a DevOps assistant. You have access to a server-status tool and a
    ticket-creation tool. Always check server status before creating a ticket.
    Respond concisely and cite which tool you used.

    5. Under “Memory,” attach a Window Buffer Memory node if you want the agent to remember the last N messages in a conversation. For anything long-running or multi-session, use a vector-store-backed memory instead (Postgres with pgvector, Qdrant, or Pinecone all have native n8n nodes).

    Adding Tools to Your Agent

    Tools are what separate an “agent” from a chatbot. In n8n, any node can become a tool by toggling “Use as Tool” or by using the dedicated Tool node wrappers. Common patterns:

  • HTTP Request Tool — expose an internal API (server metrics, ticketing system, inventory database) as a callable function the LLM can invoke
  • Code Tool — run a JavaScript or Python snippet for calculations the model shouldn’t attempt itself
  • Workflow Tool — call another n8n workflow as a sub-agent, useful for splitting complex logic into smaller, testable pieces
  • Vector Store Tool — give the agent retrieval-augmented generation (RAG) access to a document store
  • Here’s an example HTTP Request Tool configuration for checking server uptime, wired as a tool the agent can call autonomously:

    {
      "method": "GET",
      "url": "https://api.yourservice.com/v1/status",
      "authentication": "genericCredentialType",
      "toolDescription": "Returns current uptime and CPU/memory usage for the production server. Call this before creating any incident ticket."
    }

    The toolDescription field matters more than any other setting here — it’s the text the LLM reads to decide whether and when to call the tool. Vague descriptions lead to agents that either never use the tool or use it constantly for no reason.

    Testing and Debugging Agent Decisions

    Every AI Agent execution in n8n logs its full reasoning chain: which tools it considered, what parameters it passed, and the raw model response at each step. Open the execution list after a test run and click into any node to see this. This is the single biggest advantage over building agents in raw code without a visual debugger — you can see exactly why an agent chose (or refused) to call a tool, without adding print statements everywhere.

    Adding Retrieval-Augmented Generation (RAG)

    If your agent needs to answer questions from internal documentation, wire up a vector store pipeline separately from the live agent workflow:

    1. A trigger workflow that watches a folder or endpoint for new documents
    2. A Text Splitter node to chunk long documents
    3. An Embeddings node (OpenAI or a local Ollama embedding model)
    4. A Vector Store node (Qdrant, Pinecone, or Postgres/pgvector) to store the chunks

    Then in your agent workflow, add a Vector Store Tool pointed at the same collection, with a description like “Search internal documentation for policy and configuration questions.” The agent will query it automatically when a user’s question matches that description.

    Deploying n8n to Production

    Running n8n on your laptop is fine for prototyping, but agents that call real APIs and handle real users need a stable host. A small VPS is enough for most single-team deployments — n8n itself is lightweight, and the actual LLM inference happens on OpenAI’s or Anthropic’s servers, not yours.

    For this, DigitalOcean droplets are a solid default — a $12/month droplet handles n8n plus a Postgres database comfortably, and their managed database add-on removes one more thing to babysit. If you want more compute per dollar and don’t mind Europe-based infrastructure, Hetzner is consistently cheaper for the same specs.

    Once deployed, put Cloudflare in front of your n8n instance for free SSL termination and DDoS protection — this matters because webhook-triggered agents are publicly reachable by design. And since an agent that silently stops responding is worse than one that never worked, wire up BetterStack for uptime monitoring on your webhook endpoints and the n8n health check route (/healthz).

    A minimal production-ready docker-compose.yml swaps SQLite for Postgres and adds persistent volumes:

    version: "3.8"
    
    services:
      postgres:
        image: postgres:16
        restart: unless-stopped
        environment:
          - POSTGRES_USER=n8n
          - POSTGRES_PASSWORD=change_this_password
          - POSTGRES_DB=n8n
        volumes:
          - postgres_data:/var/lib/postgresql/data
    
      n8n:
        image: docker.n8n.io/n8nio/n8n:latest
        restart: unless-stopped
        depends_on:
          - postgres
        ports:
          - "5678:5678"
        environment:
          - DB_TYPE=postgresdb
          - DB_POSTGRESDB_HOST=postgres
          - DB_POSTGRESDB_DATABASE=n8n
          - DB_POSTGRESDB_USER=n8n
          - DB_POSTGRESDB_PASSWORD=change_this_password
          - N8N_ENCRYPTION_KEY=replace_with_a_long_random_string
          - WEBHOOK_URL=https://n8n.yourdomain.com/
          - N8N_PROTOCOL=https
        volumes:
          - n8n_data:/home/node/.n8n
    
    volumes:
      postgres_data:
      n8n_data:

    Deploy it the same way — docker compose up -d — then point your reverse proxy or Cloudflare Tunnel at port 5678.

    Common Pitfalls When Building n8n Agents

  • Overloaded system prompts — one agent trying to do ten things will underperform ten narrow agents chained together via Workflow Tool nodes
  • Missing tool descriptions — the model can’t guess what a tool does; write descriptions as if explaining to a new hire
  • No rate limiting on webhook triggers — a public Chat Trigger without authentication is an open invitation for abuse and runaway API bills
  • Storing API keys in plain environment variables instead of n8n’s credential vault — always use the built-in credentials system so keys are encrypted at rest
  • Skipping memory pruning — window buffer memory left unbounded will eventually blow past your model’s context window on long conversations
  • Monitoring and Iterating on Agent Performance

    Shipping the first version of an agent is the easy part. The harder part is catching failure modes before users do — an agent that occasionally calls the wrong tool, loops on a task, or returns a confident but wrong answer won’t always throw an error n8n can catch automatically. Export execution data regularly and review a sample of transcripts by hand, especially in the first few weeks after launch. Pay attention to:

  • How often the agent calls a tool it wasn’t supposed to need
  • Average response latency, which climbs fast once you chain multiple tool calls per turn
  • Token usage per conversation, since a single runaway loop can burn through your OpenAI budget in minutes
  • Cases where the agent apologizes or hedges excessively — often a sign the system prompt is too restrictive
  • Set up alerting on failed executions using n8n’s built-in error workflow feature: any workflow can have a dedicated error handler that fires on failure, letting you route exceptions to Slack, email, or a ticketing system instead of discovering them days later in the logs. Combined with BetterStack‘s uptime checks on your webhook endpoint, this gives you two independent signals — one for “the server is down” and one for “the server is up but the agent is misbehaving” — which is the distinction that actually matters once agents are handling real traffic.

    Wrapping Up

    n8n won’t replace a custom-built agent framework for every use case, but for teams that need production AI agents shipped in days instead of months, it’s one of the fastest paths available. Start local with Docker, prototype your tool descriptions carefully, and move to a proper Postgres-backed deployment once the workflow proves useful. If you’re also managing the underlying infrastructure, our self-hosting guide for VPS deployments covers hardening steps worth applying before you expose any agent publicly.

    Recommended: Want to explore DigitalOcean yourself? DigitalOcean is a direct vendor link (not an affiliate/tracked link).

    FAQ

    Do I need to know how to code to build AI agents in n8n?
    No. The AI Agent node, tool nodes, and memory nodes are all configured visually. Code nodes are optional and only needed for custom logic that no built-in node covers.

    Can I run n8n AI agents without paying for OpenAI or Anthropic?
    Yes. n8n’s Chat Model node supports Ollama, which runs open models like Llama 3 or Mistral locally. Performance depends on your hardware, but it works well for testing and low-traffic production use.

    How is an n8n AI Agent different from a regular n8n workflow?
    A regular workflow follows a fixed, predetermined sequence of steps. An AI Agent node lets the LLM decide dynamically which tools to call and in what order, based on the conversation and system prompt, rather than following a hardcoded path.

    Is n8n secure enough for production agent deployments?
    It can be, if you follow standard practices: use the credential vault instead of plain env vars, put a reverse proxy with HTTPS in front of it, restrict webhook access where possible, and keep the Docker image updated. n8n itself is open source and auditable on GitHub.

    What’s the difference between window buffer memory and vector store memory?
    Window buffer memory keeps the last N messages in a conversation in raw form — simple and fast, but limited by context window size. Vector store memory embeds and stores conversation history (or documents) for semantic retrieval, letting the agent recall relevant information from much further back or from an external knowledge base.

    Can one n8n agent call another n8n agent?
    Yes, via the Workflow Tool node. This lets you build a “manager” agent that delegates subtasks to specialized “worker” agent workflows, which is often more reliable than one agent trying to handle everything with a single sprawling system prompt.

  • How to Build Agentic AI: A Developer’s Guide

    How to Build Agentic AI: A Practical Developer’s Guide

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Agentic AI isn’t a single library or API call — it’s an architecture pattern where a language model plans, calls tools, evaluates the results, and iterates until it solves a task on its own, without a human clicking “next” at every step. If you’ve been shipping simple chatbot wrappers around an LLM and want to move up to something that actually takes actions in the real world, this guide covers how to build agentic ai systems from first principles: the reasoning loop, tool calling, memory, and the infrastructure decisions that separate a weekend demo from something you can run in production.

    We’ll build a minimal agent in Python, add tool calling, containerize it with Docker, and cover the hosting, monitoring, and security choices that matter once you’re running this for real users instead of just yourself in a notebook.

    What Is Agentic AI, Really?

    Most people use “agentic AI” loosely to describe anything that calls an LLM in a loop. A more precise definition: an agentic system is one where the model itself decides what to do next based on the current state of the world, rather than following a hardcoded sequence of steps written by a developer. The model observes, reasons about the observation, picks an action (usually a tool call), executes it, observes the result, and repeats until it decides the task is done.

    This is fundamentally different from a chatbot, which just responds to the last message, or a fixed pipeline, which runs steps A → B → C regardless of what happens along the way.

    Agents vs. Chatbots vs. Pipelines

    It helps to draw a hard line between three patterns that get conflated constantly:

  • Chatbot: stateless (or lightly stateful) request/response. User asks, model answers. No tool use, no planning.
  • Pipeline / workflow: a fixed sequence of LLM calls and deterministic steps, defined by the developer ahead of time. Reliable, but can’t adapt to novel situations.
  • Agent: the control flow itself is decided by the model at runtime. It chooses which tool to call, whether to retry, when to stop, and how to recover from errors.
  • Agents are more powerful but also less predictable and harder to debug — every extra decision the model makes is a new surface for it to get things wrong. That tradeoff should inform whether you actually need an agent or whether a simpler pipeline would do the job with far less operational risk.

    The Core Components of an Agentic System

    Every agentic AI implementation, regardless of framework, is built from the same handful of pieces.

    1. The Reasoning Loop

    The heart of an agent is the ReAct-style loop: Reason, Act, Observe, repeat. The model is prompted to think through the problem, choose an action, and the system executes that action and feeds the result back in. This continues until the model emits a “final answer” signal or a hard iteration limit is hit — that limit matters, because without it a buggy agent will happily loop forever, burning API credits.

    2. Tool Calling

    Tools are how an agent affects anything outside its own context window: searching the web, querying a database, running a shell command, hitting an internal API. Modern LLM providers (OpenAI, Anthropic, and others) expose native function-calling APIs, so the model returns structured JSON describing which tool to call and with what arguments, instead of you parsing free text.

    3. Memory and State

    Agents that run multi-step tasks need to remember what they’ve already tried. Short-term memory is usually just the running conversation/action history in the context window. Long-term memory — for agents that need to recall facts across sessions — typically uses a vector database or a simple key-value store. Don’t reach for a vector database on day one; most agents get by fine with a plain list of prior steps until you’ve proven you need more.

    Building a Minimal Agent From Scratch

    You don’t need a heavyweight framework to understand how agentic AI works. Here’s a minimal ReAct-style loop in Python using the OpenAI SDK’s function-calling interface:

    import json
    from openai import OpenAI
    
    client = OpenAI()
    
    def get_weather(city: str) -> str:
        # Stand-in for a real API call
        return f"It's 72F and sunny in {city}."
    
    TOOLS = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Get current weather for a city",
                "parameters": {
                    "type": "object",
                    "properties": {"city": {"type": "string"}},
                    "required": ["city"],
                },
            },
        }
    ]
    
    AVAILABLE_FUNCTIONS = {"get_weather": get_weather}
    
    def run_agent(user_prompt: str, max_steps: int = 5) -> str:
        messages = [{"role": "user", "content": user_prompt}]
    
        for _ in range(max_steps):
            response = client.chat.completions.create(
                model="gpt-4o",
                messages=messages,
                tools=TOOLS,
            )
            message = response.choices[0].message
            messages.append(message)
    
            if not message.tool_calls:
                return message.content
    
            for call in message.tool_calls:
                fn = AVAILABLE_FUNCTIONS[call.function.name]
                args = json.loads(call.function.arguments)
                result = fn(**args)
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": result,
                })
    
        return "Max steps reached without a final answer."
    
    if __name__ == "__main__":
        print(run_agent("What's the weather in Lisbon?"))

    That’s the whole pattern: loop, check for tool calls, execute them, feed results back, repeat. Everything else — memory, planning strategies, multi-agent orchestration — is built on top of this core.

    Adding Real Tools: Shell Execution and Web Search

    Once the loop works, the next step is giving the agent tools that do something meaningful. A shell-execution tool is common for DevOps-focused agents:

    import subprocess
    
    def run_shell(command: str) -> str:
        result = subprocess.run(
            command, shell=True, capture_output=True, text=True, timeout=30
        )
        return result.stdout + result.stderr

    Be deliberate here: giving a model direct shell access is a serious security decision, not a convenience feature. At minimum, run it inside an isolated container with no access to secrets or the host filesystem, and whitelist the specific commands the agent is allowed to run rather than passing arbitrary strings to shell=True in a production system. Treat every tool the agent can call as an attack surface, the same way you’d treat a public API endpoint.

    Containerizing Your Agent with Docker

    Once your agent works locally, package it so it runs the same way everywhere. If you’re new to multi-service setups, our Docker Compose guide for beginners covers the fundamentals this builds on.

    FROM python:3.12-slim
    
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY . .
    
    ENV PYTHONUNBUFFERED=1
    USER nobody
    
    CMD ["python", "agent.py"]

    Running as a non-root user (USER nobody) matters more here than in a typical web app, because an agent with shell or filesystem tools is effectively remote code execution by design — you want the container’s own permissions to be your last line of defense if a tool call goes wrong. Build and run it:

    docker build -t my-agent .
    docker run --rm -e OPENAI_API_KEY=$OPENAI_API_KEY my-agent

    For anything beyond a single container, wire it into a docker-compose.yml alongside a vector database (like Qdrant or Chroma) and any supporting services your agent depends on.

    Deploying and Monitoring in Production

    A local Docker container is fine for development, but production agents need a real host, uptime monitoring, and a way to catch runaway loops before they burn through your API budget.

    For hosting, a DigitalOcean droplet is a solid, low-friction choice for running a containerized agent — you get a public IP, predictable pricing, and enough control to lock down the box the way an agent with tool access requires. If you’re comparing providers for this kind of workload, our guide to picking a VPS for Docker workloads walks through the tradeoffs in more depth.

    Once it’s running, you need to know immediately if the agent process dies or starts erroring on every request — an agent stuck in a retry loop can fail silently for hours otherwise. BetterStack gives you uptime checks and log aggregation without having to stand up your own Prometheus/Grafana stack for a single service. If your agent exposes an HTTP endpoint for other systems to call, put Cloudflare in front of it for basic DDoS protection and rate limiting — an unauthenticated agent endpoint is an expensive target if someone finds it and starts hammering it with requests that each trigger a paid LLM call.

    Rate Limiting and Cost Controls

    Agentic loops are the easiest way to accidentally run up a four-figure API bill overnight. At minimum:

  • Cap the number of loop iterations per task (5–10 is usually plenty).
  • Set a hard token budget per request and abort if it’s exceeded.
  • Log every tool call with its cost so you can audit spend after the fact.
  • Use a cheaper model for the reasoning/routing steps and reserve the expensive model for the final synthesis step, if your framework supports mixed models.
  • Common Pitfalls When Building Agentic AI

    A few mistakes show up in almost every agent project:

  • No iteration cap. Without a hard max-steps limit, a confused agent will loop indefinitely.
  • Overly broad tool permissions. Giving an agent full shell or filesystem access “to be safe” is backwards — narrow, purpose-built tools are both safer and easier for the model to use correctly.
  • Ignoring tool call failures. If a tool call errors out, feed the error back into the loop so the model can adapt, don’t just crash the whole run.
  • Skipping observability. If you can’t see the full trace of reasoning steps and tool calls after the fact, you can’t debug why the agent did something wrong.
  • Treating agents as a drop-in replacement for a deterministic pipeline. If the task has a fixed, known sequence of steps, a pipeline will be more reliable and cheaper than an agent every time.
  • Recommended: Want to explore DigitalOcean yourself? DigitalOcean is a direct vendor link (not an affiliate/tracked link).

    FAQ

    Do I need LangChain or a similar framework to build agentic AI?
    No. Frameworks like LangChain, LlamaIndex, and CrewAI save time on boilerplate (tool schemas, memory stores, multi-agent orchestration), but the core reasoning loop is simple enough to write from scratch, as shown above. Many production teams start with a framework and later rip it out once they need finer control over the loop.

    What’s the difference between an agent and a RAG pipeline?
    RAG (retrieval-augmented generation) is a fixed pipeline: retrieve relevant documents, stuff them into the prompt, generate an answer. An agent can decide whether to retrieve, what to search for, and whether the results are good enough to answer with — RAG can be one of the tools an agent has available.

    How do I stop an agent from getting stuck in a loop?
    Set a hard maximum number of iterations, and consider adding a secondary check — like a separate, cheap model call — that flags when the agent is repeating the same action without making progress.

    Which LLM is best for building agentic AI?
    Models with strong native function-calling support (OpenAI’s GPT-4o, Anthropic’s Claude models) are the most reliable choice, since they return structured tool calls instead of you having to parse free-form text for intent.

    Is it safe to give an agent shell access?
    Only inside an isolated, disposable container with no access to secrets, and ideally with a whitelist of allowed commands rather than arbitrary execution. Never grant shell access to an agent running on the same host as production data or credentials.

    How much does it cost to run an agent in production?
    It depends entirely on iteration count and model choice, since each reasoning step is a separate API call. Logging token usage per tool call from day one is the only reliable way to catch cost blowouts before they show up on your bill.

    Building agentic AI isn’t about finding the right framework — it’s about understanding the loop, being deliberate about what tools you expose, and treating the infrastructure around the agent (containers, monitoring, rate limits) with the same rigor you’d apply to any other production service. Start with the minimal loop above, add one tool at a time, and only reach for memory stores, multi-agent orchestration, or a heavier framework once you’ve hit a concrete limitation the simple version can’t handle.

  • How to Create an AI Agent: A Developer’s Guide

    How to Create an AI Agent: A Practical Guide for Developers

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    If you’ve spent any time reading DevOps forums or Hacker News in the last year, you’ve seen the term “AI agent” thrown around constantly. Most of the explanations stop at theory. This guide doesn’t. We’re going to build a working AI agent in Python, wrap it in Docker, and deploy it to a real Linux server — the same way you’d ship any other production service.

    By the end of this article you’ll understand what an AI agent actually is (beyond the marketing buzzword), how to structure one, how to give it tool-use capabilities, and how to run it reliably in production — including logging, monitoring, and basic security hardening.

    What Is an AI Agent, Really?

    An AI agent is a program that uses a large language model (LLM) as its reasoning engine, combined with a loop that lets it take actions, observe results, and decide what to do next — without a human manually scripting every step.

    The key difference between an AI agent and a simple chatbot wrapper is autonomy through iteration. A chatbot takes input and returns output once. An agent can:

  • Break a goal into subtasks
  • Call external tools or APIs (search, databases, shell commands, other services)
  • Evaluate whether the result moved it closer to the goal
  • Loop again if it didn’t
  • This is why agents are useful for DevOps and infrastructure work specifically — tasks like “check if this container is healthy, and restart it if not” or “summarize last night’s error logs and file a ticket” are naturally iterative and benefit from an LLM’s ability to reason over unstructured text.

    Core Components of an Agent

    Every functional AI agent, regardless of framework, has the same four pieces:

  • A model — the LLM doing the reasoning (OpenAI’s GPT models, Anthropic’s Claude, or a self-hosted model via Ollama)
  • A memory/state store — tracks conversation history and intermediate results
  • Tools — functions the agent can call (web search, file I/O, shell commands, database queries)
  • A control loop — the code that decides when to call the model, when to call a tool, and when to stop
  • You can build this from scratch in under 150 lines of Python, which is exactly what we’ll do below.

    Prerequisites

    Before you start, make sure you have:

  • Python 3.11+ installed locally
  • Docker installed (see our Docker installation guide if you’re starting fresh)
  • An API key from OpenAI, Anthropic, or a local model server
  • A Linux VPS if you plan to deploy the agent (we use Ubuntu 22.04 in this guide)
  • If you don’t already have a VPS, DigitalOcean is a solid choice for running small agent workloads — their basic droplets are cheap enough to experiment with without committing to a large monthly bill.

    Building the Agent Step by Step

    Setting Up the Environment

    Start with a clean virtual environment and the minimal dependencies. We’re deliberately avoiding a heavyweight framework for the first pass so you understand exactly what’s happening under the hood.

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

    Create a .env file to hold your API key — never hardcode credentials into your source:

    echo "OPENAI_API_KEY=sk-your-key-here" > .env

    Writing the Agent Core Loop

    This is the heart of the system: a loop that sends the current state to the model, checks whether it wants to call a tool, executes that tool if so, and feeds the result back in.

    # agent.py
    import os
    import json
    from dotenv import load_dotenv
    from openai import OpenAI
    
    load_dotenv()
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    
    def get_disk_usage():
        import shutil
        total, used, free = shutil.disk_usage("/")
        return {
            "total_gb": round(total / (2**30), 2),
            "used_gb": round(used / (2**30), 2),
            "free_gb": round(free / (2**30), 2),
        }
    
    TOOLS = [
        {
            "type": "function",
            "function": {
                "name": "get_disk_usage",
                "description": "Return current disk usage stats for the root filesystem.",
                "parameters": {"type": "object", "properties": {}},
            },
        }
    ]
    
    AVAILABLE_FUNCTIONS = {"get_disk_usage": get_disk_usage}
    
    def run_agent(user_goal, max_iterations=5):
        messages = [
            {"role": "system", "content": "You are an infrastructure monitoring agent. Use tools when needed."},
            {"role": "user", "content": user_goal},
        ]
    
        for _ in range(max_iterations):
            response = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=messages,
                tools=TOOLS,
            )
            msg = response.choices[0].message
    
            if msg.tool_calls:
                messages.append(msg)
                for call in msg.tool_calls:
                    fn = AVAILABLE_FUNCTIONS[call.function.name]
                    result = fn()
                    messages.append({
                        "role": "tool",
                        "tool_call_id": call.id,
                        "content": json.dumps(result),
                    })
                continue
    
            return msg.content
    
        return "Max iterations reached without a final answer."
    
    if __name__ == "__main__":
        result = run_agent("Check disk usage and tell me if we're at risk of running out of space.")
        print(result)

    Run it:

    python agent.py

    The model will call get_disk_usage, receive real data from your machine, and respond with an actual assessment — not a hallucinated guess. This tool-calling pattern is the foundation every serious agent framework (LangChain, LangGraph, CrewAI) builds on top of.

    Adding More Tools

    Once the loop works, expanding capability is just a matter of adding functions and registering them:

  • A tool to tail recent log entries from a service
  • A tool to query a Prometheus endpoint for container metrics
  • A tool to restart a Docker container via the Docker SDK
  • A tool to post a summary to Slack or a ticketing system
  • Each tool should do one narrow thing and return structured data — resist the temptation to have a single “do everything” tool, since the model reasons much better with clearly scoped functions.

    Dockerizing the Agent

    Once the core loop works, package it so it runs the same way everywhere. Here’s a minimal production Dockerfile:

    FROM python:3.11-slim
    
    WORKDIR /app
    
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY agent.py .
    
    ENV PYTHONUNBUFFERED=1
    
    CMD ["python", "agent.py"]

    Build and run it:

    docker build -t ai-agent:latest .
    docker run --rm --env-file .env ai-agent:latest

    For anything beyond a one-off script, mount a volume for logs and pass secrets via environment variables rather than baking them into the image. If you’re new to container networking and volumes, our Docker networking deep dive covers the patterns you’ll need before going further.

    Deploying the Agent to a VPS

    Once containerized, deployment is straightforward. SSH into your server, pull the image (or build it there), and run it as a systemd-managed service or via docker run --restart unless-stopped for simplicity:

    ssh user@your-vps-ip
    docker pull yourregistry/ai-agent:latest
    docker run -d 
      --name ai-agent 
      --restart unless-stopped 
      --env-file /opt/ai-agent/.env 
      yourregistry/ai-agent:latest

    For anything running continuously (rather than a one-shot script), wrap the loop in a scheduler or a long-running process that sleeps between iterations, and make sure docker logs ai-agent gives you enough context to debug failures without SSHing in and guessing.

    Monitoring and Logging

    An agent that silently fails is worse than no agent at all — you need visibility into what it’s doing and why. At minimum:

  • Log every tool call and its result to stdout (captured automatically by Docker)
  • Log every model response, especially final decisions
  • Set up alerting for repeated failures or max-iteration timeouts
  • For production deployments, a dedicated uptime and log monitoring service pays for itself the first time your agent silently stops working at 3 a.m. BetterStack is worth evaluating here — their log aggregation and uptime monitoring integrate cleanly with containerized services and will page you before your users notice something’s wrong.

    Security Considerations

    Giving an LLM the ability to execute code or call APIs is powerful and dangerous in equal measure. Follow these rules:

  • Never let the agent execute arbitrary shell commands generated by the model without a strict allowlist
  • Sandbox tool execution — run agents in containers with minimal privileges, not on your host directly
  • Validate and sanitize any input that flows from the model into a database query, file path, or shell command
  • Rate-limit and log every external API call the agent makes
  • Put the agent’s public-facing endpoints (if any) behind a WAF and DDoS protection — Cloudflare is a reasonable default if you’re exposing a webhook or dashboard for the agent
  • Treat every tool the agent can call as a potential attack surface, the same way you’d treat a user-facing API endpoint.

    Scaling Beyond a Single Agent

    Once your first agent works reliably, the natural next step is running several agents for different tasks — one for log triage, one for cost reporting, one for deployment verification. At this point:

  • Isolate each agent in its own container with its own resource limits
  • Centralize logging so you’re not tailing five separate containers by hand
  • Consider a message queue (Redis, RabbitMQ) if agents need to hand off tasks to each other
  • Running multiple containers reliably means your underlying infrastructure needs to keep up. If you’re outgrowing a single small droplet, DigitalOcean‘s managed Kubernetes or larger droplet tiers are a straightforward upgrade path without re-architecting everything from scratch.

    Recommended: Want to explore DigitalOcean yourself? DigitalOcean is a direct vendor link (not an affiliate/tracked link).

    FAQ

    Do I need LangChain or CrewAI to build an AI agent?
    No. Those frameworks are useful once you have many tools and complex branching logic, but you can build a fully functional agent with plain Python and the OpenAI or Anthropic SDK, as shown above. Frameworks add convenience, not capability.

    Which LLM should I use for an agent?
    For tool-calling reliability, GPT-4o-mini, GPT-4o, and Claude models all support structured function calling well. Start with a cheaper model for development and upgrade only if you see reasoning failures in production.

    Can I run an AI agent without paying for API access?
    Yes — tools like Ollama let you run open models locally, though tool-calling support and reasoning quality vary by model. It’s a good option for prototyping or privacy-sensitive workloads.

    How do I stop an agent from looping forever?
    Always set a max_iterations cap in your control loop, as shown in the example above. Never let an agent run in an unbounded while loop in production.

    Is it safe to let an agent execute shell commands?
    Only with strict guardrails — an explicit allowlist of commands, no direct shell interpolation of model output, and execution inside an isolated container with minimal permissions.

    How is an AI agent different from a cron job with an API call?
    A cron job runs a fixed set of steps. An agent decides its own steps based on what it observes, and can adapt its plan mid-execution — that’s the core distinction.

    Wrapping Up

    Building an AI agent isn’t magic — it’s a control loop, a handful of well-scoped tools, and disciplined engineering around logging, security, and deployment. Start small: one tool, one clear goal, a hard iteration cap. Containerize it, deploy it to a real server, and monitor it like you would any other production service. Once that foundation is solid, adding more tools and more agents is incremental work, not a redesign.

    If you’re setting this up on your own infrastructure, revisit our Docker basics guide and Docker networking deep dive to make sure your container setup is production-ready before you put an agent in charge of anything that matters.