Introduction to LangGraph

Introduction to LangGraph

Introduction to LangGraph

LangGraph is built on top of LangChain and is primarily focused on creating agents or agentic workflows. While it has other uses, agents are its main purpose.

What Are Agents?

Agents utilize a large language model (LLM) to decide on a sequence of actions.
An LLM serves as a reasoning engine to:

  • Determine which actions to take.
  • Decide in what order to take these actions.

LangGraph also supports:

  • Agent Swarms: Combines multiple agents to enable data sharing, perform various tasks, and allow large language models to interact with each other.

Comparison with Other Frameworks

  • Autogen and Crew AI: High-level frameworks that are easier to use but may lack detailed customization.
  • LangGraph:
    • Has a steeper learning curve but offers a lower-level framework.
    • Provides more control and flexibility for fine-tuning workflows.
    • Ideal for meeting specific and complex requirements.

Core Concepts of LangGraph

Understanding LangGraph requires familiarity with three key concepts: Nodes, Edges, and State.

1. Nodes

  • A node is a function or runnable that performs a specific task.
  • Each node:
    • Processes input.
    • Updates the state based on its operation.

2. Edges

  • Edges define the connection and flow between nodes.
  • They determine the order of execution.
  • Conditional edges can route execution based on the current state.

3. State

  • Represents the data passed between nodes during execution.
  • Each node updates the state with its return value, enabling:
    • Persistent workflows.
    • Dynamic updates.

Workflow Structure

  • Nodes change the state.
  • Edges direct the flow to the next node.
  • The process continues until an end node is reached, marking workflow completion.

Hands-On Learning Approach

  • Start with basic examples that don't use LLMs.
  • Focus on understanding the core concepts (Nodes, Edges, and State).
  • Gradually move to real-world examples involving LLMs.

Key Classes in LangGraph

  1. MessageGraph:
    • A predefined class in LangGraph to create workflows.
    • Provides a simple interface for interacting with LLMs.
  2. END:
    • A special node that marks the end of a workflow.

Creating and Executing a LangGraph Workflow

Example Workflow Code

from langchain_core.messages import HumanMessage
from langgraph.graph import END, MessageGraph
import time

# Function to process messages
def add_one(input: list[HumanMessage]):
    input[0].content = input[0].content + "a"
    time.sleep(1)
    return input

# Create a new graph
graph = MessageGraph()

# Define nodes and edges
graph.add_node("branch_a", add_one)
graph.add_edge("branch_a", "branch_b")
graph.add_edge("branch_a", "branch_c")

graph.add_node("branch_b", add_one)
graph.add_node("branch_c", add_one)

graph.add_edge("branch_b", "final_node")
graph.add_edge("branch_c", "final_node")

graph.add_node("final_node", add_one)
graph.add_edge("final_node", END)

# Set entry point and compile the graph
graph.set_entry_point("branch_a")
runnable = graph.compile()

# Visualize the graph
from IPython.display import Image, display
display(Image(runnable.get_graph().draw_mermaid_png()))

# Execute the workflow
runnable.invoke("a")

Explanation of the Code

  1. Define the Function:
    • The add_one function modifies the content of the first message by appending an "a" and pauses for 1 second.
  2. Create the Graph:
    • An instance of MessageGraph is created to define the workflow.
  3. Add Nodes and Edges:
    • Nodes: Represent tasks to execute (add_one).
    • Edges: Define the flow between nodes.
  4. Set Entry Point:
    • Specify the starting node of the workflow using set_entry_point.
  5. Compile the Graph:
    • Use graph.compile() to create a runnable workflow.
  6. Visualize the Workflow:
    • Visualize the graph using the get_graph method in combination with IPython's display tools.
  7. Execute the Workflow:
    • Use the invoke method to execute the workflow.
  8. HumanMessage:
    • HumanMessages are messages that are passed in from a human to the model.

Workflow Visualization

The workflow consists of:

  • Branch A: Entry point that splits into Branch B and Branch C.
  • Branch B and Branch C: Perform tasks and route to the final node.
  • Final Node: Combines results and marks the workflow as complete.

Graph Overview

  • Entry point: branch_a
  • Workflow flow:
    branch_a --> branch_b --> final_node
            --> branch_c --> final_node
    
  • End node: END

Output

When executed with the input "a", the workflow:

  1. Adds "a" in each step (total of 5 additions).
  2. Produces the output: "aaaaa".

Notes and Tips

  • Visualization: Use the get_graph method to generate a visual representation of the workflow. This is helpful for debugging and understanding complex workflows.
  • Flexibility: LangGraph supports custom functions and LangChain runnables, enabling dynamic and customizable workflows.
  • Future Enhancements: You can integrate LLMs or other models for real-world applications.

This example demonstrates the foundational concepts of LangGraph. By mastering nodes, edges, and workflows, you can build sophisticated and scalable agentic systems.

Working with Conditional Edges

Conditional edges allow branching in the workflow based on input data. Here's a step-by-step explanation of how to work with conditional edges:

Functions Used

  1. entry(input):

    • Takes an input list of HumanMessage objects.
    • Simply returns the input without any modifications.
  2. work_with_b(input):

    • Executes when the workflow branches to "Branch B".
    • Prints "Using branch B".
  3. work_with_c(input):

    • Executes when the workflow branches to "Branch C".
    • Prints "Using branch C".
  4. router(input):

    • Determines the branching logic.
    • If "use_b" is found in the input's content, it routes to "Branch B"; otherwise, it routes to "Branch C".

