Repository Public
1LangGraph is a framework for building stateful LLM applications, making it a2good choice for constructing ReAct (Reasoning and Acting) Agents.34ReAct agents combine LLM reasoning with action execution. They iteratively5think, use tools, and act on observations to achieve user goals, dynamically6adapting their approach. Introduced in ["ReAct: Synergizing Reasoning and Acting7in Language Models"](https://arxiv.org/abs/2210.03629) (2023), this pattern8tries to mirror human-like, flexible problem-solving over rigid workflows.910LangGraph offers a prebuilt ReAct agent ([`create_react_agent`](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent)),11that shines when you need more control and customization for your ReAct12implementations. This guide will show you a simplified version.1314LangGraph models agents as graphs using three key components:1516- `State`: Shared data structure (typically `TypedDict` or `Pydantic BaseModel`) representing the application's current snapshot.17- `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.18- `Edges`: Define the next `Node` to execute based on the current `State`, allowing for conditional logic and fixed transitions.1920If you don't have an API Key yet, you can get one from [Google AI21Studio](https://aistudio.google.com/apikey).2223 pip install langgraph langchain-google-genai geopy requests2425Set your API key in the environment variable `GEMINI_API_KEY`.2627 import os2829 # Read your API key from the environment variable or set it manually30 api_key = os.getenv("GEMINI_API_KEY")3132To better understand how to implement a ReAct agent using LangGraph, this guide33will walk through a practical example. You will create an agent whose goal is to34use a tool to find the current weather for a specified location.3536For this weather agent, the `State` will maintain the ongoing conversation37history (as a list of messages) and a counter (as an integer) for the number of38steps taken, for illustrative purposes.3940LangGraph provides a helper function, `add_messages`, for updating state message41lists. It functions as a [reducer](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers),42taking the current list, plus the new messages, and returns a combined list. It43handles updates by message ID and defaults to an "append-only" behavior for new,44unseen messages.4546> [!NOTE]47> **Note:** Since having a list of messages in the state is common, there exists a prebuilt state called `MessagesState` that you can use as a base class. For this example the messages will be listed explicitly.4849 from typing import Annotated,Sequence, TypedDict5051 from langchain_core.messages import BaseMessage52 from langgraph.graph.message import add_messages # helper function to add messages to the state5354 class AgentState(TypedDict):55 """The state of the agent."""56 messages: Annotated[Sequence[BaseMessage], add_messages]57 number_of_steps: int5859Next, define your weather tool.6061 from langchain_core.tools import tool62 from geopy.geocoders import Nominatim63 from pydantic import BaseModel, Field64 import requests6566 geolocator = Nominatim(user_agent="weather-app")6768 class SearchInput(BaseModel):69 location:str = Field(description="The city and state, e.g., San Francisco")70 date:str = Field(description="the forecasting date for when to get the weather format (yyyy-mm-dd)")7172 @tool("get_weather_forecast", args_schema=SearchInput, return_direct=True)73 def get_weather_forecast(location: str, date: str):74 """Retrieves the weather using Open-Meteo API.7576 Takes a given location (city) and a date (yyyy-mm-dd).7778 Returns:79 A dict with the time and temperature for each hour.80 """81 # Note that Colab may experience rate limiting on this service. If this82 # happens, use a machine to which you have exclusive access.83 location = geolocator.geocode(location)84 if location:85 try:86 response = requests.get(f"https://api.open-meteo.com/v1/forecast?latitude={location.latitude}&longitude={location.longitude}&hourly=temperature_2m&start_date={date}&end_date={date}")87 data = response.json()88 return dict(zip(data["hourly"]["time"], data["hourly"]["temperature_2m"]))89 except Exception as e:90 return {"error": str(e)}91 else:92 return {"error": "Location not found"}9394 tools = [get_weather_forecast]9596Now initialize the model and bind the tools to the model.9798 from datetime import datetime99 from langchain_google_genai import ChatGoogleGenerativeAI100101 # Create LLM class102 llm = ChatGoogleGenerativeAI(103 model= "gemini-3.8-flash",104 temperature=1.0,105 max_retries=2,106 google_api_key=api_key,107 )108109 # Bind tools to the model110 model = llm.bind_tools([get_weather_forecast])111112 # Test the model with tools113 res=model.invoke(f"What is the weather in Berlin on {datetime.today()}?")114115 print(res)116117The last step before you can run your agent is to define your nodes and edges.118In this example, you have two nodes and one edge.119120- `call_tool` node that executes your tool method. LangGraph has a prebuilt node for this called [ToolNode](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/).121- `call_model` node that uses the `model_with_tools` to call the model.122- `should_continue` edge that decides whether to call the tool or the model.123124The number of nodes and edges is not fixed. You can add as many nodes and edges125as you want to your graph. For example, you could add a node for adding126structured output or a self-verification/reflection node to check the model127output before calling the tool or the model.128129 from langchain_core.messages import ToolMessage130 from langchain_core.runnables import RunnableConfig131132 tools_by_name = {tool.name: tool for tool in tools}133134 # Define our tool node135 def call_tool(state: AgentState):136 outputs = []137 # Iterate over the tool calls in the last message138 for tool_call in state["messages"][-1].tool_calls:139 # Get the tool by name140 tool_result = tools_by_name[tool_call["name"]].invoke(tool_call["args"])141 outputs.append(142 ToolMessage(143 content=tool_result,144 name=tool_call["name"],145 tool_call_id=tool_call["id"],146 )147 )148 return {"messages": outputs}149150 def call_model(151 state: AgentState,152 config: RunnableConfig,153 ):154 # Invoke the model with the system prompt and the messages155 response = model.invoke(state["messages"], config)156 # This returns a list, which combines with the existing messages state157 # using the add_messages reducer.158 return {"messages": [response]}159160 # Define the conditional edge that determines whether to continue or not161 def should_continue(state: AgentState):162 messages = state["messages"]163 # If the last message is not a tool call, then finish164 if not messages[-1].tool_calls:165 return "end"166 # default to continue167 return "continue"168169With all of the agent components ready, you can now assemble them.170171 from langgraph.graph import StateGraph, END172173 # Define a new graph with our state174 workflow = StateGraph(AgentState)175176 # 1. Add the nodes177 workflow.add_node("llm", call_model)178 workflow.add_node("tools", call_tool)179 # 2. Set the entrypoint as `agent`, this is the first node called180 workflow.set_entry_point("llm")181 # 3. Add a conditional edge after the `llm` node is called.182 workflow.add_conditional_edges(183 # Edge is used after the `llm` node is called.184 "llm",185 # The function that will determine which node is called next.186 should_continue,187 # Mapping for where to go next, keys are strings from the function return,188 # and the values are other nodes.189 # END is a special node marking that the graph is finish.190 {191 # If `tools`, then we call the tool node.192 "continue": "tools",193 # Otherwise we finish.194 "end": END,195 },196 )197 # 4. Add a normal edge after `tools` is called, `llm` node is called next.198 workflow.add_edge("tools", "llm")199200 # Now we can compile and visualize our graph201 graph = workflow.compile()202203You can visualize your graph using the `draw_mermaid_png` method.204205 from IPython.display import Image, display206207 display(Image(graph.get_graph().draw_mermaid_png()))208209210211Now run the agent.212213 from datetime import datetime214 # Create our initial message dictionary215 inputs = {"messages": [("user", f"What is the weather in Berlin on {datetime.today()}?")]}216217 # call our graph with streaming to see the steps218 for state in graph.stream(inputs, stream_mode="values"):219 last_message = state["messages"][-1]220 last_message.pretty_print()221222You can now continue with your conversation, ask for the weather in another223city, or request a comparison.224225 state["messages"].append(("user", "Would it be warmer in Munich?"))226227 for state in graph.stream(state, stream_mode="values"):228 last_message = state["messages"][-1]229 last_message.pretty_print()