jazelevator.com

Creating a Hyper AI Agent with LangGraph: A Comprehensive Guide

Written on

Chapter 1: Introduction to LangGraph

LangChain has been a prominent open-source framework for over a year, providing essential tools and modules for developing AI applications based on large models. Recently, LangChain unveiled a new library called LangGraph, which enhances and streamlines the process of creating and managing AI agents and their runtimes.

In this article, we will delve into the fundamentals of LangGraph, covering topics such as the definitions of agents and agent runtimes, the features of LangGraph, and the steps to build an agent executor within this framework. We will also examine the Chat Agent Executor in LangGraph and explore how to modify it to include human feedback in the loop.

Before we proceed, if you find this topic intriguing and wish to support my work, I’d appreciate it if you could clap for this article 50 times. Your support means a lot! Follow me on Medium for more articles. If you're not a member yet, consider signing up through my referral link for just $5 a month—less than a fancy coffee!

What are Agents and Agent Runtimes?

In the LangChain ecosystem, an agent operates as a system guided by a language model that determines the actions it should take. An agent runtime, on the other hand, is the underlying system that keeps the agent functioning by continuously making decisions, recording observations, and maintaining this operational loop until the task is completed.

LangChain simplifies agent customization through its expression language, and LangGraph takes this further by offering greater flexibility and adaptability in customizing the agent runtime. While the traditional agent runtime was based on the Agent EX class, LangGraph introduces more variety to enhance functionality.

Key Features of LangGraph

One of the standout features of LangGraph is its incorporation of cycles into the agent runtime. This allows for repetitive loops that are crucial for agent functionality, distinguishing it from non-cyclical frameworks.

LangGraph currently supports two primary agent runtimes:

  1. The Agent Executor, which parallels LangChain's executor but has been restructured within LangGraph.
  2. The Chat Agent Executor, which manages agent states as a list of messages—ideal for chat-based models that utilize messages for functions and responses.

How to Build an Agent Executor

Creating an agent executor in LangGraph mirrors the process in LangChain and is surprisingly straightforward. Let’s get started!

First, we need to establish our environment by installing several necessary packages: LangChain, LangChain OpenAI, and Tavily Python. These packages will allow us to leverage existing LangChain agent classes, power our agent with OpenAI's language models, and utilize Tavily Python for search capabilities.

pip install --quiet -U langchain langchain_openai tavily-python

Next, we will configure our API keys for OpenAI, Tavily, and LangSmith. The latter is particularly important for logging and observability, though it is currently in private beta. If you require access, feel free to reach out.

import os

import getpass

os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")

os.environ["TAVILY_API_KEY"] = getpass.getpass("Tavily API Key:")

os.environ["LANGCHAIN_TRACING_V2"] = "true"

os.environ["LANGCHAIN_API_KEY"] = getpass.getpass("LangSmith API Key:")

The first step in our notebook is to create a LangChain agent. This involves choosing a language model, establishing a search tool, and setting up our agent. For detailed instructions, refer to the LangChain documentation.

from langchain import hub

from langchain.agents import create_openai_functions_agent

from langchain_openai.chat_models import ChatOpenAI

from langchain_community.tools.tavily_search import TavilySearchResults

tools = [TavilySearchResults(max_results=1)]

# Get the prompt to use - you can modify this!

prompt = hub.pull("hwchase17/openai-functions-agent")

# Choose the LLM that will drive the agent

llm = ChatOpenAI(model="gpt-3.5-turbo-1106", streaming=True)

# Construct the OpenAI Functions agent

agent_runnable = create_openai_functions_agent(llm, tools, prompt)

Next, we will define the state of our graph, which tracks changes over time. This state allows each node in our graph to update the overall state, eliminating the need to pass it around constantly.

from typing import TypedDict, Annotated, List, Union

from langchain_core.agents import AgentAction, AgentFinish

from langchain_core.messages import BaseMessage

import operator