Steps to Build the Workflow

  1. Create a MessageGraph:

    • Initialize a MessageGraph object.
  2. Add Nodes:

    • Add nodes for each branch and the entry point:
      • "branch_a": Executes the entry function.
      • "branch_b": Executes the work_with_b function.
      • "branch_c": Executes the work_with_c function.
  3. Add Conditional Edges:

    • Use add_conditional_edges() to route based on the output of the router function.
    • Provide a mapping of output strings to target nodes:
      • "branch_b""branch_b"
      • "branch_c""branch_c"
  4. Set End Nodes:

    • Add edges from "branch_b" and "branch_c" to the END node.
  5. Set Entry Point:

    • Define "branch_a" as the entry point using set_entry_point().
  6. Compile and Visualize:

    • Compile the graph with compile() to create a runnable workflow.
    • Visualize the graph using draw_mermaid_png() to understand its structure.

Graph Visualization

Conditional edges are visualized with dashed lines, distinguishing them from standard edges. This helps in understanding how the workflow branches based on input conditions.

Example Invocations

  1. Input: "hello":

    • Since "use_b" is not in the input, the workflow branches to "branch_c".
    • Output: "Using branch C"
  2. Input: "I want to use_b":

    • The input contains "use_b", so the workflow branches to "branch_b".
    • Output: "Using branch B"

Code Implementation

from langchain_core.messages import HumanMessage
from langgraph.graph import END, MessageGraph

def entry(input: list[HumanMessage]):
    return input

def work_with_b(input: list[HumanMessage]):
    print("Using branch B")
    return input

def work_with_c(input: list[HumanMessage]):
    print("Using branch C")
    return input

def router(input: list[HumanMessage]):
    if "use_b" in input[0].content:
        return "branch_b"
    else:
        return "branch_c"

graph = MessageGraph()

graph.add_node("branch_a", entry)
graph.add_node("branch_b", work_with_b)
graph.add_node("branch_c", work_with_c)

graph.add_conditional_edges(
    "branch_a", router, {"branch_b": "branch_b", "branch_c": "branch_c"}
)
graph.add_edge("branch_b", END)
graph.add_edge("branch_c", END)

graph.set_entry_point("branch_a")

runnable = graph.compile()

from IPython.display import Image, display
display(Image(runnable.get_graph().draw_mermaid_png()))

runnable.invoke("hello")
runnable.invoke("I want to use_b")

Key Takeaways

  • Conditional Edges: Essential for branching workflows based on dynamic inputs.
  • Graph Visualization: Aids in understanding workflow structures and debugging.
  • Reusable Functions: Functions like entry, work_with_b, and router can be customized for different use cases.

LangGraph and Cycles

Key Differences Between LangGraph and LCEL

LangGraph allows the creation of cycles in workflows, which LCEL does not. Cycles enable workflows to loop back and repeat steps based on conditional logic. This functionality is useful for creating iterative or repetitive workflows.


Example: Cyclic Workflow with LangGraph

This example demonstrates a cyclic workflow using LangGraph:

  1. Entry Point:

    • A function (entry) that simply takes an input and returns the same output without modification.
  2. Action Node:

    • A function (action) that:
      • Checks the number of input messages.
      • If the number exceeds 5, appends a human message with the content end.
      • Otherwise, appends a message with the content continue.
      • Uses the content of the last message to determine whether the workflow should continue or terminate.
  3. Should Continue Function:

    • A function (should_continue) that evaluates the content of the last message:
      • If the content is end, the function returns __end__, signaling the workflow to terminate.
      • Otherwise, it returns action, signaling the workflow to continue.
  4. Graph Structure:

    • Nodes:
      • agent: Performs the entry function.
      • action: Executes the action function.
    • Conditional Edge:
      • From agent:
        • If the output of should_continue is action, it routes to the action node.
        • If the output is __end__, it routes to the termination node (END).
    • Cycle:
      • The action node routes back to the agent node, forming a cyclic structure.

Visualization of the Workflow

The compiled graph visualizes the cyclic workflow:

  • The agent node conditionally routes to either:
    • The action node for further processing.
    • The END node to terminate the workflow.
  • The action node routes back to the agent node, enabling iterative processing.

Execution of the Workflow

  1. Input:

    • Start with the input "Hello".
  2. Process:

    • The workflow repeatedly adds the message continue until the input message list reaches a length of 5.
    • At this point, the message end is added, signaling the workflow to terminate.
  3. Termination:

    • When the last message contains end, the workflow routes to the termination node (END).

Code Example

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.graph import END, MessageGraph

model = ChatOpenAI(temperature=0)

def entry(input: list[HumanMessage]):
    return input

def action(input: list[HumanMessage]):
    print("Action taken:", [msg.content for msg in input])
    if len(input) > 5:
        input.append(HumanMessage(content="end"))
    else:
        input.append(HumanMessage(content="continue"))
    return input

def should_continue(input: list):
    last_message = input[-1]
    if "end" in last_message.content:
        return "__end__"
    return "action"

graph = MessageGraph()

graph.add_node("agent", entry)
graph.add_node("action", action)

graph.add_conditional_edges(
    "agent", should_continue, {"action": "action", "__end__": END}
)
graph.add_edge("action", "agent")

graph.set_entry_point("agent")

runnable = graph.compile()

display(Image(runnable.get_graph().draw_mermaid_png()))

runnable.invoke("Hello")

Key Takeaways

  • LangGraph is powerful for creating workflows with cyclic behavior.
  • Cycles allow workflows to iterate based on conditional logic until a specific termination condition is met.
  • This feature distinguishes LangGraph from LCEL and expands its applicability for complex workflows.

Source

The notes has been taken from this video from Coding Crash Courses YouTube channel.

[YouTube]

Did you find this article valuable?

Support Neural Nonsense by becoming a sponsor. Any amount is appreciated!