Building language agents as graphs

LangGraph is a library for developing complex, stateful applications with Large Language Models (LLMs) that involve multiple actors and cycles. Drawing inspiration from Pregel and Apache Beam

The library’s interface is reminiscent of NetworkX

Its primary purpose is to add cyclical processing and persistence capabilities to LLM applications, making it an ideal choice for applications that require more than simple Directed Acyclic Graphs (DAGs), which can already be achieved with LangChain Expression Language.

LangGraph
LangGraph

LangGraph is a way to create these state machines by specifying them as graphs.

StateGraph

The StateGraph class represents a graph that manages a central state object, which evolves over time. 

  • To create a StateGraph instance, you need to provide a state definition that outlines the structure of this central state.

There are two ways to update state attributes:

  • Override: Nodes can return a new value for an attribute, replacing its current value. This is useful when nodes need to provide a new value for an attribute.
  • Add: Nodes can return a value that is added to the existing value of an attribute. This is useful when an attribute represents a collection, such as a list of actions, and nodes need to add new elements to it.

You specify whether an attribute should be overridden or added to when creating the initial state definition.

from langgraph.graph import StateGraph
from typing import TypedDict, List, Annotated
import Operator

class State(TypedDict):
    input: str
    all_actions: Annotated[List[str], operator.add]

graph = StateGraph(State)

Nodes

Once you’ve created a StateGraph, you can add nodes to it using the graph.add_node() method. 

  • Each node is identified by a unique name (a string) and has a value associated with it, which can be either a function or an LCEL runnable. 
  • This value will be executed when the node is reached in the graph.
graph.add_node("model", model)
graph.add_node("tools", tool_executor)
  • Note that there is a special node called END that marks the end of the graph. 
  • It’s important to ensure that your graph cycles can eventually terminate, and the END node helps with this.
from langgraph.graph import END

Edges

After adding nodes, you can then add edges to create the graph. There are a few types of edges.

The Starting Edge

This special edge connects the graph’s starting point to a specific node, designating it as the first node to be called when input is received.

graph.set_entry_point("model")

Normal Edges

These edges represent a linear sequence, where one node always follows another. For example, in a basic agent runtime, the model is always called after a tool is called.

graph.add_edge("tools", "model")

Conditional Edges

These edges use a function (often powered by a Large Language Model) to dynamically determine the next node to call. To create a conditional edge, you need to provide:

  • The upstream node: the output of this node will be evaluated to determine the next step
  • A function: this function will be called to determine which node to call next, based on the output of the upstream node
  • A mapping: this mapping will be used to match the output of the function to a specific node, with keys representing possible function outputs and values representing the corresponding node names.
graph.add_conditional_edge(
    "model",
    should_continue,
    {
        "end": END,
        "continue": "tools"
    }
)

Compile

Once we’ve defined our graph, we can transform it into a runnable entity! 

  • This process takes the graph definition we’ve created and generates a runnable object. 
  • This object offers the same methods as LangChain runnables, such as .invoke.stream, and .astream_log, making it compatible with the same calling conventions as a chain. 
  • This means we can seamlessly integrate our graph into LangChain workflows and invoke it like any other runnable.
app = graph.compile()

When to Use

If you need cycles.

Langchain Expression Language allows you to easily define chains (DAGs) but does not have a good mechanism for adding in cycles. langgraph adds that syntax.

Important Links:

Conclusion

LangGraph is a powerful tool for creating sophisticated, state-driven applications with Large Language Models (LLMs). 

By grasping its fundamental principles and exploring simple use cases, newcomers can unlock its potential for their projects. 

Key considerations include effective state management, strategic use of conditional edges, and ensuring all nodes have a clear path forward, avoiding dead ends. 

With these skills, you’ll be well on your way to harnessing LangGraph’s capabilities and building innovative applications.

Valuable comments