Files
langgraph/examples/create-react-agent.ipynb
T
2024-06-13 19:21:56 -04:00

32 KiB

How to create a ReAct agent

In [1]:
%%capture --no-stderr
%pip install -U langgraph langchain-openai

Setup

In [2]:
import getpass
import os


def _set_env(var: str):
    if not os.environ.get(var):
        os.environ[var] = getpass.getpass(f"{var}: ")


_set_env("OPENAI_API_KEY")

# Recommended
_set_env("LANGCHAIN_API_KEY")
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "Create ReAct Agent Tutorial"
OPENAI_API_KEY:  ········

How to create a simple ReAct agent

Let's create a simple ReAct agent app that can check the weather. The app consists of an agent (LLM) and tools. As we interact with the app, we will first call the agent (LLM) to decide if we should use tools. Then we will run a loop:

  1. If the agent said to take an action (i.e. call tool), we'll run the tools and pass the results back to the agent
  2. If the agent did not ask to run tools, we will finish (respond to the user)

In our example we'll use ChatOpenAI as our agent and a custom tool that returns pre-defined values for weather in two cities (NYC & SF)

Define model and tools

In [3]:
from typing import Literal

from langchain_core.tools import tool
from langchain_openai import ChatOpenAI


model = ChatOpenAI(model="gpt-4o", temperature=0)


@tool
def get_weather(city: Literal["nyc", "sf"]):
    """Use this to get weather information."""
    if city == "nyc":
        return "It might be cloudy in nyc"
    elif city == "sf":
        return "It's always sunny in sf"
    else:
        raise AssertionError("Unknown city")

tools = [get_weather]

Define the graph

In [4]:
from langgraph.prebuilt import create_react_agent
graph = create_react_agent(model, tools=tools)
In [5]:
from IPython.display import display, Image

display(Image(graph.get_graph().draw_mermaid_png()))
In [6]:
def print_stream(stream):
    for s in stream:
        message = s["messages"][-1]
        if isinstance(message, tuple):
            print(message)
        else:
            message.pretty_print()

Let's run the app with an input that needs a tool call

