Machine Learning Spot

Langchain LangGraph: An Ultimate and Exciting Introduction (2024 Primer)

LangChain LangGraph

LangChain LangGraph gives you more flexibility and power than regular langchain. Want to know what Langraph is? looking for a blog that can teach you how to use LangGraph?

If you are looking for a way to make LangChain more cyclic, empowering each part to be much more independent while still contributing to the process to bring the required outcome, then you have come to the right place.

This blog on LangChain LangGraph will teach you a new skill in LangChain that will help you develop much more advanced chatbots or any other system that has more complexity.

This blog is a must-read for those who want to get started with LangGraph. In this blog, I have used various analogies to make it easier for the readers to understand.

What is LangChain LangGraph?

LangGraph is a specialized library designed for building advanced applications involving large language models (LLMs). It is used for building stateful and multi-actor applications, i.e., applications built using LangChain’s LangGraph can remember past interactions, use that information in future steps, and have different agents or components within the application that can perform actions. LangChain LangGraph can coordinate multiple such actors.

(Pregel and Apache Beam)

The LangChain’s LangGraph was inspired by Pregel and Apache Beam, so to know LangGraph more, its better to know how it’s similar to them.

Pregel and LangGraph

Pregel system, developed by Google for processing large-scale graph data, is relevant to LangChain’s LangGraph as it includes a vertex-centric model Pregel processes data by thinking in terms of vertices and edges in a graph. LangGraph uses different nodes similar to it.

Next come the stateful nodes Pregel maintains its state across iterations, which is similar to LangGraph, which also maintains its state in different steps and interactions in a language model application.

Pregel uses the concept of supersteps for iterative processing, where each vertex can perform computations, send messages, and update its state. It is similar to LangChain LangGraph in that it can also handle iterative decision-making and state updates in LLM applications.

Supersteps in Pregel provide synchronization points, which ensure consistency and coordination across the graph. LangChain LangGraph also supports the same concept and can use similar concepts for checkpointing and coordination.

Pregel can handle massive graphs distributed on various machines LangGraph is designed to do the same; it can also work on graphs distributed across different machines and manage large-scale, distributed computations involving multiple actors.

Apache Beam and LangGraph

LangGraph must efficiently deal with synchronous (real-time) and asynchronous (delayed) workflows. Apache Beam is a unified model designed to define batch and streaming data processing pipelines.

A unified model means it can handle different data processing tasks in a single framework. Both batch (processing large volumes of data at once) and streaming (processing data in real-time as it arrives) can be done here. By providing these facilities, like Apache Beam, LangGraph’s power and capabilities are increased.

The LangChain LangGraph also has the capability of stateful processing, just like Apache Beam. This means that LangChain Graph can maintain information across multiple data elements.

This is a particularly important feature, especially in applications where previous data impacts current decisions, such as in a chatbot with a form or question-answer format, or even a robot with sensors combined with a chatbot.

Apache Beam timers can also be added in LangGraph to schedule an action. Furthermore, Apache Beam uses a runner abstraction to achieve portability, by making the same pipeline code able to be run on various platforms or processing engines like Apache, Flink and Google Cloud Dataflow without needing to change the codebase LangChain LangGraph provides us the same facility of portability through backend flexibility.

How LangGraph Works: A Visualized Explanation of Nodes and Edges

As the name suggests and as we have already discussed, it works on graphs, and as we know in computer science, a graph is a data structure or network that consists of vertices or nodes that are connected through edges.

This structure is used to represent connections, relationships, and networks. Similarly, in LangChain LangGraph, we create a network of nodes connected with edges where each node can work independently. Let’s have a look at nodes and edges.

Nodes in LangGraph

The most fundamental building block of LangGraph is the node. These building blocks of each node in the graph are responsible for carrying out specified processes.

