DEV Community

Cover image for Build Your Own AI Agent from Scratch Using Python + LangChain + OpenAI in 2026
Emma Schmidt
Emma Schmidt

Posted on

Build Your Own AI Agent from Scratch Using Python + LangChain + OpenAI in 2026

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
Enter fullscreen mode Exit fullscreen mode

Install the required packages:

pip install langchain langchain-openai langchain-community openai python-dotenv duckduckgo-search numexpr
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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
)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)}"
Enter fullscreen mode Exit fullscreen mode

⚠️ Security note: The eval() here is sandboxed with empty builtins. For production use, use the numexpr library 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}")
Enter fullscreen mode Exit fullscreen mode

Step 5 - Bundle the Tools

tools = [web_search, calculator, get_weather]
Enter fullscreen mode Exit fullscreen mode

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
)
Enter fullscreen mode Exit fullscreen mode

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"])
Enter fullscreen mode Exit fullscreen mode

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"])
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Swap to an open-source model:

from langchain_community.llms import Ollama

llm = Ollama(model="llama3")
Enter fullscreen mode Exit fullscreen mode

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 use 0 for 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)