← Back to Learning Hub
LangChainJune 5, 2023

Building a Simple ReAct Agent with LangChain

Learn how to create a ReAct agent using LangChain's agent framework to combine reasoning and action for enhanced problem-solving capabilities.

LangChain's agent framework provides powerful abstractions for building AI systems that can interact with tools and make decisions. In this tutorial, we'll explore how to create a ReAct agent, which combines reasoning and action to enhance the problem-solving capabilities of language models.

Understanding ReAct Agents

ReAct (Reasoning + Acting) is a paradigm that enhances language models by combining:

  • Reasoning: The model explains its thought process
  • Acting: The model uses tools to gather information or perform actions

This approach allows agents to better handle complex tasks by breaking them down into a series of thoughts and actions, similar to how humans approach problem-solving.

Implementing a Basic ReAct Agent

Let's start by implementing a simple agent that can solve math problems using a calculator tool:

from langchain.agents import AgentType, initialize_agent
from langchain.tools import BaseTool
from langchain.llms import OpenAI

# Define your custom tools
class Calculator(BaseTool):
    name = "Calculator"
    description = "Useful for performing mathematical calculations"
    
    def _run(self, query):
        try:
            return eval(query)
        except Exception as e:
            return f"Error: {e}"
            
    def _arun(self, query):
        raise NotImplementedError("This tool does not support async")

# Initialize the LLM
llm = OpenAI(temperature=0)

# Create the agent
tools = [Calculator()]
agent = initialize_agent(
    tools, 
    llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

This code creates a ReAct agent by:

  1. Defining a Calculator tool that can evaluate mathematical expressions
  2. Initializing an OpenAI language model with temperature=0 for deterministic responses
  3. Creating the agent using the ZERO_SHOT_REACT_DESCRIPTION agent type

Testing the Agent

Now let's test our agent with a simple math problem:

agent.run("What is the result of (17 * 42) / 3.5?")

# Output:
# > Entering new AgentExecutor chain...
# I need to calculate (17 * 42) / 3.5.
# First, I'll calculate 17 * 42 = 714.
# Then, I'll divide 714 by 3.5.
# Action: Calculator
# Action Input: (17 * 42) / 3.5
# Observation: 204.0
# I now know the final answer.
# Final Answer: The result of (17 * 42) / 3.5 is 204.
# > Finished chain.

Notice how the agent:

  1. First reasons about the problem: "I need to calculate (17 * 42) / 3.5..."
  2. Decides to use the Calculator tool: "Action: Calculator"
  3. Observes the result: "Observation: 204.0"
  4. Provides the final answer after reasoning

Adding Multiple Tools

ReAct agents become more powerful when they can choose between multiple tools. Let's add a search tool to our agent:

from langchain.utilities import SerpAPIWrapper
from langchain.tools import Tool

# Set up the search tool
search = SerpAPIWrapper()
search_tool = Tool(
    name="Search",
    func=search.run,
    description="Useful for searching the web for information"
)

# Create a more capable agent
tools = [Calculator(), search_tool]
agent = initialize_agent(
    tools, 
    llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# Test with a more complex query
agent.run("What is the population of France divided by the square root of 25?")

With this enhanced agent, it can now:

  1. Search the web to find the population of France
  2. Use the calculator to compute the square root of 25
  3. Perform the division operation
  4. Combine these steps to arrive at a final answer

Understanding Agent Execution Trace

One of the benefits of ReAct agents is their transparency. The verbose=True flag allows you to see the complete execution trace, revealing:

  • The agent's reasoning process
  • The sequence of tool calls
  • How the agent integrates information from tool responses

Customizing the Agent's Behavior

You can customize the agent's behavior by adjusting parameters like:

agent = initialize_agent(
    tools, 
    llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    max_iterations=5,
    early_stopping_method="generate",
    handle_parsing_errors=True
)

These parameters control:

  • max_iterations: Maximum number of steps the agent can take
  • early_stopping_method: How to handle reaching max iterations
  • handle_parsing_errors: Whether to gracefully handle parsing errors

Best Practices for ReAct Agents

When building ReAct agents, consider these best practices:

  1. Clear tool descriptions: Make sure each tool has a clear, specific description
  2. Use temperature=0: For deterministic and more reliable reasoning
  3. Add error handling: Implement robust error handling in your tools
  4. Monitor and log: Track your agent's performance using LangSmith
  5. Use human-in-the-loop: For complex tasks, consider adding human oversight

Conclusion

ReAct agents combine the reasoning power of LLMs with the ability to take actions, creating a powerful paradigm for solving complex problems. By following the approach outlined in this tutorial, you can create agents that can perform a wide range of tasks by reasoning through problems step by step.

In our next article, we'll explore how to create multi-agent systems using LangGraph, which allows for even more complex reasoning patterns through agent collaboration.