Author: admin_ts

  • Telegram Bot Example

    Telegram Bot Example: A Practical Guide to Building Your First Bot

    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’re looking for a working telegram bot example to learn from, this guide walks through the full process: registering a bot, writing the code, deploying it with Docker, and running it reliably in production. Rather than a single toy snippet, you’ll get a complete telegram bot example you can adapt for real projects, along with the reasoning behind each design decision.

    Telegram bots are lightweight, event-driven services that talk to Telegram’s Bot API over HTTPS. They don’t require a browser, a phone number pool, or any special infrastructure beyond a server that can make and receive HTTP requests. That makes them a popular choice for DevOps notification systems, internal tooling, and lightweight customer-facing automation.

    Why Build a Telegram Bot

    Before diving into a telegram bot example, it’s worth understanding what problem this pattern actually solves. Telegram bots are commonly used for:

  • Sending deployment or CI/CD status notifications to a team channel
  • Triggering infrastructure actions (restart a service, pull logs, check disk space) from a chat interface
  • Building lightweight customer support or FAQ automation
  • Relaying alerts from monitoring systems (Prometheus, Grafana, uptime checkers)
  • Acting as a simple front-end for internal admin tools
  • Compared to building a full web dashboard, a Telegram bot is fast to stand up and requires no authentication UI — Telegram already handles identity via chat IDs and usernames. This is why so many infrastructure teams reach for a telegram bot example as their first automation project.

    Bots vs. Webhooks vs. Polling

    Telegram bots can receive updates two ways:

    1. Polling — the bot repeatedly calls getUpdates on the Bot API to check for new messages.
    2. Webhooks — Telegram pushes updates to a public HTTPS endpoint you control.

    Polling is simpler to run locally and behind NAT (no public IP required), while webhooks scale better and reduce latency for high-traffic bots. Most tutorials, including the telegram bot example below, start with polling because it avoids the need for a TLS certificate and a reachable domain during development.

    Registering Your Bot with BotFather

    Every Telegram bot starts with a registration step handled entirely inside Telegram itself, via a special bot called BotFather.

    Getting a Bot Token

    1. Open a chat with @BotFather in Telegram.
    2. Send /newbot and follow the prompts for a name and username (must end in bot).
    3. BotFather returns an API token — a string like 123456789:AAF.... This token is a secret; treat it the same way you’d treat a database password or an API key.
    4. Optionally, use /setdescription, /setuserpic, and /setcommands to configure how your bot appears to users.

    Never commit this token to source control. Store it as an environment variable or in a secrets manager, and rotate it via BotFather’s /revoke command if it ever leaks.

    A Minimal Telegram Bot Example in Python

    The most common starting point for a telegram bot example is a small Python script using the python-telegram-bot library, which wraps the raw Bot API in a friendlier interface.

    python3 -m venv venv
    source venv/bin/activate
    pip install python-telegram-bot --upgrade

    Here’s a minimal, working telegram bot example that responds to /start and echoes back any text message:

    import os
    from telegram import Update
    from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes, filters
    
    BOT_TOKEN = os.environ["BOT_TOKEN"]
    
    async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
        await update.message.reply_text("Hello! Send me any message and I'll echo it back.")
    
    async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
        await update.message.reply_text(update.message.text)
    
    def main():
        app = ApplicationBuilder().token(BOT_TOKEN).build()
        app.add_handler(CommandHandler("start", start))
        app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
        app.run_polling()
    
    if __name__ == "__main__":
        main()

    Run it with BOT_TOKEN=<your-token> python3 bot.py, and the bot will start polling for updates immediately. This is the same architecture used by more advanced systems — a routing layer that matches incoming messages to handlers, similar in shape to command-routing seen in larger automation projects like n8n-based AI agent workflows.

    Adding Command Routing

    Real-world bots usually need more than one command. A slightly extended telegram bot example adds a routing table:

    COMMAND_HANDLERS = {
        "status": handle_status,
        "restart": handle_restart,
        "logs": handle_logs,
    }
    
    async def route_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
        command = update.message.text.split()[0].lstrip("/").lower()
        handler = COMMAND_HANDLERS.get(command)
        if handler:
            await handler(update, context)
        else:
            await update.message.reply_text("Unknown command.")

    This pattern — a dictionary mapping command names to functions — scales well for bots with a dozen or more commands and keeps each handler function small and testable.

    Restricting Access by Chat ID

    Most internal-tooling bots should only respond to a known chat ID, not the general public. This is a simple but important safeguard for any telegram bot example intended for infrastructure use:

    ALLOWED_CHAT_ID = int(os.environ["TG_CHAT_ID"])
    
    async def guarded_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
        if update.effective_chat.id != ALLOWED_CHAT_ID:
            return
        await update.message.reply_text("Authorized command received.")

    Without this check, anyone who discovers your bot’s username can message it and trigger handlers — a meaningful risk if any command touches infrastructure, like restarting a service or reading logs.

    Deploying the Bot with Docker

    Once your telegram bot example works locally, the next step is packaging it so it runs reliably and restarts automatically. Docker is a natural fit here, and the process closely mirrors deploying any long-running Python service.

    FROM python:3.12-slim
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    COPY bot.py .
    CMD ["python3", "bot.py"]

    A minimal docker-compose.yml keeps the bot token out of the image itself:

    services:
      telegram-bot:
        build: .
        restart: unless-stopped
        environment:
          - BOT_TOKEN=${BOT_TOKEN}
          - TG_CHAT_ID=${TG_CHAT_ID}

    If you’re new to Compose syntax or need to manage environment variables more carefully, see this guide on managing Docker Compose environment variables. For debugging a bot that isn’t responding, Docker Compose logs are usually the first place to look — docker compose logs -f telegram-bot will show you every incoming update and any stack traces.

    Running as a systemd Service (Non-Docker Alternative)

    If you’d rather not containerize a small bot, a systemd unit is a lightweight alternative that gives you automatic restarts and log integration with journalctl:

    [Unit]
    Description=Telegram Bot
    After=network.target
    
    [Service]
    ExecStart=/opt/telegram-bot/venv/bin/python3 /opt/telegram-bot/bot.py
    Restart=always
    EnvironmentFile=/opt/telegram-bot/.env
    User=telegrambot
    
    [Install]
    WantedBy=multi-user.target

    Both approaches — Docker Compose and systemd — achieve the same goal: a bot process that survives reboots and restarts automatically after a crash. Which one you pick usually comes down to whether the rest of your stack is already containerized.

    Handling Errors and Rate Limits

    A production-grade telegram bot example needs to account for two failure modes that toy examples usually skip: network errors and Telegram’s rate limits.

  • Wrap outgoing reply_text calls in a retry with backoff for transient network failures.
  • Respect Telegram’s per-chat and per-second rate limits — sending many messages in a tight loop will get throttled, and Telegram may return a retry_after value telling you how long to wait.
  • Log every incoming update and outgoing response somewhere durable (a file, or a service like the one described in this Docker Compose logging guide), so you can reconstruct what happened after an incident.
  • Catch and log exceptions inside handlers rather than letting one bad message crash the whole polling loop.
  • async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE):
        print(f"Update {update} caused error {context.error}")
    
    app.add_error_handler(error_handler)

    Extending the Bot: Webhooks for Production Scale

    Polling works fine for personal or low-traffic bots, but a webhook-based deployment reduces latency and avoids constant outbound polling requests once you’re running at any meaningful scale. Setting a webhook requires a public HTTPS endpoint:

    curl -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" 
      -d "url=https://yourdomain.com/telegram/webhook"

    If you’re already running a reverse proxy for other services, adding a webhook route for your bot is usually just one more location block or ingress rule. If you’re hosting on a VPS and need HTTPS termination, Cloudflare Page Rules or a similar edge configuration can simplify certificate management in front of your webhook endpoint.

    Choosing Where to Host Your Bot

    Whether you run polling or webhooks, the bot needs a stable place to live. A small, inexpensive VPS is usually sufficient — Telegram bots are not resource-intensive unless they’re doing heavy media processing. Providers like DigitalOcean or Hetzner offer small instances that comfortably run a bot alongside a few other lightweight services. If you’re also automating deployments or notifications around a broader workflow engine, it’s worth comparing this setup against self-hosting n8n, which can trigger Telegram messages as one step in a larger automation pipeline.

    Testing Your Bot Before Going Live

    Before pointing real users at a telegram bot example you’ve built, run through a short manual checklist:

  • Send /start and confirm the welcome message appears.
  • Send a message from an unauthorized chat ID and confirm it’s silently ignored (if you’ve added access control).
  • Kill the process mid-run and confirm your restart policy (Docker’s restart: unless-stopped or systemd’s Restart=always) brings it back.
  • Check logs after a forced crash to confirm errors are captured, not silently swallowed.
  • If using webhooks, verify the endpoint responds with a 200 status within Telegram’s timeout window, since slow responses can cause Telegram to retry and duplicate updates.
  • Automating some of this with a basic integration test — sending a message via the Bot API and asserting on the bot’s reply — catches regressions before they reach production.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a public IP address to run a Telegram bot?
    No, not if you use polling. Polling-based bots make outbound requests to Telegram’s servers, so they work fine behind NAT or on a machine with no inbound access. Webhooks, by contrast, require a publicly reachable HTTPS endpoint.

    Is the Bot API token the same as my personal Telegram account?
    No. The token BotFather issues is scoped entirely to the bot you created — it has no access to your personal account, contacts, or chats beyond conversations the bot itself is added to.

    Can a Telegram bot example like this be adapted for other chat platforms?
    The overall architecture — an event loop, a routing table for commands, and handler functions — transfers well to platforms like Slack or Discord, though each has its own API and authentication model, so the integration code itself isn’t portable.

    What’s the difference between python-telegram-bot and calling the Bot API directly with requests?
    python-telegram-bot handles update parsing, retries, and the polling/webhook loop for you, which is why most tutorials use it. Calling the raw HTTP API directly works too, and can be simpler for a bot with only one or two commands, but you’ll end up reimplementing parts of what the library already provides.

    Conclusion

    Building a working telegram bot example doesn’t require much infrastructure: a BotFather-issued token, a small script using a library like python-telegram-bot, and a reliable place to run it. The pattern scales naturally — start with polling and a single command handler locally, then move to Docker or systemd for reliability, and finally to webhooks if you need lower latency at higher volume. Whether you’re building a notification bot for a CI/CD pipeline or a lightweight support tool, the same core structure — token, handlers, deployment, monitoring — applies. For further reading on Telegram’s full command surface, see the official Telegram Bot API documentation, and for container deployment details, the Docker documentation covers image building and Compose configuration in depth.

  • Free Vps Hosting No Credit Card

    Free VPS Hosting No Credit Card: 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.

    Looking for free VPS hosting no credit card required so you can test a project without handing over payment details? You’re not alone — many developers want a disposable Linux box to try out a script, learn Docker, or prototype an API without triggering a billing relationship first. This guide walks through what’s realistically available, how to evaluate providers claiming free VPS hosting no credit card, and how to get a usable box running quickly and securely.

    Before diving in, it’s worth setting expectations correctly: genuinely free, no-card, production-grade VPS hosting is rare, and most offers in this space are either extremely limited, time-boxed, or come with real tradeoffs. This article covers the realistic options, the technical setup once you have a box, and the security basics you need regardless of which provider you choose.

    Why “Free VPS Hosting No Credit Card” Is Hard to Find

    Most cloud providers ask for a credit card even on free tiers because it deters abuse — spam, crypto mining, and DDoS launch points are common problems with genuinely anonymous free compute. That’s why services like DigitalOcean, Linode, and Vultr typically require card verification even for trial credit, despite offering low entry prices once you do sign up.

    When you do find free VPS hosting no credit card offers, they usually fall into a few categories:

  • Free-tier cloud instances that only skip the card requirement for a short trial window
  • Community or educational programs (student packs, hackathon credits) with eligibility restrictions
  • Extremely limited-resource “forever free” tiers (shared CPU, capped bandwidth, no root access in some cases)
  • Sandbox/playground environments meant for learning, not hosting real workloads
  • Understanding which category a provider falls into will save you time before you commit to setting anything up.

    Realistic Expectations for Resource Limits

    Even when a provider genuinely offers free VPS hosting no credit card, expect modest specs: often 512MB-1GB RAM, a single shared vCPU, and a small amount of SSD storage. These boxes are fine for learning Linux administration, running a lightweight Node.js or Python service, or testing a Docker container — they are not suitable for production traffic, database-heavy workloads, or anything with uptime guarantees you actually depend on.

    Common Catches to Watch For

    Read the terms before you provision anything. Common restrictions on free VPS hosting no credit card offers include:

  • Automatic account suspension after a fixed number of days
  • No SLA and no guaranteed uptime
  • Restricted outbound ports (mail servers and certain proxy uses are frequently blocked)
  • IP addresses that are already on shared blocklists due to prior abuse by other free-tier users
  • Evaluating Providers Before You Sign Up

    Not every listing that promises “no credit card” is trustworthy, and some sites collect other personal data instead — phone number verification, ID uploads, or aggressive marketing opt-ins. Treat any offer of free VPS hosting no credit card the same way you’d treat any other unfamiliar signup: check for a real support channel, a clear terms-of-service page, and reviews outside the provider’s own marketing site.

    Checking for Root Access and SSH

    A VPS that doesn’t give you root/sudo access and SSH is really just managed hosting with extra steps. Before signing up, confirm the provider explicitly states you’ll get:

  • Full root or sudo access
  • SSH key-based login (not just a web console)
  • A public IP address you can bind services to
  • If any of these are missing, it may still be useful for learning, but it isn’t a general-purpose VPS in the way most developers mean the term.

    Verifying the Provider Isn’t a Resale Scheme

    Some “free VPS” listings are unauthorized resellers running services on top of a legitimate provider’s infrastructure, in violation of that provider’s terms. This is a real risk: your instance can disappear without notice if the underlying account gets suspended. Stick to providers that are transparent about how they fund the free tier — advertising, a freemium upgrade path, or an explicit sponsorship (student programs, open-source grants) are healthier signals than vague claims.

    Setting Up Your Free VPS Securely

    Once you’ve provisioned a box, whether it’s genuinely free VPS hosting no credit card or a trial credit on a paid platform, the initial hardening steps are the same regardless of provider.

    Basic SSH and Firewall Configuration

    Start by disabling password authentication and restricting SSH to key-based login only. A minimal sshd_config change and a basic firewall rule set go a long way:

    # Generate a key pair locally if you don't have one
    ssh-keygen -t ed25519 -C "vps-key"
    
    # Copy your public key to the server
    ssh-copy-id user@your-server-ip
    
    # On the server: disable password auth
    sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
    sudo systemctl restart sshd
    
    # Enable a basic firewall (Ubuntu/Debian)
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable

    This is the same baseline hardening you’d apply on any Linux box, free or paid — see the official OpenSSH documentation for the full set of sshd_config options.

    Installing Docker on a Constrained Free VPS

    Given how limited free VPS hosting no credit card instances usually are on RAM, running services in lightweight containers is often more practical than installing everything directly on the host. The official Docker installation guide covers the exact steps per distribution; a typical Ubuntu install looks like this:

    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh get-docker.sh
    sudo usermod -aG docker $USER

    On a 512MB-1GB instance, keep an eye on memory usage — set explicit memory limits on containers so a single runaway process doesn’t crash the whole box:

    services:
      app:
        image: node:20-alpine
        deploy:
          resources:
            limits:
              memory: 256M
        ports:
          - "3000:3000"

    If you later outgrow the free tier and want persistent storage or multiple services, our guide on Docker Compose volumes and Docker Compose environment variables covers the next steps for a more durable setup.

    What to Actually Run on a Free, No-Card VPS

    Given the resource and reliability limits, free VPS hosting no credit card is best treated as a learning and prototyping environment rather than production infrastructure.

    Good Fits

  • Learning Linux server administration, systemd, and basic networking
  • Running a small self-hosted tool for personal use (a link shortener, a bookmark manager)
  • Testing a Docker Compose stack before deploying it somewhere more durable
  • Practicing CI/CD deployment scripts against a disposable target
  • Poor Fits

  • Anything customer-facing with an expected uptime commitment
  • Databases holding data you can’t afford to lose
  • Long-running background jobs that need guaranteed persistence
  • Mail servers (outbound port 25 is blocked on nearly every free tier)
  • Free VPS Hosting No Credit Card vs. Low-Cost Paid Alternatives

    If your project outgrows what a free, no-card instance can offer, the next step is usually a small paid VPS rather than chasing another free trial. Providers like DigitalOcean, Vultr, and Linode all offer entry-level droplets/instances priced low enough to be a reasonable next step once you’re comfortable committing a small monthly budget, and they come with the reliability, support, and full networking control that free tiers typically lack. If you’re weighing whether to stay on a free instance or move to unmanaged paid hosting, our unmanaged VPS hosting guide walks through what changes once you’re responsible for the full stack yourself.

    For projects that need automation glued together — scheduled jobs, webhooks, notifications — once you have a stable VPS (free or paid), tools like n8n self-hosted are worth exploring as a way to automate the operational side of your project.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Is truly free VPS hosting with no credit card required actually available?
    Yes, but it’s limited. A handful of providers offer genuinely free, no-card VPS instances, usually with small resource caps, no uptime guarantees, and time-limited or renewable trial periods. Treat these as learning environments rather than something to build a business on.

    Why do most cloud providers require a credit card even for free tiers?
    Card verification is primarily an anti-abuse measure. Free compute without any payment method attached is a common target for spam and mining abuse, so most established providers require a card even if you’re never actually charged during the free period.

    Can I self-host a real website on free VPS hosting no credit card?
    You can host a small, low-traffic personal project, but it’s not a good fit for anything with real visitors or uptime expectations. The lack of an SLA and the shared, often oversubscribed hardware behind free tiers make them unreliable for production sites.

    What happens when a free VPS trial expires?
    Depending on the provider, your instance may be suspended, deleted, or you’ll be prompted to add a payment method to continue. Always check the provider’s policy before deploying anything you’d be upset to lose, and keep backups of any configuration or data that matters.

    Conclusion

    Free VPS hosting no credit card options exist, but they come with real constraints: limited resources, no reliability guarantees, and terms that vary widely between providers. They’re genuinely useful for learning Linux administration, testing Docker Compose setups, and prototyping small projects — just go in with realistic expectations, harden SSH and your firewall immediately, and keep an eye on the provider’s terms so you’re not caught off guard when a trial period ends. When a project outgrows a free instance, moving to a low-cost paid VPS is usually a smoother path than hunting for the next free offer.

  • Build Applications With Ai Agents

    How to Build Applications With AI Agents: A DevOps 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.

    Teams that build applications with AI agents are shifting how software gets designed, tested, and shipped. Instead of writing every line of logic by hand, developers increasingly pair traditional code with autonomous or semi-autonomous agents that can reason over context, call tools, and take multi-step actions toward a goal. This guide walks through the practical architecture, infrastructure, and operational patterns you need to build applications with AI agents in a way that is maintainable, observable, and safe to run in production.

    This is not a theoretical overview. It’s written for engineers who already run Docker Compose stacks, manage VPS infrastructure, and think about uptime and logging as first-class concerns — because those same disciplines apply directly when you build applications with AI agents.

    What “Building Applications With AI Agents” Actually Means

    Before touching infrastructure, it helps to separate two very different things that both get called “AI agents”:

  • Tool-calling assistants — an LLM that receives a user request, decides which function/tool to call, executes it, and returns a result. Mostly stateless per request.
  • Autonomous agents — a process that maintains state across multiple steps, plans a sequence of actions, and can loop, retry, or escalate without a human in the loop for every decision.
  • Most production systems that build applications with AI agents actually combine both: a tool-calling layer handles individual actions (query a database, call an API, write a file), while an orchestration layer decides what sequence of tool calls achieves the broader goal.

    Core Components of an Agent-Based Application

    Regardless of framework, nearly every agent-based application has the same building blocks:

  • A model interface — the LLM API call itself, with prompt templates and structured output parsing.
  • A tool registry — a defined set of functions the agent is allowed to call, each with a schema.
  • A memory/state store — short-term (conversation context) and long-term (vector store, database) memory.
  • An orchestrator/loop — the code that decides “call the model again, call a tool, or stop.”
  • Guardrails — validation, rate limits, and permission boundaries around what the agent can actually do.
  • If you’re new to the agent concept itself, How to Create an AI Agent: A Developer’s Guide and Building AI Agents: A Practical DevOps Guide both cover the conceptual groundwork this article builds on.

    Choosing an Architecture Before You Build Applications With AI Agents

    A common mistake is picking a framework before deciding on an architecture. The framework is a detail; the architecture determines whether the system is debuggable six months from now.

    Single-Agent vs. Multi-Agent Design

    A single-agent design — one orchestrator, one set of tools, one model — is easier to reason about and should be the default starting point. Multi-agent systems (a “planner” agent delegating to “worker” agents) add real value only when tasks are genuinely parallelizable or require distinct specialized context windows. Multi-agent setups also multiply your debugging surface: every hop between agents is a place where context can be lost or misinterpreted, so don’t reach for one until a single agent has demonstrably hit its limits.

    Synchronous vs. Queue-Based Execution

    For anything beyond a simple chatbot, agent tasks should run through a queue rather than inline in an HTTP request. Long-running agent loops (multiple model calls, tool executions, retries) don’t belong in a request/response cycle with a client waiting on an open connection. A typical pattern:

  • API receives a request and writes a job record to a queue or database table.
  • A worker process picks up pending jobs, runs the agent loop, and writes results back.
  • The client polls or receives a webhook/notification when the job completes.
  • This is the same pattern used by workflow engines like n8n, and if you’re already running n8n for automation, it’s worth reading How to Build AI Agents With n8n: Step-by-Step Guide to see how a visual workflow tool can act as the orchestrator layer instead of custom code.

    Infrastructure to Build Applications With AI Agents Reliably

    Agent workloads have a different resource profile than typical web apps: unpredictable request duration, occasional need for GPU-backed inference (if self-hosting models), and heavier reliance on external API calls that can fail or rate-limit.

    Containerizing the Agent Runtime

    Package the agent runtime, its tool implementations, and its dependencies into a container so the execution environment is reproducible across dev, staging, and production. A minimal Docker Compose setup for an agent worker plus a queue and a database might look like this:

    version: "3.9"
    services:
      agent-worker:
        build: ./agent
        environment:
          - MODEL_API_KEY=${MODEL_API_KEY}
          - QUEUE_URL=redis://queue:6379
          - DATABASE_URL=postgres://agent:agent@db:5432/agent_state
        depends_on:
          - queue
          - db
        restart: unless-stopped
    
      queue:
        image: redis:7-alpine
        volumes:
          - redis_data:/data
    
      db:
        image: postgres:16-alpine
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agent_state
        volumes:
          - pg_data:/var/lib/postgresql/data
    
    volumes:
      redis_data:
      pg_data:

    If you need a deeper reference on the Postgres service definition, Postgres Docker Compose: Full Setup Guide for 2026 and Redis Docker Compose: The Complete Setup Guide cover configuration details worth applying here, including persistent volumes and health checks.

    Where to Host the Agent Stack

    A self-managed VPS gives you full control over networking, container runtime versions, and cost — important once you start running background agent workers continuously rather than just serving web requests. Providers like DigitalOcean and Vultr both offer VPS tiers suited to running a Docker Compose stack with an agent worker, a queue, and a database on a single instance for early-stage projects, scaling to multiple instances as load grows.

    Secrets and Environment Management

    Agent workers need API keys for the model provider and often for third-party tools (search APIs, email, CRM systems). Never hardcode these; store them in environment files excluded from version control, and if you’re managing several services with overlapping variables, Docker Compose Env: Manage Variables the Right Way and Docker Compose Secrets: Secure Config Management Guide both cover patterns for keeping credentials out of images and logs.

    Designing the Tool Layer

    The tools an agent can call are the actual boundary of what it can do to your systems and data. When you build applications with AI agents, this layer deserves more design attention than the prompt itself.

    Defining Tool Schemas

    Each tool should have an explicit schema — name, description, and typed parameters — so the model can reliably decide when and how to call it. Vague tool descriptions are one of the most common causes of agents calling the wrong function or passing malformed arguments.

    Limiting Blast Radius

    Give agents the narrowest permissions that let them do their job. A tool that “reads customer records” should not also have delete access. A tool that “writes to a staging table” should not be able to touch production data directly. This mirrors ordinary least-privilege practice in DevOps, and it matters more here because the caller (the model) is probabilistic, not deterministic — see AI Agent Security: A Practical Guide for DevOps for a closer look at this specific risk class.

    Observability When You Build Applications With AI Agents

    Standard application logging is necessary but not sufficient for agent systems. You also need visibility into the reasoning trace — which tools were called, in what order, with what arguments, and what the model’s intermediate outputs were.

    What to Log

  • Every model call: prompt, response, token usage, and latency.
  • Every tool invocation: tool name, arguments, result, and duration.
  • The final decision or output the agent produced, tied back to the originating request ID.
  • Any retries, fallbacks, or human-escalation events.
  • Structured logs (JSON lines) make this queryable later, and if your stack already runs Docker Compose, revisiting Docker Compose Logs: The Complete Debugging Guide or Docker Compose Logging: Complete Setup & Best Practices will help you wire agent logs into the same aggregation pipeline as the rest of your services rather than maintaining a separate system.

    Setting Cost and Latency Budgets

    Agent loops can call the model multiple times per request, and each call has real cost and latency. Set a hard cap on the number of loop iterations and a timeout per job so a misbehaving agent can’t spin indefinitely, consuming API quota or blocking a worker slot.

    # Example: enforce a max-iteration guard inside an agent worker script
    MAX_ITERATIONS=8
    iteration=0
    while [ "$iteration" -lt "$MAX_ITERATIONS" ]; do
      # run one step of the agent loop here
      iteration=$((iteration + 1))
    done

    Testing and Evaluating Agent Behavior

    Unlike deterministic code, an agent’s output can vary between runs given the same input. This changes how you approach testing.

    Golden-Path Test Cases

    Build a small set of representative tasks with known-good expected outcomes (not necessarily exact text matches, but structural checks: did it call the right tool, did it produce output in the right format). Run these against every prompt or model change before deploying.

    Human-in-the-Loop Review for High-Risk Actions

    For actions with real-world consequences — sending an email, modifying a database, making a purchase — insert a confirmation step rather than letting the agent act autonomously, at least until you have enough production evidence to trust the failure rate. This same caution shows up across customer-facing agent deployments; see Customer Service AI Agents: Self-Hosted Deployment Guide for how this plays out in a support context specifically.

    Deployment and Scaling Considerations

    Once the architecture is validated, scaling an agent application mostly follows familiar container-orchestration patterns, with a few agent-specific wrinkles.

    Horizontal Scaling of Workers

    Because agent jobs run through a queue, adding capacity is usually a matter of running more worker containers. Keep the worker process stateless with respect to job data — all state should live in the database or memory store, not in the worker’s local memory — so any worker can pick up any job.

    Rate Limiting Against the Model Provider

    Model APIs enforce rate limits per account or API key. As you scale worker count, make sure your queue consumer respects these limits (backoff and retry) rather than assuming unlimited throughput. This is a frequent source of production incidents when teams build applications with AI agents and scale workers faster than they adjust for upstream API limits.

    For general container orchestration references outside the AI-specific tooling, the Docker documentation and Kubernetes documentation both remain the authoritative sources for scaling patterns, health checks, and resource limits that apply equally to agent workers as to any other containerized service.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a specialized agent framework to build applications with AI agents?
    No. A framework can speed up development, but the core loop — call the model, parse its intended action, execute a tool, feed the result back — can be implemented directly against a model provider’s API. Start simple and adopt a framework only if it solves a concrete problem you’ve already hit.

    How do I prevent an agent from taking unintended destructive actions?
    Restrict the tool layer to the minimum permissions required, add explicit confirmation steps for high-risk actions, and log every tool call so you can audit behavior after the fact. Treat the agent’s tool access the same way you’d treat any external caller’s API permissions.

    Should agent workers run on the same VPS as my main application?
    For small workloads, yes — a single Compose stack with separate services is fine. As agent traffic grows, especially if it involves longer-running jobs or heavier API usage, separating the agent worker onto its own instance or service makes it easier to scale and monitor independently.

    How is building an application with AI agents different from just calling an LLM API in my backend?
    A simple LLM API call is a single request/response with no autonomy over subsequent steps. When you build applications with AI agents, the system itself decides which actions to take, in what order, and can loop or retry based on intermediate results — which requires the orchestration, tool, and observability layers described above.

    Conclusion

    Teams that build applications with AI agents successfully tend to treat the agent loop as just another service in their stack — containerized, queued, logged, and rate-limited like anything else — rather than as a mysterious black box bolted onto the side of an existing application. Start with a single-agent design, define a narrow and well-tested tool layer, log the full reasoning trace, and scale workers using the same container-orchestration patterns you already trust for other production services. The pattern is new, but the operational discipline it requires is not.

  • Ai Agents Developer

    What an AI Agents Developer Actually Builds: Tools, Infrastructure, and Real Workflows

    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.

    An ai agents developer is the person responsible for turning a language model into something that can actually act — call APIs, read databases, trigger deployments, and hand off work between systems — rather than just answer chat messages. This role sits at the intersection of software engineering, DevOps, and applied machine learning, and the day-to-day work looks a lot more like building and operating distributed systems than prompt-tuning a chatbot. This guide covers the tooling, infrastructure decisions, and operational patterns that define the job in 2026.

    The demand for this role has grown alongside the maturity of agent frameworks and orchestration tools, but the underlying discipline is not new. Anyone who has built a webhook-driven pipeline, managed a job queue, or debugged a flaky cron job already has half the skill set. What’s different is the addition of a non-deterministic component — the model itself — sitting in the middle of a system that otherwise needs to behave predictably.

    Core Responsibilities of an AI Agents Developer

    At a high level, the job breaks down into four recurring responsibilities, regardless of which framework or vendor stack a team has chosen.

  • Designing the agent’s decision loop — how it plans, calls tools, and decides when a task is complete
  • Wiring integrations (APIs, databases, internal services) the agent can safely call
  • Building guardrails: input validation, output validation, and hard stops for destructive actions
  • Operating the system in production: logging, monitoring, cost control, and incident response
  • None of these responsibilities are unique to “AI” work in isolation. What makes the role distinct is that the agent’s behavior is probabilistic, so testing and monitoring strategies have to account for output variance in a way traditional deterministic code doesn’t require.

    Decision Loops and Tool Calling

    Most production agents run some variant of a plan-act-observe loop: the model receives a goal and a set of available tools (functions), decides which tool to call, receives the result, and repeats until it determines the task is done or a stopping condition is hit. An ai agents developer needs to define that loop explicitly rather than trusting the model to self-terminate cleanly — unbounded loops are a common source of runaway API costs and are one of the first failure modes new teams hit in production.

    A minimal example of a tool-calling loop, expressed as pseudocode that many frameworks follow under the hood:

    # conceptual loop, not a specific framework's exact API
    while not task_complete and steps < max_steps:
      response = call_model(context, available_tools)
      if response.tool_call:
        result = execute_tool(response.tool_call)
        context.append(result)
      else:
        task_complete = True
      steps += 1

    The max_steps guard above is not optional in a production system — it’s the difference between a bounded, billable task and an agent that loops indefinitely against a paid API.

    Guardrails and Permission Boundaries

    Because an agent can trigger real side effects — sending an email, modifying a record, deploying code — permission boundaries need to be explicit at the tool level, not left to the model’s judgment. Common patterns include:

  • Read-only tools by default, with write/execute tools requiring a separate allow-list
  • A human-in-the-loop confirmation step for any action classified as destructive or irreversible
  • Rate limits and cost ceilings per agent run, enforced outside the model’s own reasoning
  • This is conceptually similar to the principle of least privilege in traditional systems administration, just applied to a component that can decide, at runtime, which of its available actions to take.

    Setting Up the Development Environment

    Before writing any agent logic, most developers need a reproducible local environment that mirrors production closely enough to catch integration issues early. Containerizing the agent and its dependencies is the standard approach.

    Containerizing the Agent Stack

    A typical agent stack includes the agent process itself, a vector store or database for retrieval, and sometimes a message queue for coordinating multi-agent workflows. Defining this as a multi-container setup keeps local development and production environments consistent — the same pattern covered in general terms in guides comparing Dockerfile vs Docker Compose approaches.

    A minimal docker-compose.yml for an agent plus a Postgres-backed memory store might look like:

    version: "3.9"
    services:
      agent:
        build: .
        environment:
          - MODEL_API_KEY=${MODEL_API_KEY}
          - DATABASE_URL=postgres://agent:agent@db:5432/agent_memory
        depends_on:
          - db
      db:
        image: postgres:16
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agent_memory
        volumes:
          - agent_db_data:/var/lib/postgresql/data
    volumes:
      agent_db_data:

    For teams that need a deeper reference on the database side of this setup, a dedicated Postgres Docker Compose guide covers volume persistence and connection tuning in more detail than fits here.

    Managing Secrets and Configuration

    Agent stacks tend to accumulate more API keys than a typical web app — one for the model provider, one for each external tool the agent can call, and often separate keys per environment. Keeping these out of version control and out of plain environment files where possible is a baseline requirement, not a nice-to-have, since a leaked key on an agent with write access to production systems is a materially worse incident than a leaked key on a read-only service. A dedicated look at Docker Compose secrets management is worth reading before wiring credentials into any agent container, and general Docker Compose environment variable handling applies directly here too.

    Choosing an Agent Framework or Building From Scratch

    There are two broad paths an ai agents developer takes on a new project: adopt an existing agent framework, or build the orchestration logic directly against a model provider’s API.

    When to Use an Existing Framework

    Frameworks handle the plumbing — tool-call parsing, memory management, retry logic — so a team doesn’t reimplement it per project. This is usually the right default for teams shipping their first agent, since the plan-act-observe loop, error handling for malformed tool calls, and conversation state management are easy to get subtly wrong on a first attempt. Detailed comparisons of the underlying decision, including trade-offs between “agentic AI” as a general pattern versus a specific agent implementation, are covered in a broader guide on agentic AI tools.

    When to Build Custom Orchestration

    Custom orchestration makes sense once a team has specific latency, cost, or compliance requirements that a general-purpose framework doesn’t accommodate well — for example, needing to log every intermediate reasoning step to an internal audit system in a specific schema, or needing tight control over retry behavior for a rate-limited internal API. Teams evaluating whether to build agent logic on top of an existing low-code automation platform instead of writing bespoke orchestration code often start from a workflow-automation angle; a guide on how to build AI agents with n8n walks through that specific path, and a broader comparison of n8n vs Make is useful context if the team hasn’t settled on an orchestration platform yet.

    Infrastructure and Deployment Considerations

    Once an agent works locally, deploying it reliably introduces a different set of concerns than deploying a stateless web service, mainly because agent runs can be long-lived and their resource usage is harder to predict up front.

    Compute Sizing and Hosting

    Agent workloads are often bursty — idle most of the time, then briefly CPU- and memory-intensive during a multi-step tool-calling run. A VPS with burstable performance characteristics is frequently more cost-effective than committing to a large fixed instance, at least for early-stage or moderate-traffic deployments. Providers like DigitalOcean and Vultr both offer VPS tiers that work well for this kind of variable load, and Hetzner is a common choice when cost-per-core is the primary constraint. For teams running an unmanaged setup, a general unmanaged VPS hosting guide covers the baseline responsibilities that come with self-managing the box an agent runs on.

    Logging, Observability, and Cost Tracking

    Because agent behavior is non-deterministic, standard application logs aren’t enough — teams typically need to log the full sequence of model calls, tool calls, and intermediate reasoning for every run, not just errors. This is what makes post-incident debugging possible: reconstructing why an agent chose a particular tool call requires the actual transcript, not just a stack trace. Cost tracking deserves the same rigor, since a single misbehaving agent loop can consume a meaningful chunk of a monthly model API budget in hours if the step limit is misconfigured.

    Common Failure Modes and How to Guard Against Them

    Most production incidents involving agents fall into a small number of recurring categories:

  • Infinite or near-infinite tool-calling loops — mitigated with hard step limits and per-run cost ceilings
  • Hallucinated tool arguments (e.g., a fabricated file path or record ID) — mitigated by validating tool inputs before execution, never trusting the model’s output as pre-sanitized
  • Silent partial failures — an agent reports success after only completing part of a multi-step task, usually caught by requiring explicit verification steps rather than trusting the model’s own “done” signal
  • Credential overreach — an agent tool has broader permissions than the task requires, which turns a minor hallucination into a real incident
  • Building automated checks around these failure modes — rather than relying on manual review of agent transcripts — is what separates a reliable production agent from a demo. The same discipline used for Docker Compose logging practices in traditional services applies directly to capturing agent run transcripts for later review.

    Testing and Iterating on Agent Behavior

    Testing agents is harder than testing traditional code because the same input can produce different valid outputs across runs. Effective approaches usually combine three layers:

    Deterministic Unit Tests for Tools

    Every tool an agent can call should have standard unit tests, independent of the model entirely. If a tool that queries a database or hits an internal API is broken, no amount of prompt engineering will fix the resulting agent behavior — so this layer should be tested exactly like any other piece of application code.

    Scenario-Based Evaluation

    Beyond unit tests, teams typically maintain a set of representative scenarios (a fixed input, an expected class of outcome) and re-run them whenever the prompt, model version, or tool set changes. This catches regressions that wouldn’t show up in a quick manual check, and it’s the closest equivalent agents have to a regression test suite.

    Staged Rollouts

    Rolling out a new agent version to a small percentage of real traffic before a full rollout, combined with close monitoring of tool-call error rates and cost per run, catches issues that scenario testing misses — particularly around edge cases in real user input that a curated test set didn’t anticipate.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a specific framework to become an ai agents developer, or can I use any language?
    No specific framework is required. The core skills — tool-calling loop design, guardrails, and production monitoring — transfer across frameworks and even across languages. Most teams pick a framework based on their existing stack and the maturity of its tool-calling and memory-management support, referenced in the framework comparisons above.

    How is an ai agents developer different from a machine learning engineer?
    A machine learning engineer is typically focused on training, fine-tuning, or evaluating models themselves. An ai agents developer usually works with an existing model (often via API) and focuses on the surrounding system: orchestration, tool integration, guardrails, and production operations — closer to backend/DevOps engineering than to model research.

    What’s the biggest infrastructure mistake teams make when deploying their first agent?
    Skipping hard limits on tool-call loops and cost ceilings. An agent that works fine in a demo can rack up unexpectedly high API costs in production if a step limit isn’t enforced, especially when the agent encounters an edge case it wasn’t tested against.

    Can agent workloads run on a small VPS, or do they need dedicated GPU infrastructure?
    Most agent orchestration workloads are CPU/network-bound, not GPU-bound, since the model inference itself typically happens via an external API call rather than locally. A standard VPS is sufficient for the orchestration layer; GPU infrastructure is only necessary if a team is self-hosting the underlying model as well.

    Conclusion

    Becoming an effective ai agents developer means treating agent systems as production infrastructure from day one — with the same discipline around testing, observability, and permission boundaries that any reliable distributed system requires, plus additional guardrails for the non-deterministic component sitting in the middle of it. The frameworks and model providers will keep changing, but the underlying job — building tool integrations, enforcing safe boundaries, and operating the system reliably once it’s live — stays consistent. Teams that treat agent development as “just prompting” tend to hit reliability and cost problems quickly; teams that treat it as systems engineering with an unusual component tend to ship something that survives contact with real traffic. For further reading on the orchestration side of this work, the Kubernetes vs Docker Compose comparison is a useful next step once an agent stack outgrows a single-host deployment, and the official Docker documentation and Kubernetes documentation remain the most reliable references for the underlying container orchestration primitives this work depends on.

  • Build Ai Agents From Scratch

    How to Build AI Agents From Scratch: A DevOps Deployment 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.

    If you want to build AI agents from scratch instead of relying on a closed-source framework, you need to understand three things: how an agent reasons about the next action, how it calls tools, and how you actually deploy and monitor that process in production. This guide walks through the architecture, the code, and the operational side of the problem — the parts most tutorials skip once the demo works on a laptop.

    Most articles about agents stop at “call an LLM in a loop.” That’s a fine starting point, but it isn’t a system you can run reliably. Below we cover the core loop, tool execution, state management, deployment with Docker, and the observability you need once the agent is doing real work against real APIs.

    Why Build AI Agents From Scratch Instead of Using a Framework

    Frameworks like LangChain or CrewAI are useful when you want to move fast and don’t mind the abstraction overhead. But there are good reasons teams choose to build ai agents from scratch instead:

  • Full control over the reasoning loop — no hidden retries, no opaque prompt templates you have to reverse-engineer.
  • Smaller dependency surface, which matters a lot when you’re running this in a container with a strict resource budget.
  • Easier debugging, since every step of the loop is code you wrote and can log, trace, and test.
  • No lock-in to a specific framework’s versioning cadence, which can break your agent overnight on an upgrade.
  • That doesn’t mean frameworks are bad — for many teams they’re the right tradeoff. But if you’re a DevOps engineer who wants to understand exactly what’s happening between a user prompt and an API call, building the loop yourself is the fastest way to actually learn how these systems work, and it gives you a codebase you fully own.

    The Core Agent Loop

    At its simplest, an agent is a loop: observe the current state, ask a model what to do next, execute that action, and feed the result back in. When you build ai agents from scratch, this loop is the one piece of code you’ll spend the most time refining.

    def agent_loop(goal, tools, model_client, max_steps=10):
        history = [{"role": "user", "content": goal}]
        for step in range(max_steps):
            response = model_client.chat(history, tools=tools)
            if response.tool_call is None:
                return response.content  # final answer
            result = execute_tool(response.tool_call, tools)
            history.append({"role": "assistant", "content": response.tool_call})
            history.append({"role": "tool", "content": result})
        return "Max steps reached without a final answer."

    This is intentionally minimal. No retries, no memory compression, no parallel tool calls — just the skeleton. Everything else in this article builds on top of it.

    Choosing a Model Provider

    You don’t need to commit to one provider forever, but you do need a consistent interface. Most people who build ai agents from scratch start with the OpenAI API or Anthropic’s API because both have mature tool-calling support and clear documentation. Whichever you pick, isolate the provider-specific code behind a thin client class so you can swap models without rewriting your loop.

    Designing the Tool Layer

    Tools are what separate an agent from a chatbot. A tool is any function the model can request to be executed — searching the web, querying a database, hitting an internal API, or writing a file. When you build ai agents from scratch, the tool layer is where most of the real engineering effort goes, not the prompt.

    Each tool needs three things: a machine-readable schema (so the model knows it exists and what arguments it takes), an execution function, and error handling that returns something useful back into the loop rather than crashing it.

    TOOLS = [
        {
            "name": "get_weather",
            "description": "Get current weather for a city",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        }
    ]
    
    def execute_tool(tool_call, tools):
        try:
            if tool_call.name == "get_weather":
                return fetch_weather(tool_call.arguments["city"])
            return f"Unknown tool: {tool_call.name}"
        except Exception as e:
            return f"Tool error: {str(e)}"

    Guardrails on Tool Execution

    Never let an agent call a tool with unbounded permissions. If a tool can write to a filesystem, delete records, or spend money, put an explicit allowlist and a confirmation step in front of it. A reasonable pattern is to classify each tool as read-only or mutating, and require a human-in-the-loop confirmation for anything mutating until you’ve built enough confidence in the agent’s behavior to relax that.

  • Read-only tools (search, lookup, calculation) can run automatically.
  • Mutating tools (writes, deletes, payments, outbound messages) should require explicit confirmation or a dry-run mode first.
  • Every tool call and its result should be logged with a timestamp and the triggering prompt for later audit.
  • Rate Limiting and Timeouts

    An agent stuck in a loop calling a slow external API can silently rack up cost and latency. Wrap every tool call with a timeout, and cap the number of tool calls per session. This is a small amount of code that prevents most of the runaway-cost incidents teams run into once an agent goes from a demo to something users actually invoke repeatedly.

    Managing State and Memory

    A single-session agent loop is easy. The harder problem when you build ai agents from scratch is state that persists across sessions — remembering what a user asked yesterday, or tracking the status of a long-running multi-step task.

    For most use cases you don’t need a vector database on day one. A simple relational table tracking session_id, role, content, and timestamp is enough to reconstruct conversation history. Only reach for embeddings and semantic search once you have a concrete need to retrieve relevant history that a simple recency window can’t satisfy.

    Trimming Context Without Losing Intent

    As conversations grow, you’ll exceed the model’s context window or just waste tokens on irrelevant history. A common approach is to keep the last N full turns verbatim and summarize everything older into a single condensed block, re-injected at the top of the history. This keeps token usage predictable while preserving enough context for the agent to stay coherent across a long session.

    Build AI Agents From Scratch: Deployment With Docker

    Once the loop and tool layer work locally, the next step is packaging the agent so it runs reliably outside your laptop. This is the part of “build ai agents from scratch” that most tutorials skip entirely, and it’s where a DevOps background actually pays off.

    A minimal agent service needs: the agent process itself, a way to receive triggers (webhook, queue, or scheduler), and persistent storage for state. Docker Compose is a reasonable starting point for a single-host deployment before you need anything like Kubernetes.

    version: "3.9"
    services:
      agent:
        build: .
        restart: unless-stopped
        environment:
          - MODEL_API_KEY=${MODEL_API_KEY}
          - DATABASE_URL=postgres://agent:agent@db:5432/agent
        depends_on:
          - db
        ports:
          - "8080:8080"
      db:
        image: postgres:16
        restart: unless-stopped
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agent
        volumes:
          - agent_pgdata:/var/lib/postgresql/data
    volumes:
      agent_pgdata:

    If you’re new to the Compose file format itself, the Postgres Docker Compose setup guide and the Docker Compose Env guide cover the surrounding details — secrets handling, environment variable precedence, and volume persistence — that this snippet assumes you already know.

    Running the Agent as a Long-Lived Service

    If your agent needs to poll a queue or run on a schedule rather than respond to a single webhook, wrap the loop in a service with a clear retry policy and restart behavior. Docker’s restart: unless-stopped covers crash recovery, but you still need your own logic for “what happens if the model API is down for five minutes” — usually an exponential backoff with a cap, rather than a tight retry loop that burns through your rate limit.

    For teams that don’t want to write this orchestration layer themselves, it’s worth comparing against a visual workflow tool. The guide on how to build AI agents with n8n shows the same core loop implemented as a workflow instead of raw code — useful context even if you ultimately decide to build ai agents from scratch in your own codebase, since it clarifies which parts of the problem are genuinely hard versus just boilerplate.

    Hosting Considerations

    Wherever you run this, you want predictable CPU and a static IP for outbound webhook calls. A small VPS is enough for most single-agent workloads — you don’t need a Kubernetes cluster until you’re running many agents concurrently or need horizontal autoscaling. Providers like DigitalOcean offer straightforward droplet sizing if you want to start with a single box before deciding whether to scale out.

    Observability and Debugging

    An agent that fails silently is worse than one that crashes loudly. Every production agent needs structured logging of the full decision trace: the prompt sent, the tool selected, the arguments, the result, and the final output. Without this, debugging a bad decision means guessing.

    Log each step as a structured event rather than free text, so you can query it later:

    echo '{"session_id":"abc123","step":2,"tool":"get_weather","args":{"city":"Berlin"},"result":"12C, cloudy"}' 
      | tee -a agent_trace.jsonl

    A JSONL trace file like this is a low-effort starting point. As the system matures, ship these events to a real log aggregator so you can search and alert on patterns like repeated tool failures or sessions that hit max_steps without resolving.

    Testing the Agent Loop

    Unit-test the tool functions in isolation — they’re regular functions, so this is straightforward. For the loop itself, write scenario tests that feed a scripted sequence of model responses (mocked, not live API calls) and assert the loop takes the expected path. This catches regressions in your control flow without burning API credits on every test run, and it’s the same testing discipline you’d apply to any other stateful service.

    Common Pitfalls When You Build AI Agents From Scratch

    A few mistakes show up repeatedly in early agent implementations:

  • No upper bound on loop iterations, leading to runaway cost when the model gets stuck in a reasoning loop.
  • Tool errors returned as exceptions instead of structured results, which crashes the whole session instead of letting the agent recover.
  • Secrets (API keys, database credentials) hardcoded instead of injected via environment variables — see the Docker Compose Secrets guide for a cleaner pattern.
  • No idempotency on mutating tool calls, so a retried step can duplicate a side effect like sending a message twice.
  • Treating the model’s tool-call arguments as fully trusted input instead of validating them before execution, which is effectively the same class of bug as trusting unvalidated user input in a web app.
  • Keeping these in mind from the start saves a rewrite later. Most of them are standard software engineering discipline — logging, validation, idempotency — applied to a system where one of the callers happens to be a language model instead of a human.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    Choosing a Memory Strategy

    An agent without memory re-derives everything from scratch on every call, which is expensive and limits what it can do across a multi-turn conversation. There are two broad memory tiers worth separating:

  • Short-term (conversation) memory — the running message history for the current session. Simplest option: keep it in a list in application memory or a Redis key, trimmed or summarized once it exceeds a token budget.
  • Long-term (knowledge) memory — facts, documents, or past interactions the agent should recall across sessions. Typically backed by a vector database or a relational store with full-text search.
  • Persisting State With Redis or Postgres

    For most self-hosted setups, Redis is a good fit for short-term session state because it’s fast and simple to run alongside your agent process. If you’re already running a Docker Compose stack, our Redis Docker Compose setup guide covers the exact service definition you’ll need. For long-term memory that needs relational queries or joins against other application data, Postgres is a solid default — see the Postgres Docker Compose guide for a working configuration.

    A minimal docker-compose.yml combining both, alongside the agent service itself, looks like this:

    services:
      agent:
        build: .
        environment:
          - OPENAI_API_KEY=${OPENAI_API_KEY}
          - REDIS_URL=redis://redis:6379
          - DATABASE_URL=postgresql://agent:agent@postgres:5432/agent
        depends_on:
          - redis
          - postgres
    
      redis:
        image: redis:7-alpine
        restart: unless-stopped
    
      postgres:
        image: postgres:16-alpine
        restart: unless-stopped
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agent
        volumes:
          - pgdata:/var/lib/postgresql/data
    
    volumes:
      pgdata:

    If you need to manage secrets like your OPENAI_API_KEY more carefully than a plain .env file allows, our Docker Compose secrets guide walks through the options.

    Deployment and Infrastructure Choices

    Once the agent logic works locally, you need somewhere reliable to run it. This is where a lot of “from scratch” projects stall — not because the agent code is wrong, but because the deployment story was never planned.

    Picking a VPS and Sizing It Correctly

    An LLM-calling agent is usually not CPU-bound (the model runs remotely via API), so you don’t need a large instance unless you’re also running local embeddings or a vector database with a heavy index. A small, unmanaged VPS is often enough for the agent process itself. DigitalOcean and Vultr both offer straightforward droplet/instance sizing if you want a starting point, and our unmanaged VPS hosting guide covers what “unmanaged” actually means for day-to-day maintenance.

    If you expect to scale the agent horizontally later (multiple workers pulling from a shared task queue), it’s worth sizing for that from day one rather than re-architecting under load.

    Logging, Debugging, and Observability

    Agent behavior is nondeterministic by nature — the same input can produce a different tool-call sequence on different runs. That makes logging non-negotiable. At minimum, log every model call’s input, the chosen tool, the tool’s result, and the final response. If you’re running the agent inside Docker Compose, the Docker Compose logs debugging guide and the related Docker Compose logging guide cover how to keep those logs queryable without them growing unbounded.

  • Log structured JSON, not free text, so you can filter by session ID or tool name later
  • Set a hard step limit on the agent loop (as shown above) to prevent runaway token spend from an infinite tool-calling cycle
  • Capture latency per step so you can tell whether slowness comes from the model call or your own tool code
  • FAQ

    Do I need a framework to build AI agents from scratch?
    No. A framework can save time on boilerplate, but the core loop — call model, execute tool, feed result back — is a few dozen lines of code. Many teams choose to build ai agents from scratch specifically to avoid framework lock-in and keep the reasoning loop fully inspectable.

    How many tools should a single agent have?
    Keep it focused. An agent with a large, unfocused tool list tends to make worse tool-selection decisions than one with a small, well-described set. Start with the minimum set needed for the task and add tools only when there’s a clear gap.

    How do I prevent an agent from taking destructive actions?
    Classify tools as read-only or mutating, and require explicit confirmation or a dry-run step before any mutating tool executes. Log every tool call so you can audit what happened after the fact.

    Should I run the agent on a VPS or a serverless platform?
    Either works. A VPS with Docker Compose is simpler to reason about and debug for a single agent or small fleet. Serverless makes more sense once you have bursty, infrequent invocations where paying for an always-on container doesn’t make sense.

    Conclusion

    Learning to build ai agents from scratch means understanding the reasoning loop, the tool execution layer, state management, and the deployment and observability work that turns a demo into a system you can trust. None of these pieces are individually complex, but skipping any of them — especially guardrails on tool execution and structured logging — is what turns an agent from a useful automation into a production incident. Start with the minimal loop shown here, add tools deliberately, and invest in tracing early; it’s far easier to build that discipline in from the start than to retrofit it once the agent is already handling real traffic. For deeper reference on the model side, the Anthropic API documentation and OpenAI API documentation are both good starting points once your own loop is solid enough to plug either provider into.

  • Building Ai Agent From Scratch

    Building AI Agent From Scratch: A Practical Engineering 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.

    Building an AI agent from scratch is less about picking a fashionable framework and more about designing a reliable control loop: something that observes state, decides on an action, executes it, and checks the result. This guide walks through the architecture, tooling, and deployment decisions involved in building AI agent from scratch systems that hold up outside of a demo notebook, with a focus on the parts most tutorials skip: state management, tool execution safety, and running the thing in production on your own infrastructure.

    Most public tutorials show you how to call a chat completion endpoint in a loop and call it an “agent.” That’s a fine starting point, but it isn’t durable. A real agent needs persistent memory, a defined action space, error handling for tool failures, and observability so you know why it did what it did. If you’re building ai agent from scratch for a real workload — customer support triage, DevOps automation, content pipelines — you need to treat it like a distributed system component, not a script.

    Why Building AI Agent From Scratch Beats Using a Black-Box Platform

    There are plenty of no-code and low-code agent builders on the market. They’re useful for prototyping, but they trade away control: you can’t easily inspect the reasoning trace, swap the underlying model, or self-host the runtime next to your data. Building ai agent from scratch gives you three things a managed platform usually can’t:

  • Full control over the prompt, context window, and tool schema
  • The ability to run entirely on infrastructure you own, which matters for data residency and cost predictability
  • No vendor lock-in on the orchestration layer, so you can swap model providers without rewriting your application
  • This doesn’t mean you should avoid frameworks entirely. Libraries that handle tool-calling boilerplate and conversation state can save real time. The distinction that matters is between using a library as a component versus outsourcing your entire architecture to a hosted black box you can’t debug.

    When a Framework Is the Right Call

    If your team already has infrastructure experience with workflow engines, tools like n8n can meaningfully speed up the plumbing around an agent — webhook triggers, retries, scheduling — while you keep the actual reasoning loop in code you control. Our guide on how to build AI agents with n8n covers that hybrid approach in detail, and it pairs well with the from-scratch architecture described here for the parts that genuinely don’t need to be custom-built.

    When to Write Everything Yourself

    If your agent needs tight latency, custom tool-calling logic that doesn’t map cleanly onto an existing framework’s abstractions, or has to run inside an existing codebase with specific security constraints, writing it from scratch in your primary language (Python is the common choice) keeps the surface area small and auditable.

    Core Architecture for Building AI Agent From Scratch Projects

    At minimum, a functioning agent needs four components: a state store, a planning/reasoning step, a tool executor, and a feedback loop that feeds results back into the next reasoning step.

    The Reasoning Loop

    The reasoning loop is the part most people mean when they say “agent.” It’s a function that takes the current context (conversation history, tool results, system instructions) and produces either a final answer or a tool call. The loop terminates when the model produces a final answer instead of another tool call, or when you hit a hard iteration limit — always set one, since an unbounded loop against a paid LLM API is a real cost risk.

    A minimal loop looks like this in pseudocode:

    def run_agent(user_input, max_iterations=8):
        context = [{"role": "user", "content": user_input}]
        for _ in range(max_iterations):
            response = call_model(context, tools=TOOL_SCHEMA)
            if response.tool_call is None:
                return response.content
            result = execute_tool(response.tool_call)
            context.append({"role": "assistant", "content": response.raw})
            context.append({"role": "tool", "content": result})
        return "Max iterations reached without a final answer."

    This is intentionally bare. In production you’d add structured logging around every iteration, timeout handling per tool call, and a way to short-circuit on repeated identical tool calls (a common failure mode where the model gets stuck retrying the same failing action).

    Tool Definition and Execution

    Tools are the agent’s action space. Each tool needs a name, a schema describing its arguments, and a handler function. Keep the schema strict — the fewer degrees of freedom the model has to misuse a tool, the fewer failure modes you have to handle.

    A practical pattern is to validate tool arguments against a schema before execution, reject anything that doesn’t match, and return the validation error back into the context so the model can self-correct on the next turn rather than crashing the whole run.

    State and Memory Management

    Short-term memory is just the running conversation context, bounded by your model’s context window. Long-term memory — things the agent should recall across sessions — needs external storage. A simple key-value store or a lightweight database is usually enough; you don’t need a vector database unless you’re doing semantic retrieval over a large, unstructured corpus.

    Choosing an Execution Environment for Building AI Agent From Scratch Workloads

    Once the code works locally, the next decision is where it runs. Agents that call external tools, hit rate-limited APIs, or run on a schedule need a persistent environment, not a laptop.

    Containerizing the Agent

    Packaging the agent as a Docker container makes the deployment reproducible and keeps dependencies isolated from the host. A minimal setup mounts your API keys as environment variables rather than baking them into the image, and separates the agent process from anything stateful it depends on (a database, a queue) via Docker Compose:

    services:
      agent:
        build: .
        restart: unless-stopped
        environment:
          - MODEL_API_KEY=${MODEL_API_KEY}
        depends_on:
          - agent_db
    
      agent_db:
        image: postgres:16
        restart: unless-stopped
        environment:
          - POSTGRES_PASSWORD=${DB_PASSWORD}
        volumes:
          - agent_db_data:/var/lib/postgresql/data
    
    volumes:
      agent_db_data:

    If you’re new to the Compose file format or want a refresher on managing environment variables safely across services, see our guides on Docker Compose env handling and Docker Compose secrets management — both directly apply here, since an agent’s API keys and tool credentials are exactly the kind of secret that shouldn’t end up hardcoded in a Compose file. If you need to debug why a container won’t start, the Docker Compose logs guide covers the full debugging workflow.

    Self-Hosting vs. Managed Runtimes

    Running your own VPS gives you predictable costs and full control over the runtime, which matters once you’re running an agent continuously rather than in short bursts. Providers like DigitalOcean and Hetzner offer straightforward VPS instances that are more than sufficient for an agent process plus a small database — you don’t need GPU instances unless you’re self-hosting the model itself rather than calling an API.

    Handling Errors and Failure Modes

    An agent that silently fails is worse than one that fails loudly. The most common failure modes in production agents are: the model calling a tool with malformed arguments, a tool timing out or returning an error, the model looping on the same failed action, and context window overflow on long-running conversations.

    Retry and Backoff for Tool Calls

    Wrap every external tool call — HTTP requests, database queries, API calls to other services — in a retry with exponential backoff, and cap the total retry time so a single flaky dependency doesn’t stall the whole agent loop indefinitely. Distinguish between retryable errors (timeouts, 5xx responses) and non-retryable ones (validation errors, 4xx responses) so you’re not wasting cycles retrying something that will never succeed.

    Guarding Against Runaway Loops

    Beyond a hard iteration cap, track whether the agent’s last N tool calls are identical. If they are, break the loop and return an explicit failure message rather than letting the model keep spinning — this is both a cost control and a reliability safeguard.

    Observability and Testing for Building AI Agent From Scratch Systems

    You cannot debug an agent you can’t see inside of. Log every reasoning step, every tool call and its arguments, and every tool result, with a correlation ID tying a full run together. This is the same discipline used for any distributed system — the Docker Compose logging guide covers structured logging patterns that transfer directly to agent runtimes.

    Testing the Reasoning Loop

    Unit test your tool handlers directly — they’re regular functions and should be tested like any other code. For the reasoning loop itself, build a small set of fixed scenarios with known-good expected tool call sequences, and run them against a pinned model version whenever you change the system prompt or tool schema. Prompt changes are a common source of silent regressions, and without a regression suite you won’t catch them until a real user does.

    Monitoring in Production

    Track latency per iteration, total iterations per run, tool error rates, and token usage. A sudden spike in average iterations per run is often the first sign that a recent prompt change introduced ambiguity the model is struggling to resolve.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a specialized agent framework to get started building AI agent from scratch?
    No. A framework can reduce boilerplate around tool-calling and conversation state, but the core loop — call model, execute tool, feed result back — is straightforward enough to write directly in Python or another general-purpose language. Start without a framework; add one later if the boilerplate becomes a real burden.

    What’s the minimum infrastructure needed to run an agent in production?
    A single VPS running the agent process in a container, plus a small database for state, is enough for most workloads. You don’t need Kubernetes or a GPU instance unless you’re self-hosting the underlying model or handling very high request volume.

    How do I prevent an agent from calling the same tool in an infinite loop?
    Cap the total number of reasoning iterations per run, and separately detect repeated identical tool calls so you can break out and return an explicit error rather than letting the loop continue silently.

    Should I use Docker Compose or a single Dockerfile for an agent project?
    Use Docker Compose once your agent depends on anything stateful, like a database or a queue — it’s the standard way to define and start multiple related services together. Our Dockerfile vs. Docker Compose comparison covers the tradeoff in more depth if you’re deciding between the two for a smaller project.

    Conclusion

    Building AI agent from scratch is a solvable engineering problem once you treat it like one: a bounded reasoning loop, a strictly defined tool schema, persistent state, and real observability. The reasoning loop itself is a small amount of code — the bulk of the engineering effort goes into making tool execution safe, handling failures gracefully, and deploying the result somewhere reliable. Start with the minimal loop shown above, containerize it early, and add framework components only where they save real time rather than because they’re popular. For deeper reference on the underlying model APIs, the OpenAI API documentation and the Anthropic API documentation are both good starting points for the tool-calling and structured-output features these architectures depend on.

  • Building Ai Agents From Scratch

    Building AI Agents From Scratch: A Practical DevOps 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.

    Building AI agents from scratch is one of the most common requests DevOps and platform teams get once large language models move from a demo into something people actually want running in production. This guide walks through the architecture, infrastructure, and operational decisions involved in building AI agents from scratch — without relying on a heavyweight no-code platform — so you understand exactly what you’re deploying and why.

    Most tutorials on this topic either hand-wave the infrastructure (“just call the API”) or over-engineer a toy example into something unmaintainable. This article splits the difference: it treats an agent as a normal piece of backend software with a scheduler, a state store, and a set of tools, then shows how to wire those pieces together and run them reliably on a VPS.

    What “Building AI Agents From Scratch” Actually Means

    Before writing code, it helps to define the term precisely. An AI agent, in the practical engineering sense, is a loop: it receives an input, decides on an action (call a tool, ask a clarifying question, or respond), executes that action, observes the result, and repeats until it reaches a stopping condition. Building AI agents from scratch means you own every part of that loop — the prompt construction, the tool-calling logic, the state management, and the deployment — rather than delegating it to a hosted agent-builder product.

    This distinction matters operationally. A hosted platform trades control for convenience: you get a faster start but inherit its rate limits, its logging model, and its outage schedule. When you build AI agents from scratch, you decide how requests are queued, how failures are retried, and where the data lives. For teams already running Docker-based infrastructure, this is usually the more maintainable long-term choice.

    Core Components of a From-Scratch Agent

    At minimum, an agent built this way needs:

  • A model client — an HTTP client wrapping calls to an LLM provider’s API, with retry and timeout handling.
  • A tool registry — a set of functions the model can invoke (web search, database query, shell command, API call), each with a defined input/output schema.
  • A state store — somewhere to persist conversation history, task status, and intermediate results (Redis or Postgres are both reasonable choices).
  • An orchestration loop — the code that decides when to call the model again, when a tool result satisfies the task, and when to stop.
  • A runtime — the process (or container) that actually keeps this loop alive and exposes it via a queue, webhook, or scheduled job.
  • If you’re comparing this manual approach against a workflow-automation tool, it’s worth reading How to Build AI Agents With n8n first — n8n handles the orchestration loop and tool registry for you at the cost of some flexibility, which is a legitimate tradeoff for many teams.

    Designing the Agent Loop

    The orchestration loop is the part most tutorials skip past, but it’s where most production bugs live. A naive implementation calls the model, executes whatever tool it requests, and loops forever until the model stops requesting tools. In practice you need explicit guardrails.

    Bounding Iterations and Cost

    Every agent loop needs a hard iteration cap and a cost/token budget per task. Without this, a model that gets stuck in a reasoning loop (asking for the same tool repeatedly, or looping between two contradictory conclusions) will burn API credits indefinitely. A simple counter passed through the loop, combined with a maximum wall-clock timeout, catches the vast majority of runaway cases.

    Structuring Tool Calls

    Tool definitions should be strict — a JSON schema per tool, validated before execution, not just passed straight from the model’s output into a shell command or database query. This is the single most important security boundary when building AI agents from scratch: the model’s output is untrusted input, exactly like a form submission from a browser. Treat it accordingly — validate types, whitelist allowed operations, and never string-concatenate model output directly into a shell command or SQL query.

    # Minimal example: validate a tool call before executing it
    python3 - <<'EOF'
    import json, subprocess, shlex
    
    def run_tool(tool_name, args: dict):
        ALLOWED_TOOLS = {"get_weather", "search_docs"}
        if tool_name not in ALLOWED_TOOLS:
            raise ValueError(f"Unregistered tool: {tool_name}")
        if tool_name == "search_docs":
            query = str(args.get("query", ""))[:200]  # bound input length
            return subprocess.run(
                ["grep", "-ri", query, "/data/docs"],
                capture_output=True, text=True, timeout=5
            ).stdout
        raise NotImplementedError(tool_name)
    
    print(run_tool("search_docs", {"query": "deployment"}))
    EOF

    Handling Partial Failures

    Tool calls fail — APIs time out, databases lock, shell commands return nonzero exit codes. The loop needs to feed failures back to the model as observations rather than crashing the whole task, so the agent can retry, choose a different tool, or gracefully report that it couldn’t complete the request. This is different from typical request/response error handling because the “caller” here is the model itself, which needs the failure expressed in natural language it can reason about.

    Choosing the Right Infrastructure

    Once the loop is designed, the next question is where it runs. Building AI agents from scratch doesn’t require Kubernetes or a large cloud budget — a single VPS with Docker Compose is enough for most single-tenant or small-team agent deployments.

    Containerizing the Agent Process

    Package the agent runtime as a container with clearly defined environment variables for API keys, model selection, and tool endpoints. Keep the container stateless — persist conversation state and task status externally (Redis or Postgres), not on the container’s local filesystem, so the process can restart or scale without losing in-flight work.

    If you’re already running Postgres for other services, this Postgres Docker Compose setup guide is a reasonable starting point for the state store, and Redis Docker Compose works well if you’d rather keep agent state in-memory with periodic persistence. For managing secrets like API keys across containers, see Docker Compose Secrets rather than baking keys into the image.

    Scheduling and Triggering

    Agents can be triggered synchronously (an HTTP request waits for the full loop to complete) or asynchronously (a webhook enqueues a task, a worker processes it, a callback or polling endpoint returns the result). For anything that might take more than a few seconds — which most multi-step agent tasks do — asynchronous triggering is the more reliable choice, since it avoids tying up an HTTP connection for the duration of an unpredictable model reasoning loop.

    A minimal docker-compose.yml for a two-process setup (API + worker) might look like this:

    version: "3.8"
    services:
      agent-api:
        build: ./api
        ports:
          - "8080:8080"
        environment:
          - REDIS_URL=redis://redis:6379
        depends_on:
          - redis
    
      agent-worker:
        build: ./worker
        environment:
          - REDIS_URL=redis://redis:6379
          - MODEL_API_KEY=${MODEL_API_KEY}
        depends_on:
          - redis
    
      redis:
        image: redis:7-alpine
        volumes:
          - redis-data:/data
    
    volumes:
      redis-data:

    Observability and Debugging

    Agent behavior is harder to debug than typical request/response services because the “logic” isn’t fully expressed in your code — it emerges from the model’s interpretation of a prompt at runtime. Building AI agents from scratch means you’re also responsible for building the observability that makes this debuggable.

    Logging Every Model Call and Tool Invocation

    Log the full prompt sent to the model, the raw response, every tool call requested, and every tool result returned — not just a summary. When an agent produces an unexpected output days later, the only way to understand why is to replay exactly what the model saw at each step. Structured logging (JSON lines, one per model/tool interaction) makes this searchable later.

    docker compose logs -f agent-worker | grep '"event":"tool_call"'

    If you’re running this stack alongside other Docker services, Docker Compose Logs covers the general debugging workflow this pattern builds on.

    Tracking Cost and Latency Per Task

    Each agent task should log total tokens consumed and wall-clock duration. Over time this data tells you which tasks are expensive outliers, which is essential for capacity planning and for deciding whether a given task should be routed to a smaller, cheaper model instead of your default.

    Security Considerations Specific to Agents

    An agent that can call tools is functionally similar to a service account with programmatic access to your systems — the model is deciding what to execute, but your infrastructure is executing it. Building AI agents from scratch puts this responsibility squarely on you rather than a platform vendor.

  • Run tool-executing workers with the minimum filesystem and network permissions they need — never as root, and never with unrestricted outbound network access.
  • Treat any URL, file path, or shell argument the model produces as untrusted input requiring the same validation you’d apply to a public API endpoint.
  • Rate-limit tool calls per task and per user to prevent a single runaway agent from exhausting downstream API quotas or database connections.
  • Store API keys and credentials outside the application code, using your orchestrator’s secrets mechanism rather than plain environment files committed to version control.
  • For a deeper walkthrough of the security-specific failure modes (prompt injection into tool arguments, excessive tool permissions, unbounded recursive tool calls), see AI Agent Security: A Practical Guide for DevOps.

    Deployment and Hosting

    A single agent process handling moderate traffic runs comfortably on a small VPS. If you’re setting up infrastructure specifically for this, a provider like DigitalOcean or Hetzner gives you a straightforward Docker-ready VPS without committing to a full managed Kubernetes bill before you know your actual traffic pattern. Start with a single droplet or server running Docker Compose, and only move to container orchestration once you have real usage data justifying the added complexity.

    For the initial server setup itself, an unmanaged VPS hosting guide covers the baseline hardening (SSH keys, firewall rules, unattended upgrades) worth doing before you deploy anything that holds API credentials.

    Zero-Downtime Restarts

    Because agent tasks can run for tens of seconds to a few minutes, a naive docker compose restart during a deploy can kill in-flight tasks. Use a queue-based worker pattern (the worker pulls from Redis or a similar queue) so a graceful shutdown can finish the current task before exiting, and the orchestrator can spin up a replacement worker without losing queued work.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a specialized “agent framework” to build AI agents from scratch?
    No. Frameworks like LangChain or LlamaIndex can save time on boilerplate (prompt templates, tool-calling glue code), but they’re not required. Building AI agents from scratch with a plain HTTP client and a hand-written loop gives you more visibility into what’s actually happening at each step, which is often worth the extra initial code for production systems.

    How is building AI agents from scratch different from using n8n or a similar automation tool?
    n8n and similar tools provide the orchestration loop, tool registry, and scheduling out of the box through a visual workflow editor, trading some flexibility for a much faster setup. Building AI agents from scratch means writing that orchestration yourself, which gives finer control over retry logic, cost tracking, and custom tool behavior at the cost of more initial engineering time.

    What’s the biggest infrastructure mistake teams make when building AI agents from scratch?
    Running the agent loop synchronously inside an HTTP request handler with no timeout or iteration cap. This leads to hung connections, unpredictable API bills, and no way to observe what the agent is doing mid-task. A queue-based worker with logging at every step avoids all three problems.

    Can I run building-AI-agents-from-scratch workloads on the same VPS as my other Docker services?
    Yes, as long as you isolate resource usage — set memory and CPU limits on the agent worker container so a runaway task can’t starve your other services, and keep its state store (Redis or Postgres) properly backed up alongside the rest of your stack.

    Conclusion

    Building AI agents from scratch is a reasonable, well-scoped engineering task once you break it into its component parts: a bounded orchestration loop, a validated tool registry, an external state store, and a container runtime you already know how to operate. None of these pieces require exotic infrastructure — a single Docker Compose stack on a modest VPS is enough to get a reliable agent into production. The work that actually differentiates a good implementation from a fragile one is the same work that differentiates any backend service: careful input validation, structured logging, iteration and cost bounds, and a deployment process that doesn’t kill in-flight work. Get those right, and building AI agents from scratch becomes a maintainable, extensible part of your infrastructure rather than a one-off experiment. For further reading on the underlying model APIs, the OpenAI API documentation and Docker’s official documentation are both useful references while implementing the patterns described above.

  • N8N Workflow Examples

    N8N Workflow Examples: Practical Patterns for Real Automation

    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.

    Teams evaluating n8n almost always start by searching for n8n workflow examples rather than reading the documentation cover to cover — it’s faster to reverse-engineer a working pattern than to build one from a blank canvas. This article walks through a set of production-realistic n8n workflow examples, from simple webhook-triggered automations to multi-branch orchestration with error handling, so you can adapt them directly to your own infrastructure.

    Why n8n Workflow Examples Matter More Than Documentation Alone

    Reading node reference docs tells you what a node does in isolation. It rarely tells you how nodes compose into something that survives a production restart, a malformed payload, or a rate-limited API. That’s the gap n8n workflow examples fill: they show the connective tissue — error branches, retry logic, credential scoping, and data shaping — that documentation glosses over.

    If you’re self-hosting n8n (rather than using n8n Cloud), you already control the runtime, the database, and the network path, which means these examples can be adapted with full visibility into what’s actually happening under the hood. If you haven’t set up a self-hosted instance yet, see our guide on self-hosting n8n with Docker before working through the examples below.

    What Makes an Example “Production-Realistic”

    A workflow that only handles the happy path isn’t a real example — it’s a demo. The examples below deliberately include:

  • Explicit error handling branches, not just success paths
  • Credential references instead of hardcoded secrets
  • Idempotency checks where duplicate execution would cause harm
  • Reasonable timeout and retry configuration
  • Core n8n Workflow Examples for Common Automation Tasks

    The following patterns cover the majority of automation requests teams actually bring to n8n: syncing data between systems, reacting to webhooks, and running scheduled jobs.

    Webhook-to-Database Sync

    This is one of the most common n8n workflow examples in practice: an external service (a form, a payment processor, a SaaS tool) sends a webhook, and n8n normalizes the payload and writes it to a database.

    # Conceptual node chain (as configured in the n8n editor)
    nodes:
      - name: Webhook
        type: n8n-nodes-base.webhook
        parameters:
          path: incoming-lead
          httpMethod: POST
          responseMode: onReceived
      - name: Validate Payload
        type: n8n-nodes-base.if
        parameters:
          conditions:
            string:
              - value1: "={{$json.email}}"
                operation: isNotEmpty
      - name: Insert Into Postgres
        type: n8n-nodes-base.postgres
        parameters:
          operation: insert
          table: leads

    The critical detail most n8n workflow examples skip: the Validate Payload step. Without it, malformed webhook bodies flow straight into your database node and either fail loudly or, worse, insert partial garbage rows. If you’re running Postgres alongside n8n, our Postgres Docker Compose setup guide covers the container configuration this workflow assumes.

    Scheduled Report Generation

    A second recurring category among n8n workflow examples is time-based automation — pulling data on a schedule and pushing a summary somewhere (Slack, email, a Google Sheet). The Schedule Trigger node replaces what used to require a cron job and a script:

    # Equivalent cron expression used inside the Schedule Trigger node
    0 8 * * MON  # every Monday at 08:00

    Internally, this maps to n8n’s cron-based trigger rather than a raw system crontab, which means the schedule lives inside the workflow definition itself and travels with it if you export/import the workflow between environments.

    Multi-Branch Approval Workflow

    More complex n8n workflow examples introduce conditional branching where a single trigger fans out into multiple paths based on business logic — for instance, routing a support ticket to different teams based on priority or keyword content.

    Building AI Agent Workflows in n8n

    One of the fastest-growing categories of n8n workflow examples involves connecting n8n to large language model APIs to build agentic automation — workflows that don’t just move data, but make decisions about what to do with it.

    A minimal pattern looks like this: a trigger (webhook, schedule, or manual) feeds into an HTTP Request or dedicated AI node, the model’s response is parsed, and an IF or Switch node routes the result to different downstream actions. For a deeper walkthrough of this pattern, including tool-calling and memory nodes, see our guide on building AI agents with n8n.

    Structuring the Prompt Node

    When an n8n workflow example calls out to an LLM, the prompt itself should live in a dedicated Set node or be templated with expressions, rather than hardcoded inline in the HTTP Request node. This keeps the workflow readable and makes prompt iteration possible without touching the request configuration.

    Handling Non-Deterministic Output

    LLM responses are not guaranteed to be valid JSON or to match a fixed schema, even with structured-output settings enabled. Every AI-driven n8n workflow example that reaches production should include a parsing/validation node immediately after the model call, with a fallback branch for malformed responses — otherwise a single unexpected response format can silently break the rest of the chain.

    Error Handling Patterns Across n8n Workflow Examples

    Almost every real n8n workflow example that survives contact with production traffic includes some form of explicit error handling, because the default behavior — a failed node stopping the entire execution — is rarely what you want for anything user-facing.

    n8n exposes this through two main mechanisms:

  • Error Workflow: a separate workflow assigned at the workflow-settings level, triggered automatically whenever any node in the main workflow fails
  • Continue on Fail: a per-node setting that lets execution proceed past a failed node, routing the error down a separate output branch
  • # Node-level setting (shown as workflow JSON, not UI)
    "continueOnFail": true,
    "onError": "continueErrorOutput"

    A well-built error-handling n8n workflow example typically logs the failure (to a database table, a logging service, or a Slack channel) and, where appropriate, retries the failed operation with backoff rather than dropping it silently.

    Retry Logic With Backoff

    HTTP Request nodes in n8n support built-in retry configuration (retry count and wait time between attempts), which covers transient failures like rate limits or momentary network blips. For failures that need longer-term retry logic — say, retrying a failed webhook delivery an hour later — a common pattern pairs a database table tracking failed items with a Schedule Trigger that periodically re-attempts anything still marked as pending.

    Comparing n8n Workflow Examples Against Other Automation Tools

    If you’re evaluating whether n8n is the right fit before committing engineering time to these patterns, it’s worth comparing against alternatives. Our n8n vs Make comparison covers pricing, self-hosting options, and workflow-building philosophy differences between the two platforms, which matters if any of the examples above need to be portable across tools later.

    Self-Hosted vs Cloud Considerations

    Many n8n workflow examples assume you have full control over environment variables, credential storage, and execution history retention — all of which differ meaningfully between a self-hosted instance and n8n Cloud. If cost is the deciding factor, our n8n Cloud pricing breakdown is worth reading alongside your self-hosting cost estimate before you commit either direction.

    Deploying and Maintaining n8n Workflow Examples in Production

    Getting a workflow working in the editor is only the first step. Running it reliably requires attention to the underlying infrastructure.

  • Use environment variables for all credentials — never hardcode API keys inside node parameters
  • Enable execution data pruning so your database doesn’t grow unbounded from execution history
  • Run n8n behind a reverse proxy with HTTPS termination if it’s reachable from the public internet
  • Back up workflow definitions and credentials on a regular schedule, not just the underlying database volume
  • Monitor the n8n process itself (via systemd, Docker healthchecks, or an external uptime check) so a crashed instance doesn’t silently stop processing triggers
  • For teams running n8n in Docker Compose, keeping secrets out of the committed compose file is worth getting right early — see our Docker Compose secrets guide for patterns that apply directly to n8n’s credential-heavy configuration. If you’re deploying on a VPS from scratch, the official n8n hosting documentation is the authoritative starting point for infrastructure requirements and reverse-proxy configuration.

    Choosing Where to Run n8n

    Self-hosted n8n needs a persistent VPS with enough memory to handle concurrent workflow executions, particularly if any of your workflows call external APIs with meaningful response payloads. A provider like DigitalOcean offers straightforward VPS provisioning that works well for a single n8n instance behind Docker Compose. Whatever provider you choose, make sure you can scale vertical resources without a full migration, since workflow execution volume tends to grow faster than initial estimates.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    What’s the simplest n8n workflow example for a beginner to start with?
    A webhook trigger connected to a Set node and then a Slack or email notification node is the simplest genuinely useful pattern. It requires no database, minimal configuration, and demonstrates the core trigger-transform-action shape that every more complex n8n workflow example builds on.

    Can n8n workflow examples be exported and shared between instances?
    Yes. Workflows can be exported as JSON from the n8n editor (or via the n8n REST API) and imported into another instance. Credentials are not included in workflow exports by default, so they need to be reconfigured separately on the target instance.

    Do n8n workflow examples require paid nodes or credentials?
    Most core automation patterns — webhooks, HTTP requests, database nodes, scheduling — use n8n’s built-in nodes, which are available in the open-source, self-hosted version at no licensing cost. Costs typically come from the external services you connect to (an LLM API, a paid SaaS tool), not from n8n itself.

    How do I debug a failing n8n workflow example?
    Use the execution history panel in the n8n editor to inspect the exact input and output data at each node for a failed run. Pinning test data on a node while iterating is also useful, since it lets you re-run downstream nodes without re-triggering the original webhook or schedule.

    Conclusion

    The n8n workflow examples covered here — webhook ingestion, scheduled reporting, AI-driven branching, and structured error handling — represent the patterns that show up repeatedly in real automation work, not just tutorial demos. Start with the simplest version of whichever pattern matches your use case, add validation and error branches before you add complexity, and keep credentials out of the workflow JSON itself. Once these core patterns are solid, extending them to more elaborate multi-system orchestration is largely a matter of composition rather than learning new concepts. For further reference on node behavior and expression syntax, the official n8n documentation remains the most reliable source as the platform evolves.

  • N8N Vs Airflow

    N8N Vs Airflow: Choosing the Right Workflow Automation Tool

    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.

    When comparing n8n vs Airflow, the choice usually comes down to what kind of work you’re automating: lightweight integration and notification workflows, or heavyweight, scheduled data pipelines. This guide breaks down the architectural differences, use cases, and deployment considerations so you can decide which tool fits your infrastructure without wasting weeks migrating between them later.

    Both tools are widely used in DevOps and data engineering, but they were built to solve different problems. n8n grew out of the workflow-automation space (similar in spirit to Zapier or Make, but self-hostable and node-based), while Apache Airflow was built at Airbnb specifically for orchestrating data pipelines as directed acyclic graphs (DAGs). Understanding that origin story explains almost every practical difference you’ll run into when running either tool in production.

    What n8n and Airflow Are Actually For

    Before diving into feature comparisons, it helps to separate the two tools by their core design intent.

    n8n is a visual, node-based automation platform. You drag nodes onto a canvas, connect them, and each node performs an action: call a webhook, query a database, transform JSON, send a Slack message, and so on. It’s designed for people who want to automate business processes, integrate SaaS APIs, or build internal tools quickly, often without writing much code.

    Airflow, in contrast, is a Python-first orchestration framework. You define DAGs as Python code, and each node in the DAG (a “task”) is typically a unit of work like running a SQL query, triggering a Spark job, or calling an external script. It was purpose-built for data engineering teams who need reliable, scheduled, dependency-aware pipeline execution — think ETL/ELT jobs that run nightly and must retry, log, and alert consistently.

    Execution Model Differences

    The n8n vs airflow execution model is one of the biggest practical differences engineers notice immediately:

  • n8n executions are typically triggered by webhooks, schedules, or manual runs, and each workflow execution is usually short-lived and stateless between runs.
  • Airflow DAGs are scheduled by design (via a scheduler process) and are built around the concept of “runs” tied to specific logical dates — even backfills for past dates are a first-class feature.
  • n8n workflows are visual graphs of nodes; Airflow DAGs are Python objects, which means you get the full power of a general-purpose language (loops, conditionals, dynamic task generation) baked into the pipeline definition itself.
  • This distinction matters more than it looks. If you need dynamic task generation based on database contents at runtime, Airflow’s Python-native DAGs make that far more natural than trying to build the same logic visually in n8n.

    n8n vs Airflow for Integration Workflows

    If your primary need is connecting SaaS tools, reacting to webhooks, or building internal automation (e.g., “when a new row appears in a Google Sheet, generate content and post it to WordPress”), n8n vs airflow comparisons almost always favor n8n. It ships with hundreds of pre-built integration nodes, has a lower learning curve for non-Python-fluent team members, and its visual editor makes workflows easier to hand off to less technical teammates.

    We’ve covered this same trade-off in more depth in our comparison of n8n vs Make, which is a closer apples-to-apples fight since both tools target the same integration-automation space that Airflow was never designed for.

    When n8n Wins

  • Rapid prototyping of business workflows without writing custom code
  • Real-time or near-real-time reactions to webhooks and events
  • SaaS-to-SaaS glue work (CRM updates, notification routing, content pipelines)
  • Teams that want a low-code option with an escape hatch (n8n supports custom JavaScript/Python code nodes when needed)
  • If you’re just getting started, our n8n self-hosted installation guide walks through deploying it with Docker, and the n8n automation guide covers running it long-term on a VPS.

    n8n vs Airflow for Data Pipeline Orchestration

    For data engineering workloads — batch ETL, machine learning pipeline orchestration, multi-step jobs with strict dependency ordering and retry semantics — Airflow is the more mature, purpose-built tool. It has first-class support for backfilling historical runs, task-level retries with exponential backoff, SLA monitoring, and a rich ecosystem of “providers” for integrating with cloud data warehouses, Spark clusters, and Kubernetes.

    Airflow’s DAG-Centric Design

    Every Airflow pipeline is defined as a DAG — a set of tasks with explicit upstream/downstream dependencies. This is deliberately restrictive: cycles aren’t allowed, which forces a clean, predictable execution order. A minimal Airflow DAG looks like this:

    from airflow import DAG
    from airflow.operators.bash import BashOperator
    from datetime import datetime
    
    with DAG(
        dag_id="daily_etl",
        schedule="@daily",
        start_date=datetime(2026, 1, 1),
        catchup=False,
    ) as dag:
        extract = BashOperator(
            task_id="extract",
            bash_command="python3 /opt/etl/extract.py",
        )
        load = BashOperator(
            task_id="load",
            bash_command="python3 /opt/etl/load.py",
        )
        extract >> load

    That extract >> load syntax is Airflow’s dependency operator — it’s simple, readable, and scales well to DAGs with dozens of interdependent tasks. n8n can express similar dependency chains visually, but it doesn’t have the same native concept of “logical run date” or backfilling historical schedule intervals, which is a core Airflow feature for data pipelines that need to reprocess past data.

    Where Airflow Falls Short

    Airflow isn’t a good fit for everything. It has a steeper operational footprint — you generally need a scheduler, a metadata database, one or more workers (or the newer lighter-weight executors), and often a message broker depending on the executor you choose. For simple automation tasks, that’s a lot of infrastructure overhead compared to n8n’s single-container deployment. Airflow also isn’t designed for real-time, event-driven workflows the way n8n is — it’s schedule- and batch-oriented at its core, even though sensors and deferrable operators have narrowed that gap somewhat over time.

    Deployment and Infrastructure Considerations

    Both tools can run self-hosted on a VPS or in Kubernetes, but their resource profiles differ meaningfully.

    n8n can run comfortably as a single Docker container (plus optionally Postgres for persistence), making it a good fit for smaller VPS instances. A minimal docker-compose.yml for n8n looks like this:

    services:
      n8n:
        image: n8nio/n8n:latest
        restart: unless-stopped
        ports:
          - "5678:5678"
        environment:
          - N8N_HOST=your-domain.com
          - N8N_PROTOCOL=https
        volumes:
          - n8n_data:/home/node/.n8n
    
    volumes:
      n8n_data:

    If you’re setting this up yourself, our guides on Docker Compose environment variables and Docker Compose secrets management are directly relevant for handling credentials safely, and our Postgres Docker Compose guide covers adding persistent storage if you outgrow SQLite.

    Airflow, by contrast, typically needs more moving parts: a scheduler, a webserver, an executor (CeleryExecutor, KubernetesExecutor, or the simpler LocalExecutor for small deployments), and a backing database. Running Airflow well on a budget VPS is possible with LocalExecutor and Postgres, but it’s a heavier footprint than n8n out of the box. For either tool, choosing adequately sized infrastructure matters — providers like DigitalOcean or Vultr offer VPS tiers that scale well for either an n8n instance or a modest Airflow deployment, and Hetzner is a common budget-friendly option for self-hosters running either tool.

    Monitoring and Logging in Production

    Regardless of which tool you pick, production reliability depends on visibility into failures. If you’re containerizing either tool, our Docker Compose logs debugging guide and Docker Compose logging setup guide cover the fundamentals of capturing and inspecting logs from long-running services — both n8n and Airflow benefit from centralized log aggregation once you have more than a handful of workflows or DAGs running.

    Migrating or Running Both Together

    It’s common for teams to run both tools side by side rather than picking one exclusively. A typical pattern: n8n handles the “glue” — reacting to webhooks, triggering downstream jobs, notifying stakeholders — while Airflow owns the actual scheduled data processing. n8n can trigger an Airflow DAG via its REST API, and Airflow can call back into n8n via a webhook node when a pipeline completes. This hybrid approach avoids forcing either tool outside its comfort zone.

    If you’re evaluating this hybrid path, it’s worth first confirming your automation actually needs Airflow’s scheduling rigor. Many teams considering n8n vs airflow migrations discover that n8n’s built-in scheduling trigger, combined with its code node for custom logic, covers 80% of what they thought they needed Airflow for — reserving Airflow only for the pipelines with genuine multi-step data dependencies and backfill requirements.

    Team Skillset Is a Real Deciding Factor

    Don’t underestimate this factor in an n8n vs airflow decision. Airflow assumes Python fluency across the team maintaining it — DAGs are code, and debugging them requires reading Python tracebacks. n8n’s visual model lowers the bar for contribution, but it can become harder to review changes at scale (visual diffs are less git-friendly than Python diffs, though n8n does support exporting workflows as JSON for version control).


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Is n8n a replacement for Airflow?
    Not entirely. n8n can replace Airflow for simpler, event-driven automation and integration work, but it lacks Airflow’s native backfilling, complex dependency graphs at scale, and mature scheduling semantics that data engineering teams typically need for large batch pipelines.

    Can n8n and Airflow be used together?
    Yes. A common pattern is having n8n trigger Airflow DAGs via its API for scheduled data jobs, while n8n itself handles lighter-weight integration and notification tasks. This lets each tool focus on what it does best.

    Which is easier to self-host, n8n or Airflow?
    n8n is generally easier to self-host — it can run as a single Docker container with an optional Postgres backend. Airflow requires more components (scheduler, webserver, executor, metadata database) and a bit more operational knowledge to run reliably.

    Does Airflow support real-time triggers like n8n?
    Airflow has added sensors and deferrable operators that reduce the gap, but it remains fundamentally schedule- and batch-oriented. n8n is more naturally suited to real-time, webhook-driven automation.

    Conclusion

    The n8n vs airflow decision isn’t really about which tool is “better” — it’s about matching the tool to the workload. Choose n8n when you need fast, visual automation of integrations, notifications, and business processes, especially if your team isn’t Python-heavy. Choose Airflow when you’re orchestrating genuine data pipelines that need dependency-aware scheduling, backfills, and retry logic at scale. Many production environments end up running both, each doing the job it was actually designed for. For deeper reading on either platform’s internals, the official Apache Airflow documentation and n8n documentation are the most reliable starting points before you commit to a production deployment.

  • Ai Agent Projects

    Ai Agent Projects: A Practical Guide to Planning and Deploying Them

    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.

    Choosing the right ai agent projects to build determines whether an AI initiative ships something useful or stalls in prototype limbo. This guide walks through how to scope, architect, deploy, and operate ai agent projects using tools most infrastructure teams already run, with a focus on self-hosted, framework-agnostic patterns rather than any single vendor’s SDK.

    Why Ai Agent Projects Fail Before They Ship

    Most failed ai agent projects don’t fail because the underlying model is weak. They fail because the team never defined a bounded task, never gave the agent reliable tools, or never built the operational scaffolding (logging, retries, rate limiting) that any production service needs. An LLM call wrapped in a loop is not a project — it’s a demo.

    Scoping the Task Correctly

    Before writing any code, write down exactly what the agent is allowed to decide versus what must remain deterministic. A support-ticket triage agent, for example, should be free to draft a reply, but the actual send action should go through a human-approved or rule-gated step until the system has a track record. This distinction — decision-making versus execution — is the single biggest predictor of whether ai agent projects survive contact with real users.

    Picking an Architecture Pattern

    There are three common shapes for ai agent projects:

  • Single-agent, tool-using loop — one LLM call in a loop with function-calling tools (search, database read, API call). Good for well-bounded tasks like data lookup or summarization.
  • Multi-agent orchestration — a supervisor agent delegates subtasks to specialized workers (a researcher, a writer, a verifier). Useful when the task naturally decomposes but adds coordination overhead.
  • Workflow-embedded agent — an LLM step is inserted into an otherwise deterministic pipeline (e.g., an n8n workflow), where the agent only handles the parts that genuinely need judgment. This is often the most reliable pattern for production infrastructure because everything around the LLM call remains testable and observable.
  • If you’re evaluating no-code or low-code orchestration for this last pattern, a guide like how to build AI agents with n8n is a reasonable starting point for teams that want workflow-level control without hand-rolling an agent loop from scratch.

    Core Components Every Ai Agent Project Needs

    Regardless of framework, every one of these ai agent projects needs the same underlying components: a model provider, a tool/function-calling layer, state/memory storage, and an execution environment. Skipping any of these usually shows up later as an incident.

    Model Access and Cost Control

    Most ai agent projects call a hosted model API. Track token usage per agent run from day one — agent loops can call the model many times per user request, and costs compound quickly if a retry logic bug causes infinite looping. If you’re using OpenAI’s models, read the OpenAI API pricing and OpenAI API cost guides before committing to a pricing tier, and check the OpenAI API reference for the exact parameters that affect token consumption (max tokens, temperature, function-call schemas).

    Tool and Function Definitions

    Agents are only as useful as the tools they can call. Define each tool with a strict JSON schema, validate inputs before execution, and never let an agent call a tool that can mutate production state without an explicit allow-list. This is the same principle behind least-privilege access control in traditional infrastructure — an agent’s tool surface is its blast radius.

    Persistent State and Memory

    Multi-turn or long-running agents need somewhere to store conversation history, intermediate results, and task status. For most self-hosted ai agent projects, a relational database is sufficient and easier to operate than a dedicated vector store, unless retrieval-augmented generation is a hard requirement. If you’re already running Postgres for other services, see the Postgres Docker Compose or PostgreSQL Docker Compose setup guides for a pattern that reuses existing infrastructure instead of adding a new datastore.

    Deploying Ai Agent Projects with Docker Compose

    Containerizing an agent’s runtime, its tool servers, and its state store together makes ai agent projects reproducible and easy to move between environments. A minimal Compose file for a single agent service with a Postgres backing store looks like this:

    version: "3.9"
    services:
      agent:
        build: ./agent
        environment:
          - MODEL_API_KEY=${MODEL_API_KEY}
          - DATABASE_URL=postgresql://agent:agent@db:5432/agent_state
          - MAX_TOOL_CALLS_PER_RUN=8
        depends_on:
          - db
        restart: unless-stopped
    
      db:
        image: postgres:16
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agent_state
        volumes:
          - agent_db_data:/var/lib/postgresql/data
        restart: unless-stopped
    
    volumes:
      agent_db_data:

    Note the MAX_TOOL_CALLS_PER_RUN variable — this kind of hard cap belongs in your environment configuration, not buried in application code, so it can be adjusted without a redeploy. For more on managing these values correctly across environments, see the Docker Compose env and Docker Compose environment variables guides.

    Handling Secrets Safely

    Model API keys and any credentials an agent’s tools use to reach internal systems should never sit in a Compose file in plaintext. Use Docker secrets, an external secrets manager, or at minimum a gitignored .env file with restricted permissions — the Docker Compose secrets guide covers the tradeoffs between these approaches.

    Rebuilding and Iterating Safely

    Agent prompts and tool definitions change frequently during development. Know the difference between a plain restart and a full rebuild — if you change the agent’s Dockerfile or its dependency list, docker compose up alone won’t pick up the change. The Docker Compose rebuild guide walks through when each command is actually needed, which matters more for agent services than most, since prompt-engineering iteration cycles are fast.

    Observability and Debugging for Ai Agent Projects

    Agents fail in ways that traditional services don’t: a tool call can succeed but return data the model misinterprets, or the model can hallucinate a tool argument that passes schema validation but is semantically wrong. Standard logging and log-shipping practices still apply, but you also need to log the full reasoning trace — every tool call, its input, its output, and the model’s next decision — not just request/response pairs.

    Structured Logging Practices

    Log each agent run as a structured event with a unique run ID, then log every tool invocation nested under that ID. This lets you reconstruct exactly what happened when a user reports unexpected behavior, without needing to reproduce the bug live. Standard container log tooling still applies here — the Docker Compose logs and Docker Compose logging guides cover the practical mechanics of tailing and filtering these logs, and the Docker Compose log command reference is useful once you’re grepping for a specific run ID across services.

    Setting Up Alerting

    Alert on things that indicate the agent is behaving outside its intended bounds: tool-call counts exceeding your configured cap, repeated identical tool calls (a sign of a stuck loop), or a spike in fallback/error responses. These are infrastructure-level signals, not model-quality signals, and they’re usually cheaper to catch and act on.

    Orchestrating Ai Agent Projects at Scale

    Once you have more than one agent, or an agent that needs to trigger based on external events (a new support ticket, a scheduled report, a webhook), an orchestration layer becomes necessary. Comparing dedicated automation platforms against a hand-rolled scheduler is worth doing early, since retrofitting orchestration onto a pile of cron jobs is painful.

    Workflow Engines vs. Custom Schedulers

    Tools like n8n let you wire an agent step into a larger, auditable workflow with built-in retry, error branches, and a visual execution history — useful for teams that want the LLM confined to one well-defined step rather than owning the entire control flow. If you’re comparing platforms, the n8n vs Make comparison and the n8n self-hosted installation guide are good starting points, and n8n templates can shortcut the first version of a workflow rather than starting from a blank canvas.

    Where to Host the Orchestration Layer

    Whatever orchestration tool you choose, it needs a stable host separate from your laptop. A modest VPS is usually enough for early-stage ai agent projects — you don’t need a Kubernetes cluster to run a handful of agent workflows reliably. Providers like DigitalOcean and Hetzner offer VPS tiers that are sized appropriately for this kind of workload, and Vultr is worth comparing if latency to a specific region matters for your users.


    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do ai agent projects always require a dedicated vector database?
    No. Many ai agent projects only need short-term conversation state and a record of past tool calls, both of which fit comfortably in a relational database. A vector store is only necessary if the agent performs semantic retrieval over a large, unstructured document corpus.

    How many tool calls should an agent be allowed per run?
    There’s no universal number, but every agent should have an explicit hard cap, enforced in code or configuration, not left to the model’s judgment. Start conservative (single digits) and raise the limit only after you’ve observed real usage patterns and confirmed the agent isn’t looping unnecessarily.

    Should agent code live in the same repository as the rest of the application?
    It depends on team structure, but keeping agent prompts, tool schemas, and orchestration config under version control — in whichever repository your team already reviews changes in — is more important than which repository it is. Prompts and tool definitions change behavior just as much as code does and should go through the same review process.

    What’s the fastest way to get a first ai agent project into production?
    Pick the narrowest possible task with a clear success/failure signal, wire it into an existing workflow engine or a small Docker Compose service rather than a new framework, and instrument logging before you instrument anything else. A small, observable agent in production teaches you more than a large one still in development.

    Conclusion

    Successful ai agent projects share a common shape: a narrowly scoped task, a small and well-validated set of tools, deterministic infrastructure around the LLM call, and logging detailed enough to reconstruct any run after the fact. None of this requires exotic tooling — Docker Compose, a relational database, and an existing workflow engine cover most early-stage needs. For further reading on the underlying platforms referenced here, the official Docker documentation and Kubernetes documentation are the authoritative references once an agent project outgrows a single-host deployment.