InsightsSuper Intelligence

How to Build an AI Agent in 2026: A Step-by-Step Guide for Developers

How to build an AI agent in 2026: a runnable Python example with tool calling, an agent loop, memory, guardrails, deployment and packaging it as a product.

Digital Silk Route8 min read

How to Build an AI Agent in 2026: A Step-by-Step Guide for Developers

To build an AI agent, you connect a large language model to a set of tools (functions it can call), then run a loop: the model decides which tool to use, your code runs it, the result goes back to the model, and the loop repeats until the task is done. This guide builds a small, working customer-support agent in Python, then adds memory, guardrails, an API and a path to selling it as a product.

Key takeaways

  • An agent is three parts: a model, tools, and a loop that feeds tool results back to the model.
  • Start with the simplest design that works. Many tasks need a single model call or a fixed workflow, not a full agent.
  • Tool descriptions are part of your prompt. Clear names, descriptions and input schemas matter as much as code.
  • Guardrails (step limits, input validation, allow-listed tools, human approval for risky actions) belong in your code, not only in the prompt.
  • An agent becomes a product when it is tested, documented, deployed behind an API and scoped to one clear job.

What is an AI agent?

An AI agent is a program where a language model directs its own steps toward a goal by using tools. Anthropic's guide "Building effective agents" draws a useful line between:

  • workflows, where your code follows a predefined path and calls the model at fixed points; and
  • agents, where the model decides dynamically which tools to use and in what order.

Workflows are more predictable and cheaper. Agents are more flexible. A good rule: use a workflow when you can write down the steps in advance, and an agent when the steps depend on what the model discovers along the way.

AI agent architecture

Every agent in this guide has the same shape:

  1. System prompt: who the agent is, what it may and may not do.
  2. Tools: functions with a name, a description and a JSON schema for inputs.
  3. The loop: send messages to the model; if it asks for a tool, run it and send back the result; stop when it gives a final answer or hits a step limit.
  4. State: the message history, plus any longer-term memory you add.
  5. Guardrails: checks around every tool call and every output.

Step 1: Set up the project

You need Python 3.10 or newer and an Anthropic API key.

python -m venv .venv
source .venv/bin/activate      # On Windows: .venv\Scripts\activate
pip install anthropic
export ANTHROPIC_API_KEY="your-key-here"   # never commit this to Git

We use the official anthropic Python SDK. The same pattern (model plus tools plus loop) works with other providers' SDKs, but the exact function names differ, so check their docs.

Step 2: Define the tools

Our example agent answers questions for a small online shop. It has two tools: one looks up an order, the other returns the return policy. In a real product, lookup_order would query your database; here it reads a dictionary so the example runs anywhere.

# agent.py
import json
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
MODEL = "claude-opus-5-5"

ORDERS = {
    "PK-1001": {"status": "shipped", "city": "Lahore", "eta_days": 2},
    "PK-1002": {"status": "processing", "city": "Karachi", "eta_days": 5},
}

def lookup_order(order_id: str) -> str:
    order = ORDERS.get(order_id.strip().upper())
    if order is None:
        return json.dumps({"error": f"No order found with id {order_id}"})
    return json.dumps(order)

def get_return_policy() -> str:
    return "Unused items can be returned within 7 days of delivery."

TOOLS = [
    {
        "name": "lookup_order",
        "description": "Look up the status of a customer's order by order ID, "
                       "for example PK-1001. Use this whenever the user asks "
                       "where their order is.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string", "description": "Order ID such as PK-1001"}
            },
            "required": ["order_id"],
        },
    },
    {
        "name": "get_return_policy",
        "description": "Get the shop's return policy.",
        "input_schema": {"type": "object", "properties": {}},
    },
]

TOOL_FUNCTIONS = {"lookup_order": lookup_order, "get_return_policy": get_return_policy}

def run_tool(name: str, tool_input: dict) -> tuple[str, bool]:
    """Run an allow-listed tool. Returns (output, is_error)."""
    fn = TOOL_FUNCTIONS.get(name)
    if fn is None:
        return f"Unknown tool: {name}", True
    try:
        return fn(**tool_input), False
    except Exception as exc:  # report errors to the model instead of crashing
        return f"Tool error: {exc}", True

Notice the descriptions say when to use each tool. The model only knows what you tell it.

Step 3: Write the agent loop

This is the heart of the agent.

SYSTEM = (
    "You are a polite support assistant for a small online shop in Pakistan. "
    "Answer in the language the customer uses (English, Urdu or Roman Urdu). "
    "Use tools for order facts; never guess an order status. "
    "If you cannot help, say so and suggest contacting support@example.com."
)

