How to Build an AI Agent in Python from Scratch
An AI agent is a program that can reason, act, and observe in a loop. In this tutorial you will build a minimal agent in plain Python that can choose tools, run them, and answer questions.
What you will build
A Python agent that can answer questions like "What is the weather in Paris?" by deciding whether to use a weather tool or answer directly.
The agent loop
Every agent follows the same cycle:
1. Receive a task or question
2. Think about what to do
3. Act by calling a tool or generating an answer
4. Observe the result
5. Repeat until done
Set up the project
python -m venv .venv
source .venv/bin/activate
pip install openai python-dotenvCreate a .env file with your OpenAI API key:
OPENAI_API_KEY=sk-...Define a simple tool
import json
import os
import random
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
def get_weather(city: str) -> str:
"""Return fake weather for demo purposes. Replace with a real API."""
conditions = ["sunny", "cloudy", "rainy"]
temp = random.randint(10, 30)
return f"The weather in {city} is {random.choice(conditions)} and {temp}°C."
tools = {
"get_weather": get_weather
}Describe tools to the model
tool_definitions = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
}
}
]Run the agent loop
def run_agent(question: str, max_turns: int = 5) -> str:
messages = [{"role": "user", "content": question}]
for _ in range(max_turns):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tool_definitions
)
choice = response.choices[0]
if choice.message.content:
return choice.message.content
if choice.message.tool_calls:
messages.append({
"role": "assistant",
"content": "",
"tool_calls": [tc.model_dump() for tc in choice.message.tool_calls]
})
for tc in choice.message.tool_calls:
name = tc.function.name
args = json.loads(tc.function.arguments)
result = tools[name](**args)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": result
})
return "I could not find an answer."
print(run_agent("What is the weather in Paris?"))Add memory
Keep a conversation history across calls so the agent remembers context.
class Agent:
def __init__(self):
self.history = []
def chat(self, message: str) -> str:
self.history.append({"role": "user", "content": message})
answer = run_agent_with_history(self.history)
self.history.append({"role": "assistant", "content": answer})
return answerAdd more tools
Good tools to add next:
search_web(query)using an API like Serper or Tavilyread_file(path)for local file accesssend_email(to, subject, body)for automationcalculate(expression)for math reliability
From scratch to framework
Once you understand the loop, you can adopt LangGraph, CrewAI, or AutoGen with confidence. The concepts are the same; the frameworks just handle routing, memory, and parallelism for you.
Next steps
- Add error handling and retries
- Let the agent ask clarifying questions
- Persist history to a database
- Build a web UI with Streamlit or Gradio
Building an AI agent from scratch is the best way to understand how models, tools, and memory fit together.
Khalid Abdelaty
Abid Ali Awan
Tim Lu
Filip Schouwenaars