The LlamaIndex ReAct agent doesn’t just use tools; it uses them to think about how to think.

Let’s watch it in action. Imagine we’ve got a simple RAG setup where our agent can search a document and also perform a calculation.

from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.core.llms import OpenAI # Or your preferred LLM

# Assume documents are loaded and indexed into an 'index' object

# Tool 1: Search the index
def search_index(query: str) -> str:
    """Searches the provided documents for information related to the query."""
    response = index.as_query_engine().query(query)
    return str(response)

# Tool 2: Perform a calculation
def calculate(expression: str) -> str:
    """Evaluates a mathematical expression."""
    try:
        return str(eval(expression))
    except Exception as e:
        return f"Error evaluating expression: {e}"

# Initialize LLM
llm = OpenAI(model="gpt-4-turbo-preview") # Or another capable model

# Create the agent
agent = ReActAgent.from_tools(
    tools=[
        FunctionTool.from_defaults(fn=search_index, name="document_search", description="Search for information within the loaded documents."),
        FunctionTool.from_defaults(fn=calculate, name="calculator", description="Perform mathematical calculations."),
    ],
    llm=llm,
    verbose=True # Crucial for seeing the ReAct loop
)

# Now, let's ask it a question that requires both tools
response = agent.chat("What is the capital of France, and what is 5 + 7?")
print(response)

When you run this, you’ll see a back-and-forth. The agent doesn’t just magically know the answer. It reasons about the question, decides it needs to find the capital of France and also do a calculation, picks the document_search tool for the first part, gets the answer ("Paris"), then decides it needs to do the calculation, picks the calculator tool, gets the answer ("12"), and finally synthesizes them into a coherent response. This "thought-action-observation" cycle is the core of ReAct.

The problem ReAct solves is the gap between an LLM’s knowledge and its ability to interact with external, dynamic information or perform precise, deterministic tasks. An LLM is great at understanding language and generating text, but it can hallucinate facts and struggles with real-time data or complex calculations. Tools provide this external capability. ReAct provides the reasoning framework for the LLM to decide when and how to use these tools, and how to interpret their outputs to achieve a complex goal. It’s not just about having tools; it’s about having a system that can strategically employ them.

Internally, the ReAct agent works by generating a thought process that looks something like this:

  • Thought: "I need to find the capital of France and also calculate 5 + 7."
  • Action: "I should use the document_search tool to find the capital of France."
  • Action Input: {"query": "capital of France"}
  • Observation: "Paris"
  • Thought: "Okay, I found the capital is Paris. Now I need to perform the calculation."
  • Action: "I should use the calculator tool for the math."
  • Action Input: {"expression": "5 + 7"}
  • Observation: "12"
  • Thought: "I have both pieces of information. I can now synthesize the final answer."
  • Final Answer: "The capital of France is Paris, and 5 + 7 is 12."

The verbose=True flag is your window into this internal monologue. You control the agent’s behavior by the tools you provide, their descriptions (which are crucial for the LLM to understand what they do), and the LLM itself. A more capable LLM will generate better reasoning steps and choose tools more effectively.

The "action input" format is critical. When the agent decides to use a tool, it doesn’t just call it; it generates a structured input. For FunctionTool, this is typically a dictionary matching the function’s parameter names. If your tool requires specific JSON or a particular string format, you’d define that in the tool_kwargs when creating the FunctionTool. The LLM learns to conform to these expected input structures based on the tool’s definition and its own training.

A common pitfall is under-describing your tools. If the document_search tool’s description was just "Search," the LLM might not know what to search for or how to formulate the query. A good description guides the LLM’s reasoning. Similarly, for the calculator, if it was described as "Do math," the LLM might struggle to know that expression="5 + 7" is the correct way to pass the problem, as opposed to expression="calculate five plus seven". The LLM is trying to match its understanding of the request to the tool’s documented capabilities and expected inputs.

Once you’ve mastered ReAct with simple tools, the next step is exploring agents that can chain tool calls, where the output of one tool is used to dynamically construct the input for another tool in a more complex sequence.

Want structured learning?

Take the full Llamaindex course →