Nodes in LangGraph can be of multiple types, depending on our creativity. A few of them can be read below.

  • Function Nodes: These nodes are functions that perform specific tasks, like taking an input, processing it, and then producing an output that updates the graph state.
  • Tool Node: These nodes interact with external tools or APIs that may fetch data and then produce an output based on the fetched data.
  • State Management Node: Each node can update the central state object of the graph. So in state Management node, we have flexibility to change the central state.

    For example, if there are some key-value pairs, this node can be made responsible for overwriting some information and then pass it to produce an output.
  • Special Nodes: There are special nodes in LangGraph, for example, the start node and end node. We have to specify where the graph starts and where it ends.

It depends on you and your program what type of node should be used. Each node will work as a single step in your program that is connected with each other.

Speaking of connection, let’s move on to the concept of edges.

Edges the Strings That Connect the Nodes

LangChain LangGraph has nodes, but alone they can’t do anything; we have to connect them with each other.

Here, edges play the role of strings or chains to not only tie the nodes but also to tell the graph which node it should process next.

To see how each edge is used in code, suppose we have initialized an instance of LangChain LangGraph’s graph as “graph” in the code below, you can see what I mean.

from langgraph.graph import Graph

# Define a Langchain LangGraph's graph
graph = Graph()  #initialized an instance of LangChain Graph's graph as graph

Edges can be of 3 types:

  1. Starting Edge: Suppose one of our nodes is named step_1 we want to make it our first node, and then to add it to the graph, we will use this line of code graph.set_entry_point (“step_1“) the name of the first node to which we had named step 1 was added.
  2. Normal Edge: This is used to connect any of the two nodes. Let’s suppose we named our next node step_2 Now we have to connect both step_1 and step_2 so in brackets instead of one, two names of two different nodes will have to be shared.

    This is how it is added graph.add_edge(“step_2”, “step_1“).
  3. Conditional Edge: Suppose there is more than one node that the graph can choose after processing node, i.e. when we need the edge to decide its next node based on some condition, then we use conditional edge. Suppose we have two options: go back to step_1 or end the node.
    Conditional edges are analogous to railroad switch

LangChain LangGraph: An Analogy to Understand

Now that we have learned about nodes and edges, let’s learn how to create the simplest graph in LangChain LangGraph.

I like to imagine nodes as departments of an industry where each department is responsible for some task. The department can be as large as another company or as small as just a single person working in it. Furthermore, I like to think of edges as a conveyor belt connecting each department.

Suppose we have a car industry with three departments, each responsible for a specific task. Let the three departments be:

  1. Design
  2. Production
  3. Testing

Let’s see how it will be made.

Implementing Our Analogy: Creating a Simple LangChain LangGraph

Since this is a hypothetical situation, the functions for nodes that I am going to create will be empty functions, whose job will be to return an indicative output that the particular department of the industry has completed its work.

Right now, they are not nodes; they are functions that will be used to add nodes in the graph since it won’t get any input, so it’s crucial to set it as none, or else our code of LangChain LangGraph might give us an error.

Below, by writing functions, we are establishing departments of our car industry, each responsible for a specified job. By combining these functions, we can establish our company.

Remember, we have not named these departments yet; we have just designed their functions. We will name them later, when they are made as nodes.

# Define functions for each department
def design_department(input=None):
    return "Car design completed."

def production_department(input=None):
    return "Car production completed."

def testing_department(input=None):
    return "Car testing completed.
LangChain LangGraph: Analogy image adding dunctions as department of industry
Departments established with functions, but nodes not named yet

Now to add nodes, we need a graph, so by importing the graph module and initializing the graph instance as an industry, we will use this instance to define and manage the workflow of the car manufacturing process.

 from langgraph.graph import Graph

# Define a Langchain graph
industry = Graph()

Now that we have created the functions and initialized the graph, it’s time to add a node. To add a node, we use the .add_node method.

In the parentheses, we first write the name of the node that we want, for example, “design” and the second argument is the function name that will be used for the node, for example, “design_department”.

industry.add_node("design", design_department)
industry.add_node("production", production_department)
industry.add_node("testing", testing_department)
LangChain LAngraph Analaogy image nodes named
Node names can be seen in the bubble (node).

Now to connect the nodes and create a graphical sequence by adding edges, notice how we have one less edge. Here we have three nodes to connect; two edges are enough.

