Graphs

Data Structures

Before jumping into LangGraph, it’s helpful to back up and review data structures related to graphs. It puts the “Graph” of LangGraph in context.

Linked Lists

A linked list is a chain of nodes where each node holds a reference to the next node. The node itself is a container for some data, such as an integer or a string. In the image below, the circles represent nodes, and the arrows represent the links between the nodes:

A linked list

Linked lists are linear in nature because each node only has links with the nodes before and after it.

Trees

A tree is a non-linear data structure where all nodes, except the root node, have a single parent node and zero or more child nodes. You can observe this structure in the diagram below:

A tree

The root node at the top has three children, each with one or two child nodes. Nodes without any children are called leaf nodes.

Graphs

A graph data structure is a step beyond trees. In a graph, a single node can link to any number of other nodes. The graph below shows this structure:

A graph

In graph terminology, the links between the nodes are called edges.

Node Node Edge

In an undirected graph, the edges go both ways. That means you can go from the first node to the second node or from the second node to the first one. In a directed graph, on the other hand, the edges go in only one direction, usually indicated by an arrow:

Node Node Edge

Now that you’ve had a refresher on the graph data structure, you’re ready to jump into LangGraph.

Note: If you find data structures interesting and would like a more in-depth understanding, check out Kodeco’s Data Structures & Algorithms books, which are available for Dart, Swift, and Kotlin.

LangGraph vs LangChain

LangGraph is a library built by LangGraph Inc. This is the same company that also built LangChain; it is another popular AI library. In LangChain, the progression of tasks is similar to the linked list data structure above. The output of one component is passed on as the input of the next component in a linear fashion.

A basic chain might look something like the following example from the LangChain documentation:

chain = prompt_template | model | parser

The user provides a prompt to the prompt template, which outputs it in a standard form to be used as input for the large language model. Then, the output from the model is given as input to the parser, which, in turn, provides formatted output that can be displayed to the user.

It’s possible to create graph-like workflows in LangChain, but they tend to be directed acyclic graphs (DAGs). In plain English, that means no looping. You start at one point and continue directly to the end of the workflow. You can’t go back and repeat previous steps.

Looping is important, though. There are many situations where you might want to redo something. For example, if you fetch a document and it doesn’t contain the required information, you’d probably want to keep trying a few more times before giving up. Or if you’re cleaning up some data and the first pass still leaves something to be desired, you might want to take a second pass. This models real life. If something doesn’t work the first time, you don’t just give up, right?

  • Mom: Hey, Suzy, will you please get me my slippers? I think they’re on the floor by the door.
  • Suzy: Sure, Mom. (Looks by the door.) They’re not here!
  • Mom: Oh, I just remembered. I put them under my bed.
  • Suzy: Sorry, Mom. I can’t get them for you because I can only look one place.

That would be silly! That’s not how life works, and it isn’t how an AI agent should work, either.

LangGraph solves this problem by allowing much more complex workflows with branching and looping. It also has built-in memory and allows human-in-the-loop interaction. You can use LangGraph within LangChain workflows, but you can also build workflows without using LangChain at all. Both of these libraries are independent of each other.

Core Concepts in LangGraph

Setting Up the Development Environment

Installation is easy. Run the following pip command in the terminal:

pip install langgraph

In a JupyterLab notebook, you would create a basic graph like so:

from langgraph.graph import Graph

graph = Graph()

Nodes and Edges

A Node in LangGraph is a wrapper for a Python function. Given the function below:

def my_function(input):
  return "Input: " + input

You’d create a node like so:

graph.add_node("node_1", my_function)

The first parameter is the node’s name, and the second is the function that handles the input coming into the node.

An Edge in LangGraph determines how the graph is structured and how data is routed. Given two nodes, node_1 and node_2, you’d connect them like so:

graph.add_edge("node_1", "node_2")

Edges in LangGraph are directed. The output of node_1 is the input to node_2.

In addition to normal nodes, LangGraph has special nodes that determine where the execution flow starts and finishes. The start node is called START, and the end node is called END. Thus, if you wanted to run node_1 first, you would add an edge from START to node_1 like so:

from langgraph.graph import START, END

graph.add_edge(START, "node_1")

Similarly, you can set the end node by adding an edge from node_2 to END:

graph.add_edge("node_2", END)

Alternatively, you can call set_entry_point and set_finish_point with the node names to accomplish the same thing.

Compiling and Running a Graph

Once you’ve created all the nodes of your graph and connected them with edges, you’re ready to compile the graph. The compile step validates the graph and prepares it for execution. This is how you’d do it:

compiled_graph = graph.compile()

After that, you can run the compiled graph using the invoke method with an initial input:

compiled_graph.invoke("user input")

Another core concept in LangGraph is State. However, before jumping into that, it helps to get a little hands-on practice creating a graph. Follow along with the video demo in the next section.

See forum comments
Download course materials from Github
Previous: Introduction Next: Graphs Demo