A research agent with custom tools: a calculator, a web search tool, and a document lookup. Give it a complex question and watch it reason through which tools to use and in what order.
ReAct: Reason + Act
A ReAct agent loops: (1) Reason about what to do, (2) Act by calling a tool, (3) Observe the result, (4) Repeat until done. The LLM decides which tool to call and what arguments to pass.
Tools are just Python functions with a name and description. The agent reads the description and decides when to call each tool based on the task at hand.
Creating Custom Tools with @tool
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# Define tools with the @tool decorator
@tool
def calculate(expression: str) -> str:
"""Evaluate a math expression. Input should be a valid Python math expression like '2 + 2' or '100 * 1.15'."""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"Error: {e}"
@tool
def get_company_info(company_name: str) -> str:
"""Look up information about a company. Returns founding year, headquarters, and main products."""
# In real code, this would query a database or API
companies = {
"openai": "Founded 2015, San Francisco, AI research and GPT models",
"anthropic": "Founded 2021, San Francisco, Claude AI models",
"langchain": "Founded 2022, LangChain Inc., AI application framework",
}
return companies.get(company_name.lower(), "Company not found in database")
# Build the agent
model = ChatOpenAI(model="gpt-4o-mini")
tools = [calculate, get_company_info]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful research assistant. Use tools when needed."),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad")
])
agent = create_tool_calling_agent(model, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Run the agent — watch it reason and use tools
result = executor.invoke({
"input": "Anthropic was founded how many years after OpenAI? Calculate the difference."
})
print(result["output"])
verbose=True shows the agent's reasoning process — what tool it chose, what arguments it passed, what it got back. Keep it on while learning; turn it off in production.
Day 4 Complete — What You Learned
- How ReAct agents reason and act in a loop
- Created custom tools with the @tool decorator
- Built an AgentExecutor with multiple tools
- Used verbose mode to watch agent reasoning
Final day: LangGraph for production workflows
Day 5 takes agents to the next level — LangGraph for stateful, cyclic, controllable agent workflows.
Day 5: LangGraph