ReAct Agent with Retrieval
Build a ReAct agent pattern using LangGraph with a retriever tool. Implement the observe-think-act loop: retrieve relevant docs, reason about the context, and generate answers.
Learning Goals
- Build a ReAct agent with retrieval as a tool
- Implement observe-think-act loop in LangGraph
ReAct Agent with Retrieval
The ReAct pattern (Reason + Act) is the foundation of modern AI agents. In this pattern, the LLM follows a loop: it Reasons about the current state, decides to take an Action (like calling a retriever tool), and then Observes the result. This cycle continues until the agent has enough information to provide a final answer.
In this lesson, we will implement a ReAct agent using LangGraph that can dynamically decide when to retrieve information from our vector store.
Learning Goals
- Define the ReAct reasoning loop.
- Build a stateful graph that connects an LLM with a retriever tool.
- Implement conditional routing to stop the loop when an answer is found.
Core Concepts
1. The Observe-Think-Act Loop
Unlike a chain, the ReAct agent is non-linear.
- Think: "I need to know the price of gold in 2023 to answer this."
- Act: Call
search_finance_datatool. - Observe: "The tool returned $1,940/oz."
- Think: "Now I have the data. I can generate the final answer."
2. StateGraph: The Agent's Map
In LangGraph, we define the agent as a StateGraph. This graph has:
- State: A shared object that tracks the list of messages (conversation history).
- Nodes:
agent(thinking) andaction(tool execution). - Edges: Logic that flows from agent to tools and back.
Agent State Machine
Building the ReAct Graph
- 1Step 1
Use a simple dictionary or a TypedDict to track messages:
1from typing import Annotated, TypedDict 2from langgraph.graph.message import add_messages 3 4class State(TypedDict): 5 messages: Annotated[list, add_messages] - 2Step 2
Create a
StateGraphand define the nodes:1from langgraph.graph import StateGraph, START, END 2 3workflow = StateGraph(State) 4 5# Define the nodes 6workflow.add_node("agent", call_model) 7workflow.add_node("tools", tool_node) - 3Step 3
Use conditional logic to decide if tools are needed:
1workflow.add_edge(START, "agent") 2workflow.add_conditional_edges( 3 "agent", 4 should_continue, # Logic gate function 5) 6workflow.add_edge("tools", "agent") - 4Step 4
1app = workflow.compile() 2for chunk in app.stream({"messages": [("user", "What is RAG?")]}): 3 print(chunk)
Example: The Multi-Step Researcher
Imagine you ask an agent: "Compare the weather in Tokyo today with the average weather in 1990." The agent will:
- Call a
live_weathertool for Tokyo. - Call a
historical_weather_retrievertool for 1990 data. - Think about the difference.
- Finalize the response. A standard RAG chain would struggle to coordinate these two separate data sources sequentially.
Common Mistakes
- Infinite Loops: If the agent doesn't realize it has the answer, it might keep calling the tool. Ensure your prompt clearly says: "If you have the information, provide the final answer."
- Forgetting Tool Nodes: Tools must be executed in a separate node, not inside the LLM node. This keeps the architecture clean and allows for "Human-in-the-loop" approval if needed.
Recap
- ReAct combines reasoning with tool execution.
- LangGraph's
StateGraphis the standard way to build these loops. - Conditional edges are the "Decision Gates" of the agent.
Knowledge Check
What does the 'Observe' step in the ReAct loop represent?