ReAct agent from scratch with Gemini and LangGraph

LangGraph is a framework for building stateful LLM applications, making it a good choice for constructing ReAct (Reasoning and Acting) Agents.

ReAct agents combine LLM reasoning with action execution. They iteratively think, use tools, and act on observations to achieve user goals, dynamically adapting their approach. Introduced in "ReAct: Synergizing Reasoning and Acting in Language Models" (2023), this pattern tries to mirror human-like, flexible problem-solving over rigid workflows.

LangGraph offers a prebuilt ReAct agent ( create_react_agent), that shines when you need more control and customization for your ReAct implementations. This guide will show you a simplified version.

LangGraph models agents as graphs using three key components:

  • State: Shared data structure (typically TypedDict or Pydantic BaseModel) representing the application's current snapshot.
  • Nodes: Encodes logic of your agents. They receive the current State as input, perform some computation or side-effect, and return an updated State, such as LLM calls or tool calls.
  • Edges: Define the next Node to execute based on the current State, allowing for conditional logic and fixed transitions.

If you don't have an API Key yet, you can get one from Google AI Studio.

pip install langgraph langchain-google-genai geopy requests

Set your API key in the environment variable GEMINI_API_KEY.

import os

# Read your API key from the environment variable or set it manually
api_key = os.getenv("GEMINI_API_KEY")

To better understand how to implement a ReAct agent using LangGraph, this guide will walk through a practical example. You will create an agent whose goal is to use a tool to find the current weather for a specified location.

For this weather agent, the State will maintain the ongoing conversation history (as a list of messages) and a counter (as an integer) for the number of steps taken, for illustrative purposes.

LangGraph provides a helper function, add_messages, for updating state message lists. It functions as a reducer, taking the current list, plus the new messages, and returns a combined list. It handles updates by message ID and defaults to an "append-only" behavior for new, unseen messages.

from typing import Annotated,Sequence