A step-by-step guide for developers who want to go beyond ChatGPT wrappers and build something real.
Introduction
AI agents are no longer a research concept. They are production tools being shipped by teams worldwide right now. Whether you are looking to Hire Python developers to build intelligent automation for your company, or you are a solo dev leveling up your own skills, understanding how to build an AI agent from scratch is one of the most valuable things you can learn in 2026. In this guide, we will build a fully functional AI agent using Python, LangChain, and the OpenAI API. One that can reason, use tools, and complete multi-step tasks autonomously. No fluff. Just working code and clear explanations.
What Exactly Is an AI Agent?
Before writing a single line of code, let us get the definition right.
A standard LLM call looks like this:
User Input > LLM > Output
An AI agent looks like this:
User Input > LLM > Decision > Tool Use > Observe Result > LLM > Decision > Final Output
The key difference is the loop. An agent can:
- Decide which tool to use based on context
- Call that tool (search the web, run code, query a database)
- Observe the result
- Decide what to do next
- Repeat until it reaches a final answer
This is called the ReAct pattern (Reasoning + Acting), and it is the foundation of almost every modern AI agent framework.
What We Are Building
By the end of this tutorial, you will have an AI agent that can:
- Answer questions using web search
- Perform math calculations
- Look up current weather
- Chain multiple tools together to solve complex tasks
All orchestrated automatically by LangChain + OpenAI. You just give it a goal in plain English.
Prerequisites
- Python 3.10+
- An OpenAI API key
- Basic familiarity with Python functions and pip
Step 1 - Project Setup
Create a clean project directory and set up a virtual environment.
mkdir ai-agent-tutorial
cd ai-agent-tutorial
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
Install the required packages:
pip install langchain langchain-openai langchain-community openai python-dotenv duckduckgo-search numexpr
Create a .env file in your project root:
OPENAI_API_KEY=your_openai_api_key_here
Step 2 - Load Environment Variables
Create a file called agent.py and start with:
from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
Never hardcode your API key. Always use .env and add it to .gitignore.
Step 3 - Initialize the LLM
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4o",
temperature=0,
api_key=OPENAI_API_KEY
)
We set temperature=0 because agents need deterministic, logical reasoning, not creative text generation. Lower temperature = more consistent tool selection.
Step 4 - Define the Tools
Tools are just Python functions wrapped with a LangChain decorator. The agent reads the docstring to understand what the tool does and when to use it, so write clear docstrings.
Tool 1 - Web Search
from langchain_community.tools import DuckDuckGoSearchRun
from langchain.tools import tool
search = DuckDuckGoSearchRun()
@tool
def web_search(query: str) -> str:
"""
Search the web for current information.
Use this when the user asks about recent events,
news, or anything that requires up-to-date data.
"""
return search.run(query)
Tool 2 - Math Calculator
@tool
def calculator(expression: str) -> str:
"""
Evaluate a mathematical expression.
Use this for any arithmetic, algebra, or numeric calculation.
Input must be a valid Python math expression as a string.
Example: '(100 * 1.08) ** 2'
"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"Error evaluating expression: {str(e)}"
⚠️ Security note: The
eval()here is sandboxed with empty builtins. For production use, use thenumexprlibrary or a dedicated math parser instead.
Tool 3 - Weather Lookup (Simulated)
@tool
def get_weather(city: str) -> str:
"""
Get the current weather for a city.
Use this when the user asks about weather conditions
in a specific location.
"""
mock_data = {
"london": "Cloudy, 14°C, 80% humidity",
"new york": "Sunny, 22°C, 55% humidity",
"tokyo": "Rainy, 18°C, 90% humidity",
"mumbai": "Hot and humid, 34°C, 75% humidity",
}
return mock_data.get(city.lower(), f"Weather data not available for {city}")
Step 5 - Bundle the Tools
tools = [web_search, calculator, get_weather]
LangChain will pass this list to the agent, which learns what each tool does from the docstrings automatically.
Step 6 - Create the Agent
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(
llm=llm,
tools=tools,
prompt=prompt
)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10,
handle_parsing_errors=True
)
Step 7 - Run the Agent
if __name__ == "__main__":
response = agent_executor.invoke({
"input": "Who won the most recent FIFA World Cup and when was it held?"
})
print("\n✅ Answer:", response["output"])
response = agent_executor.invoke({
"input": "If I invest $5,000 at 8% annual compound interest for 10 years, how much will I have?"
})
print("\n✅ Answer:", response["output"])
response = agent_executor.invoke({
"input": "What is the current population of Japan? Now divide that by 1,000,000 and round it."
})
print("\n✅ Answer:", response["output"])
Step 8 - Sample Output
Entering new AgentExecutor chain...
Thought: I need to find the current population of Japan.
Action: web_search
Action Input: current population of Japan 2026
Observation: Japan's population is approximately 123.2 million as of 2026.
Thought: Now I need to divide 123,200,000 by 1,000,000.
Action: calculator
Action Input: 123200000 / 1000000
Observation: 123.2
Thought: I now know the final answer.
Final Answer: Japan's population is 123.2 million, which equals 123.2 when divided by 1,000,000.
Finished chain.
Full agent.py - Complete Code
from dotenv import load_dotenv
import os
from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchRun
from langchain.tools import tool
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
load_dotenv()
llm = ChatOpenAI(
model="gpt-4o",
temperature=0,
api_key=os.getenv("OPENAI_API_KEY")
)
search = DuckDuckGoSearchRun()
@tool
def web_search(query: str) -> str:
"""Search the web for current information about recent events or news."""
return search.run(query)
@tool
def calculator(expression: str) -> str:
"""Evaluate a mathematical expression. Input must be a valid Python math expression."""
try:
return str(eval(expression, {"__builtins__": {}}, {}))
except Exception as e:
return f"Error: {str(e)}"
@tool
def get_weather(city: str) -> str:
"""Get current weather for a city."""
mock_data = {
"london": "Cloudy, 14°C, 80% humidity",
"new york": "Sunny, 22°C, 55% humidity",
"tokyo": "Rainy, 18°C, 90% humidity",
"mumbai": "Hot and humid, 34°C, 75% humidity",
}
return mock_data.get(city.lower(), f"Weather data not available for {city}")
tools = [web_search, calculator, get_weather]
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10,
handle_parsing_errors=True
)
if __name__ == "__main__":
response = agent_executor.invoke({
"input": "What is the weather in Tokyo and what is 34°C in Fahrenheit?"
})
print("\n✅ Answer:", response["output"])
How to Extend This Agent
Add memory:
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
agent_executor = AgentExecutor(agent=agent, tools=tools, memory=memory, verbose=True)
Add a custom database tool:
@tool
def query_user_database(user_id: str) -> str:
"""Look up user information from the internal database by user ID."""
return f"User {user_id}: Name=John, Plan=Pro, Joined=2026-01"
Swap to an open-source model:
from langchain_community.llms import Ollama
llm = Ollama(model="llama3")
Common Mistakes to Avoid
- Vague tool docstrings - the agent picks tools by reading them. Be specific or it hallucinates.
-
No
max_iterations- a confused agent loops forever and drains your API credits. -
temperature > 0- makes tool selection unpredictable. Always use0for agents. -
Skipping
handle_parsing_errors=True- malformed output will crash silently without it.
What to Build Next
- Research agent - searches, summarises, and writes a report on any topic
- Code reviewer agent - reads a GitHub PR and suggests improvements
- Customer support agent - handles tier-1 tickets using your product database
- Data analyst agent - takes a CSV and answers plain-English questions about it
Conclusion
You have just built a working AI agent from scratch. One that reasons, selects tools, observes results, and loops until it finds the answer. This is not a toy demo. The same architecture powers production agents at companies shipping real products today.
The concepts here, ReAct loops, tool definitions, memory, and executor configuration, transfer directly to more advanced frameworks like LangGraph, AutoGen, and CrewAI.
What kind of agent are you going to build? Drop it in the comments. I read every single one. And if this helped you, a ❤️ goes a long way in helping other devs find this post.
Found this useful? Follow me for more Python, AI, and backend deep dives every week.
Top comments (0)