DS DevShelfHub Projects · AI tools
Tutorials / AI Agents / Build Your First Agent
AI Agents Hands-on · 15 min read Page 7 of 10

How to Build Your First AI Agent in Python

By DevShelfHub

Write a working research agent in plain Python — no framework required. It will search the web and summarise what it finds.

Series progress7 / 10
Build your first AI agent in Python — hands-on tutorial

What we are building

A minimal research agent. You give it a question, it searches the web, reads the top results, and writes a concise summary. It runs as a loop until it decides it has enough information.

You will need:

  • Python 3.10+
  • An OpenAI API key
  • A Tavily API key for web search (free tier available)
  • truststore — fixes SSL certificate errors on macOS

Step 1 — Install dependencies

bash
pip install openai tavily-python truststore

Set your API keys as environment variables:

bash
export OPENAI_API_KEY="sk-..."
export TAVILY_API_KEY="tvly-..."

Step 2 — Define the tools

We will give the agent one tool: web search. We define it as a Python function and describe it in the OpenAI tool-calling format so the LLM knows when and how to use it.

python
# tools.py
import os
from tavily import TavilyClient

client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])

def web_search(query: str) -> str:
    """Search the web and return a summary of the top results."""
    results = client.search(query=query, max_results=3)
    output = []
    for r in results["results"]:
        output.append(f"Title: {r['title']}\nURL: {r['url']}\nSnippet: {r['content']}\n")
    return "\n---\n".join(output)


# OpenAI tool definition
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "web_search",
            "description": "Search the web for up-to-date information on a topic.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "The search query"}
                },
                "required": ["query"],
            },
        },
    }
]

Step 3 — Write the agent loop

This is the core of the agent. We send messages to the LLM, check whether it wants to call a tool, execute the tool if so, and add the result back to the messages — then loop.

python
# agent.py
import json
import os

import truststore
truststore.inject_into_ssl()

from openai import OpenAI
from tools import TOOLS, web_search

openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])


def run_agent(goal: str, max_steps: int = 10) -> str:
    messages = [
        {
            "role": "system",
            "content": (
                "You are a research assistant. Use the web_search tool to find information, "
                "then write a concise summary. When you have enough information, respond "
                "directly without calling any more tools."
            ),
        },
        {"role": "user", "content": goal},
    ]

    for _ in range(max_steps):
        response = openai_client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages,
            tools=TOOLS,
            tool_choice="auto",
        )
        msg = response.choices[0].message

        if not msg.tool_calls:
            return msg.content

        messages.append(msg)
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            result = web_search(**args)
            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": result,
            })

    return "Max steps reached without a final answer."


if __name__ == "__main__":
    goal = input("Research goal: ")
    print("\n" + run_agent(goal))

Step 4 — Run it

bash
python agent.py
Research goal: What are the top Python web frameworks in 2025?

The agent will call the search tool one or more times, read the results, and write a summary — all automatically.

What just happened?

Let's trace through the agent loop for this run:

1

Perceive: Agent receives goal "What are the top Python web frameworks in 2025?"

2

Think: LLM decides to call web_search("top Python web frameworks 2025")

3

Act: Search tool runs, returns snippets about Django, FastAPI, Flask, etc.

4

Observe: Results added to messages. Agent reads them.

5

Decide: LLM has enough info — returns a final summary without calling any more tools.

Extending the agent

To add more tools, just define another function and add it to the TOOLS list:

  • A save_to_file(filename, content) tool to persist the summary
  • A run_python(code) tool to let the agent execute calculations
  • A fetch_url(url) tool to read a specific webpage in full

The LLM will automatically use whichever tool is most appropriate given the goal.

Complete code Project link (GitHub)

Demo

Common pitfalls when building your first agent

Most first-time agent builders hit the same problems. Knowing them in advance saves hours of debugging.

Infinite loops

If the agent keeps calling the same tool with the same query, your loop will run forever. Always set a max_iterations counter (10 is a reasonable default) and break when it is hit. Log a warning so you know it happened.

Tool description mismatch

The LLM decides which tool to call based entirely on the tool's description. If your description says "search the web" but the function actually queries a local database, the agent will call it at the wrong time. Write descriptions from the LLM's perspective — what does this tool do and when should I use it.

Missing error handling in tools

If a tool raises an unhandled exception, the loop crashes. Wrap each tool function in a try/except and return a plain-text error message instead. The LLM can often recover from "Search failed: rate limit exceeded, try again in 10 seconds" — but not from a Python traceback.

Context window overflow

Every tool result gets appended to the message list. After several iterations with large search results, you can exceed the model's context limit. Truncate or summarise tool outputs before appending them — keep only the most relevant parts.

How to debug agent loops

Agents are harder to debug than regular programs because the LLM's reasoning is a black box. These techniques make agent behavior visible and predictable.

  • Print every iteration. Log the iteration number, which tool was called, the arguments, and a truncated version of the result. This gives you a trace you can read top-to-bottom to understand what the agent did and why.
  • Use a system prompt that encourages reasoning. Adding "Think step-by-step before choosing a tool" to the system message makes the LLM write its reasoning in the response, which you can read in the logs. This is the ReAct pattern in practice.
  • Test tools in isolation first. Call each tool function directly with known inputs and verify the output format before wiring it into the agent. If the tool returns unexpected JSON, the agent will not know how to interpret the result.
  • Replay with fixed messages. Save the full message list from a failed run. Replay it by passing those messages directly to the LLM call — you will get the same (or very similar) response, which lets you experiment with prompt changes without running the full loop.

Build Your First AI Agent FAQ

What do I need to build an AI agent in Python?

You need Python 3.10+, an OpenAI API key, and a Tavily API key for web search. The free tiers of both APIs are enough to get started.

How many lines of code is a basic AI agent?

A basic agent loop in plain Python is about 30 lines of code. You define a tool function, describe it for the LLM, and write a loop that calls the model and executes tools until the task is done.

Do I need a framework like LangChain to build an AI agent?

No. You can build a fully working agent in plain Python using the OpenAI API directly. Frameworks add convenience for complex projects but are not required.

How does the AI agent loop work?

The agent sends messages to the LLM, checks whether it wants to call a tool, executes the tool if requested, adds the result back to messages, and loops until the LLM responds without requesting a tool.

Can I add more tools to the agent?

Yes. Define another Python function and add it to the TOOLS list. The LLM will automatically use whichever tool is most appropriate for the task.

Want to use a framework instead of plain Python? See the agent frameworks overview to compare LangChain, CrewAI, and more. For real-world inspiration, check out AI agent use cases. You can also explore our full tutorials catalog for more hands-on guides.

Quick summary

  • An agent loop in plain Python is just ~30 lines of code
  • Define tools as functions + OpenAI-format descriptions
  • The loop: call LLM → if tool requested, execute it → add result to messages → repeat
  • The agent stops when the LLM responds without requesting a tool