If the design is the first department of our industry analogy, then our conveyor belt, i.e., the edge, will take the produced output to the next department, i.e., the production department. After the work and processing, this production department will send its product to the testing department.

# Define the flow of work
industry.add_edge('design', 'production')
industry.add_edge('production', 'testing')
LangChain LangGraph Analogy Production
Conveyor belts acting as edges.

Now that we have added nodes and edges to our graph, it is time to introduce starting and ending points. For this, we will just tell the LangGraph which node we are considering as the entry point and which node we are considering as the end point, so this is how we will do it.

industry.set_entry_point("design")
industry.set_finish_point("testing")


Now, to complete our graph, we need to compile it and then by executing it, we can observe the power of LangChain LangGraph.

# Compile the workflow
car_manufacturing_process = industry.compile()

The below lines are just to prepare the workflow input = "start" sets a dummy initial input value. This input isn’t used by the department functions but ensures that the workflow has a starting input. print("Workflow Output:") prints a header for the workflow output.

# Simulate a car through the workflow using the stream method
input = "start"  # Provide a dummy initial input
print("Workflow Output:")

Now the below lines will execute and print the output, “for output in car_manufacturing_process.stream(input) uses the stream method to execute the workflow. This yields dictionaries containing output for each node.

Then an inner loop for key, value in output.items() iterates over each dictionary yielded through the stream process; the key is taken as the node’s name, and the value is the node’s output.

Lastly, print(f”Output from ‘{key}’: {value}”) prints the output and lets us observe the power of LangChain LangGraph


for output in car_manufacturing_process.stream(input):
    for key, value in output.items():
        print(f"Output from '{key}': {value}")

Now let us see the output to observe the power of LangChain LangGraph.

Workflow Output:
Output from 'design': Car design completed.
Output from 'production': Car production completed.
Output from 'testing': Car testing completed.

Clarifying the Confusion: LangChain LangGraph vs. LangChain

In all our previous blogs, we used chains of LangChain to connect LLMs, prompts and everything else we wanted to connect to make a custom chain LangChain Chains is a facility provided by LangChain in the same way LangGraph is another facility provided by LangChain as a library to make cyclic chains or introduce cycles in the chain.

The custom chains that we made in our previous blogs on LangChain using LangChain chains were Directed Acyclic Graphs (DAG); they were not cyclic.

Custom chains are more suitable for less complex, non-cyclic tasks. LangGraph supports various graph types; it can be either DAG or cyclic.

Unlike custom chains, in LangGraph, we can introduce cycles with ease. LangGraph works on nodes connected through edges.

Using these edges, we can create cycles by connecting nodes. Each node can discreetly work while maintaining its history, which is then passed along with the output. Here are some of the graphs that you can create using LangGraph.

  1. Linear Graph: In this graph, each node is executed only once
  2. Branching Graph: Splits into multiple paths based on conditions
  3. Cyclic Graph: In this graph, nodes can be revisited multiple times.
  4. Tree Graph: In this graph, nodes branch out in a hierarchical structure without cycles
  5. Complex Multi-Branch Cyclic Graph: By combining branching, cycles, and stateful updates, you can create highly sophisticated workflows.

It depends on how we want LangChain LangGraph to work; the structure is not limited to the list of graphs that I shared above. Let’s dig a little deeper into the specialty that we just mentioned, i.e., cyclic graphs.

Conclusion:

Hurray! By completing this blog on LangChain LangGraph, you now know everything you need to utilize LangGraph in your program. Stay tuned to learn more about LangGraph.

Soon, I will share a blog post on how to make a simple chatbot using LangChain LangGraph. If you want to learn more about LangChain, please read my other blog posts on LangChain.

As I am always open to feedback, feel free to contact me and enlighten me with your valuable feedback and suggestions.

Liked the Post?  You can share as well

Facebook
Twitter
LinkedIn

More From Machine Learning Spot

Get The Latest AI News and Insights

Directly To Your Inbox
Subscribe

Signup ML Spot Newsletter

What Will You Get?

Bonus

Get A Free Workshop on
AI Development