In [7]:
from langchain_core.tools import Tool
In [8]:
inputs = {"messages": [("user", "what is the weather in sf")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================ Human Message =================================

what is the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_g6w9lHn3fxYo2ABE3Ihhprbr)
 Call ID: call_g6w9lHn3fxYo2ABE3Ihhprbr
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

Now let's try a question that doesn't need tools

In [9]:
inputs = {"messages": [("user", "who built you?")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================ Human Message =================================

who built you?
================================== Ai Message ==================================

I was created by OpenAI, a research organization focused on developing and advancing artificial intelligence technology.

How to add system prompt to create_react_agent

There are several ways to customize prompt, all of which are controlled by messages_modifier param. You can pass:

  • system message string / SystemMessage that will be prepended to the list of messages
  • a function that takes a list of messages and transforms them into an output that can be passed to the language model
In [10]:
system_prompt = "You are a helpful bot named Fred."
graph = create_react_agent(model, tools, messages_modifier=system_prompt)

inputs = {"messages": [("user", "What's your name? And what's the weather in SF?")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================ Human Message =================================

What's your name? And what's the weather in SF?
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_PGwTiytTVAAvNKWp4nznPi4s)
 Call ID: call_PGwTiytTVAAvNKWp4nznPi4s
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

My name is Fred. The weather in San Francisco is currently sunny.

We can also add a more complex prompt for the LLM:

In [11]:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful bot named Fred."),
    ("user", "My name is Joe"),
    ("placeholder", "{messages}"),
])

def modify_messages(messages: list):
    # You can do more complex modifications here
    return prompt.invoke({"messages": messages})

graph = create_react_agent(model, tools, messages_modifier=modify_messages)

inputs = {"messages": [("user", "What's my name? And what's the weather in SF?")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================ Human Message =================================

What's my name? And what's the weather in SF?
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_scpzIjdK3l411zcEn2T00Xm0)
 Call ID: call_scpzIjdK3l411zcEn2T00Xm0
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

Your name is Joe. The weather in San Francisco is always sunny.

How to add memory to create_react_agent

We can add "chat memory" to the graph with LangGraph's checkpointer, to retain the chat context between interactions

In [12]:
from langgraph.checkpoint import MemorySaver
graph = create_react_agent(model, tools, checkpointer=MemorySaver())

config = {"configurable": {"thread_id": "1"}}
inputs = {"messages": [("user", "What's the weather in NYC?")]}

print_stream(graph.stream(inputs, config=config, stream_mode="values"))
================================ Human Message =================================

What's the weather in NYC?
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_C5yEOD1GhlVPX9Gc5nnqgUXF)
 Call ID: call_C5yEOD1GhlVPX9Gc5nnqgUXF
  Args:
    city: nyc
================================= Tool Message =================================
Name: get_weather

It might be cloudy in nyc
================================== Ai Message ==================================

The weather in NYC might be cloudy.

Notice that when we pass the same the same thread ID, the chat history is preserved

In [13]:
inputs = {"messages": [("user", "What's it known for?")]}
print_stream(graph.stream(inputs, config=config, stream_mode="values"))
================================ Human Message =================================

What's it known for?
================================== Ai Message ==================================

New York City (NYC) is known for many things, including:

1. **Landmarks and Attractions**: 
   - **Statue of Liberty**: A symbol of freedom and democracy.
   - **Times Square**: Known for its bright lights, Broadway theaters, and bustling atmosphere.
   - **Central Park**: A large urban park offering various recreational activities.
   - **Empire State Building**: An iconic skyscraper with an observation deck offering panoramic views of the city.
   - **Brooklyn Bridge**: A historic bridge connecting Manhattan and Brooklyn.

2. **Cultural Diversity**: NYC is a melting pot of cultures, languages, and cuisines, making it one of the most diverse cities in the world.

3. **Arts and Entertainment**: 
   - **Broadway**: Renowned for its world-class theater productions.
   - **Museums**: Such as the Metropolitan Museum of Art, the Museum of Modern Art (MoMA), and the American Museum of Natural History.
   - **Music and Nightlife**: A vibrant scene with numerous music venues, bars, and clubs.

4. **Financial Hub**: 
   - **Wall Street**: The financial district is home to the New York Stock Exchange and numerous financial institutions.

5. **Fashion and Shopping**: 
   - **Fifth Avenue**: Known for its high-end shopping.
   - **Fashion Week**: One of the major fashion events held twice a year.

6. **Cuisine**: 
   - **Diverse Food Scene**: From street food like hot dogs and pretzels to fine dining and international cuisines.
   - **Famous Foods**: New York-style pizza, bagels, and cheesecake.

7. **Media and Publishing**: 
   - Home to major media companies, newspapers like The New York Times, and numerous publishing houses.

8. **Sports**: 
   - Home to several major sports teams, including the New York Yankees (baseball), New York Mets (baseball), New York Knicks (basketball), Brooklyn Nets (basketball), New York Giants (football), and New York Jets (football).

9. **Education and Research**: 
   - Prestigious institutions like Columbia University, New York University (NYU), and Rockefeller University.

10. **Public Transportation**: 
    - An extensive subway system, buses, and taxis that make getting around the city convenient.

NYC is a city that never sleeps, offering endless opportunities for exploration and experiences.

And if we pass a different thread ID, the chat history is reset

In [14]:
inputs = {"messages": [("user", "What's it known for?")]}
print_stream(graph.stream(inputs, config={"configurable": {"thread_id": 2}}, stream_mode="values"))
================================ Human Message =================================

What's it known for?
================================== Ai Message ==================================

Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?

How to add human-in-the-loop to create_react_agent

Let's add an interrupt to let the user confirm before LLM takes an action:

In [15]:
graph = create_react_agent(
    model, tools, interrupt_before=["tools"], checkpointer=MemorySaver()
)

config = {"configurable": {"thread_id": "42"}}
inputs = {"messages": [("user", "What's the weather in SF?")]}

print_stream(graph.stream(inputs, config, stream_mode="values"))
================================ Human Message =================================

What's the weather in SF?
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_I7B9YW4ENth7QXYzDpiIoLCE)
 Call ID: call_I7B9YW4ENth7QXYzDpiIoLCE
  Args:
    city: sf
In [16]:
snapshot = graph.get_state(config)
print("Next step: ", snapshot.next)
Next step:  ('tools',)
In [17]:
print_stream(graph.stream(None, config, stream_mode="values"))
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.