def run_agent(messages: list, max_steps: int = 8) -> str:
    """Run the agent on a conversation. Appends to `messages` in place."""
    for _ in range(max_steps):
        response = client.messages.create(
            model=MODEL,
            max_tokens=16000,
            system=SYSTEM,
            tools=TOOLS,
            messages=messages,
        )
        # Keep the full assistant turn (including tool_use blocks) in history.
        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason == "refusal":
            return "Sorry, I can't help with that request."
        if response.stop_reason != "tool_use":
            return "".join(b.text for b in response.content if b.type == "text")

        # Run every tool the model asked for, then send all results back together.
        results = []
        for block in response.content:
            if block.type == "tool_use":
                output, is_error = run_tool(block.name, block.input)
                results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": output,
                    "is_error": is_error,
                })
        messages.append({"role": "user", "content": results})

    return "Sorry, this is taking too long. Please contact support."

if __name__ == "__main__":
    history = [{"role": "user", "content": "Mera order PK-1001 kahan hai?"}]
    print(run_agent(history))

What happens when you run it:

  1. The model reads the Roman Urdu question and decides to call lookup_order with PK-1001.
  2. Your code runs the function and returns {"status": "shipped", ...}.
  3. The model writes a reply in Roman Urdu using that data.

Three details worth knowing:

  • Parallel tool calls. The model can ask for several tools in one turn. Return all the results in a single user message, as the loop does.
  • Errors go back to the model. Setting is_error lets the model recover, for example by asking the user to re-check an order number.
  • The step limit stops runaway loops and runaway bills.

The Anthropic SDK also offers a beta "tool runner" that handles this loop for you. Writing it by hand once is the best way to understand what agents really do.

Step 4: Add memory to your AI agent

There are two kinds of memory.

Short-term memory is the conversation history. Because run_agent appends to the messages list, you can keep the list per user session and keep calling it:

history = []
for user_text in ["Order PK-1002 ka status?", "Aur return policy kya hai?"]:
    history.append({"role": "user", "content": user_text})
    print(run_agent(history))

Long-term memory is anything you store between sessions: a user's preferred language, past orders, notes. Store it in your own database and either inject a short summary into the system prompt or expose it through a tool such as get_customer_profile. Keep it small and relevant; more context is not always better.

Step 5: Add guardrails

Prompts guide behaviour; code enforces it. Practical guardrails for a first agent:

  • Allow-list tools. run_tool only runs functions in TOOL_FUNCTIONS.
  • Validate inputs. Check that order_id matches your format (for example, a regular expression) before touching a database.
  • Limit steps and tokens. Already done with max_steps and max_tokens.
  • Separate read and write actions. Reading an order is low-risk. Issuing a refund is not. Put write actions behind human approval or strict limits.
  • Treat retrieved text as data. Prompt injection, where text in a user message or a document tries to override your instructions, is ranked first (LLM01) in the OWASP Top 10 for LLM Applications 2025. Never let tool output grant new permissions.
  • Log everything. Save each conversation, tool call and result so you can debug and evaluate.

Step 6: Deploy the agent as an API

Wrap the agent in a small web API so a website, WhatsApp integration or mobile app can call it. With FastAPI:

# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from agent import run_agent

app = FastAPI()

class Ask(BaseModel):
    message: str

@app.post("/ask")
def ask(body: Ask) -> dict:
    history = [{"role": "user", "content": body.message}]
    return {"reply": run_agent(history)}
pip install fastapi uvicorn
uvicorn main:app --reload

For production, add authentication, rate limiting, per-session history storage, and monitoring. Keep the API key on the server, never in a browser or mobile app.

Step 7: Test before you ship

An agent that works on three examples may fail on the fourth. Before launch, write 20 to 50 realistic test questions, including tricky ones (wrong order IDs, mixed Urdu and English, attempts to get a refund without approval), and check the answers automatically. Our guide to evaluating AI agents (SI-10) builds a simple test harness for exactly this agent.

Step 8: Package your AI agent as a product

A tutorial agent becomes a product when someone else can buy it, install it and trust it. That means:

  • One clear job. "Order-status and returns assistant for small e-commerce shops" is sellable. "General AI assistant" is not.
  • Configuration, not code edits. Let buyers plug in their own order database, policy text and brand voice through a config file or settings page.
  • Documentation. Setup steps, required API keys, limits, and what the agent will not do.
  • Evidence. Share your test results: how many test cases, what passed, known weaknesses.
  • Support and updates. Say how you handle bugs and model changes.

You can also connect your agent to standard tool ecosystems. The Model Context Protocol (MCP), introduced by Anthropic and donated to the Linux Foundation's Agentic AI Foundation in December 2025, lets agents connect to tools and data sources through a shared standard, which makes your tools reusable across clients.

This build, test and package sequence is also how Digital Silk Route (DSR) structures its Superintelligence capstones.

Next step with Digital Silk Route

This guide is the core skill behind the Superintelligence track at the Digital Silk Route (DSR) AI & Crypto Academy. Across Beginner, Intermediate and Advanced levels, each capstone has you build and test a working AI product, such as an agent like this one, scoped for real buyers. When it is ready, list it on the DSR Marketplace. Learn. Build. Earn.

Sources

Frequently asked questions

  • how to build an ai agent
  • ai agent tutorial python
  • tool calling llm
  • agent loop
  • build ai agent from scratch
  • deploy ai agent