How to Make an AI Agent: A Practical Build-and-Deploy 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.
Every few months a new framework promises to make agent development “effortless.” Most of them just wrap the same four pieces: a language model, a set of tools, some memory, and a loop that decides what to do next. If you understand those four pieces, you can build an agent without depending on whatever framework is trendy this quarter.
This guide walks through how to make an AI agent from first principles — the architecture, the code, and how to actually run it in production instead of leaving it in a Jupyter notebook. We’ll build a working Python agent, then containerize it and deploy it on a VPS the same way you’d deploy any other backend service.
What an AI Agent Actually Is
An AI agent is a program that uses a language model to decide what action to take next, executes that action using real tools (APIs, shell commands, database queries), observes the result, and repeats until it reaches a goal. That’s the whole definition. Everything else — vector databases, orchestration frameworks, multi-agent swarms — is optional tooling layered on top.
Agent vs. Chatbot vs. Script
It’s worth being precise about terminology before you start building:
If your “agent” always does the same three API calls in the same order regardless of input, you’ve built a script with an LLM bolted on, not an agent. That’s not necessarily bad — scripts are more predictable and cheaper to run — but don’t call it agentic if it isn’t.
The Core Components You Need
Before writing code, decide how you’ll implement each of these:
Skipping the stop condition is the single most common mistake in agent code you’ll find in tutorials. Always cap the number of iterations.
How to Make an AI Agent: Step-by-Step
Step 1: Define the Agent’s Goal and Scope Narrowly
General-purpose agents that “do anything” are hard to test and easy to break. Start with a narrow, well-defined job: “summarize new GitHub issues and label them,” “check server disk usage and alert if over 80%,” “pull the latest movie release schedule and post it.” A narrow scope makes the tool list short and the failure modes predictable.
Step 2: Pick Your Stack
You have three realistic options:
1. Raw API calls (OpenAI, Anthropic, or a local model via Ollama) — most control, most code to write
2. A framework like LangChain or LlamaIndex — faster to prototype, more abstraction to fight later
3. A managed agent platform — fastest to ship, least control over cost and behavior
For learning how agents actually work, build the loop yourself first with raw API calls. You can always migrate to a framework once you understand what it’s abstracting away.
Step 3: Write the Tools
Tools are just Python functions with a schema the model can read. Here’s a minimal example with two tools — a weather lookup and a disk-usage checker:
import shutil
def get_disk_usage(path: str = "/") -> dict:
total, used, free = shutil.disk_usage(path)
return {
"total_gb": round(total / (1024**3), 2),
"used_gb": round(used / (1024**3), 2),
"percent_used": round((used / total) * 100, 2),
}
def search_web(query: str) -> str:
# Replace with a real search API call (SerpAPI, Bing, etc.)
return f"Search results for: {query}"
TOOLS = {
"get_disk_usage": get_disk_usage,
"search_web": search_web,
}
Step 4: Build the Reasoning Loop
This is the ReAct pattern (reason, act, observe) — the model picks a tool, you run it, you feed the result back, and repeat until the model returns a final answer instead of a tool call.
from openai import OpenAI
import json
client = OpenAI()
tool_schemas = [
{
"type": "function",
"function": {
"name": "get_disk_usage",
"description": "Check disk usage for a given path",
"parameters": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": [],
},
},
}
]
def run_agent(goal: str, max_steps: int = 6):
messages = [{"role": "user", "content": goal}]
for step in range(max_steps):
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tool_schemas,
)
choice = response.choices[0].message
if choice.tool_calls:
messages.append(choice)
for call in choice.tool_calls:
fn = TOOLS[call.function.name]
args = json.loads(call.function.arguments)
result = fn(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
})
else:
return choice.content
return "Max steps reached without a final answer."
That max_steps cap is your stop condition. Without it, a model that keeps second-guessing itself will happily loop until you run out of API budget.
Step 5: Add Memory
For a single task, the messages list above is your short-term memory — it’s just conversation state. If you need the agent to remember things across separate runs (yesterday’s disk usage, a user’s past requests), persist that state somewhere durable: SQLite for simple cases, or a vector database like Chroma or pgvector if you need semantic recall over large amounts of text. Don’t reach for a vector database on day one if a plain SQL table does the job — it’s usually premature complexity for small agents.
Step 6: Containerize It
Once the agent works locally, package it so it runs the same way everywhere. A basic Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "agent.py"]
And a docker-compose.yml if the agent needs a database or scheduler alongside it:
services:
agent:
build: .
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
restart: unless-stopped
volumes:
- ./data:/app/data
If you haven’t containerized a Python service before, our Docker Compose guide for beginners covers the fundamentals of volumes, networks, and restart policies used above.
Deploying Your Agent to a VPS
Running an agent locally is fine for testing, but a scheduled or always-on agent needs a real server. A small VPS is enough for most single-purpose agents — you don’t need GPU hosting unless you’re running the model itself locally rather than calling an API.
We’ve had good results running containerized agents on DigitalOcean droplets — their managed Docker support and predictable pricing make it easy to keep an agent running as a background service without babysitting the underlying infrastructure. For workloads where you’re comparing raw compute cost per dollar, Hetzner is worth checking too, since their VPS pricing tends to undercut the big three clouds for simple always-on containers.
Once it’s deployed, you’ll want to know if it’s actually running. BetterStack can ping your agent’s health endpoint and alert you the moment it stops responding — useful for agents that run on a cron schedule, where a silent failure could go unnoticed for days. If your agent exposes any kind of webhook or API endpoint publicly, put it behind Cloudflare so you get DDoS protection and TLS termination without managing certificates yourself.
For background on picking server sizing before you commit to a plan, see our guide on choosing the right VPS for Docker workloads.
Common Pitfalls When Building Your First Agent
That last point matters more than tutorials usually admit. An agent with unrestricted shell access is one bad prompt injection away from doing something you didn’t intend. Scope tool permissions the same way you’d scope a service account: least privilege, always.
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 framework like LangChain to build an AI agent?
No. Frameworks speed up prototyping but add abstraction layers that can obscure what’s actually happening. Building the loop yourself first, as shown above, makes it much easier to debug and extend later — you can always adopt a framework once you understand the underlying pattern.
What’s the cheapest way to run an AI agent in production?
Use a small VPS (a $6–12/month droplet is enough for most single-purpose agents), rely on API-based models rather than self-hosting a large LLM, and cap your iteration limits so a misbehaving loop doesn’t rack up API costs.
Can I run an AI agent without calling an external API?
Yes — tools like Ollama let you run open models like Llama 3 locally, which removes API costs entirely but requires more compute (typically a GPU) for reasonable response times.
How do I stop an agent from calling the wrong tool?
Keep the tool list short and each tool’s description precise. Vague descriptions or overlapping tool purposes are the most common cause of the model picking the wrong one.
Is an AI agent the same thing as a workflow automation tool like Zapier?
No. Zapier-style tools follow a fixed, predefined sequence of steps. An agent uses a model to decide dynamically which step to take next based on the current situation, which makes it more flexible but also less predictable.
How much does it cost to run a simple agent 24/7?
For a lightweight agent polling every few minutes, API costs are usually a few dollars a month with an efficient model, and VPS hosting adds another $5–10. The bigger cost driver is usually inefficient looping, not the base infrastructure.
Leave a Reply