class AgentState(TypedDict):

input: str

chat_history: list[BaseMessage]

agent_outcome: Union[AgentAction, AgentFinish, None]

intermediate_steps: Annotated[list[tuple[AgentAction, str]], operator.add]

After setting up our state, we will focus on defining the nodes and edges in our graph. We need two main nodes: one to run the agent and another to execute tools based on the agent's decisions.

from langchain_core.agents import AgentFinish

from langgraph.prebuilt.tool_executor import ToolExecutor

tool_executor = ToolExecutor(tools)

# Define the agent

def run_agent(data):

agent_outcome = agent_runnable.invoke(data)

return {"agent_outcome": agent_outcome}

# Define the function to execute tools

def execute_tools(data):

agent_action = data['agent_outcome']

output = tool_executor.invoke(agent_action)

return {"intermediate_steps": [(agent_action, str(output))]}

Finally, we construct our graph, defining nodes, setting an entry point, and establishing edges—both conditional and normal. Once compiled, the graph is ready to be utilized like any LangChain runnable.

from langgraph.graph import END, StateGraph

workflow = StateGraph(AgentState)

workflow.add_node("agent", run_agent)

workflow.add_node("action", execute_tools)

workflow.set_entry_point("agent")

workflow.add_conditional_edges(

"agent",

should_continue,

{

"continue": "action",

"end": END

}

)

workflow.add_edge('action', 'agent')

app = workflow.compile()

We will run our executor with some input data to see it in action. This will involve streaming results from each node, enabling us to observe the agent's decisions, the tools executed, and the overall state at each stage.

inputs = {"input": "what is the weather in sf", "chat_history": []}

for s in app.stream(inputs):

print(list(s.values())[0])

print("----")

For a visual understanding, we can explore these processes in LangSmith, which provides a detailed view of each step, including the prompts and responses involved in the execution.

The first video titled "Creating an AI Agent with LangGraph Llama 3 & Groq" provides an in-depth look at setting up an AI agent within LangGraph, showcasing its features and capabilities.

Exploring the Chat Agent Executor

Next, we will explore the Chat Agent Executor in LangGraph, a tool designed specifically for chat-based models. This executor uniquely operates on a list of input messages, updating the agent's state over time by appending new messages to this list.

To set up, we will need to install the same packages as before and set our API keys.

pip install --quiet -U langchain langchain_openai tavily-python

The process of defining the agent state and creating nodes will mirror our earlier setup.

How to Modify the Chat Agent Executor

We can enhance the Chat Agent Executor to include a "human in the loop" feature, allowing for human validation before executing tool actions.

The major change involves the call_tool function, which will prompt the user for confirmation before proceeding with any tool action.

def call_tool(state):

messages = state['messages']

last_message = messages[-1]

action = ToolInvocation(

tool=last_message.additional_kwargs["function_call"]["name"],

tool_input=json.loads(last_message.additional_kwargs["function_call"]["arguments"]),

)

response = input(prompt=f"[y/n] continue with: {action}?")

if response == "n":

raise ValueError

response = tool_executor.invoke(action)

function_message = FunctionMessage(content=str(response), name=action.tool)

return {"messages": [function_message]}

When running the modified executor, it will request approval before executing any tool action. If the user responds with "yes," it continues; if "no," it raises an error.

For more detailed capabilities and examples, refer to the following video.

The second video titled "Tutorial 1-Getting Started With LangGraph - Building Stateful Multi AI Agents" serves as a comprehensive guide for beginners looking to understand the foundational elements of LangGraph.

Conclusion

In conclusion, you now have the knowledge to create a hyper AI agent using LangGraph. I hope this overview has provided you with a solid understanding of its capabilities. As a next step, I encourage you to explore LangGraph further to build more innovative applications.

References

This article was originally published on: Page

🧙‍♂️ I am an AI application expert! If you want to collaborate on a project, feel free to reach out or book a 1-On-1 Consulting Call with me.