Skip to main content

Building stateful, multi-actor applications with LLMs

Project description

🦜🕸️LangGraph

Version Downloads Open Issues Docs

⚡ Building language agents as graphs ⚡

[!NOTE] Looking for the JS version? Click here (JS docs).

Overview

LangGraph is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures, differentiating it from DAG-based solutions. As a very low-level framework, it provides fine-grained control over both the flow and state of your application, crucial for creating reliable agents. Additionally, LangGraph includes built-in persistence, enabling advanced human-in-the-loop and memory features.

LangGraph is inspired by Pregel and Apache Beam. The public interface draws inspiration from NetworkX. LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.

Key Features

  • Cycles and Branching: Implement loops and conditionals in your apps.
  • Persistence: Automatically save state after each step in the graph. Pause and resume the graph execution at any point to support error recovery, human-in-the-loop workflows, time travel and more.
  • Human-in-the-Loop: Interrupt graph execution to approve or edit next action planned by the agent.
  • Streaming Support: Stream outputs as they are produced by each node (including token streaming).
  • Integration with LangChain: LangGraph integrates seamlessly with LangChain and LangSmith (but does not require them).

Installation

pip install -U langgraph

Example

One of the central concepts of LangGraph is state. Each graph execution creates a state that is passed between nodes in the graph as they execute, and each node updates this internal state with its return value after it executes. The way that the graph updates its internal state is defined by either the type of graph chosen or a custom function.

Let's take a look at a simple example of an agent that can search the web using Tavily Search API.

pip install langchain_openai langchain_community
export OPENAI_API_KEY=sk-...
export TAVILY_API_KEY=tvly-...

Optionally, we can set up LangSmith for best-in-class observability.

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=ls__...
from typing import Annotated, Literal, TypedDict

from langchain_core.messages import HumanMessage
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langgraph.checkpoint import MemorySaver
from langgraph.graph import END, StateGraph, MessagesState
from langgraph.prebuilt import ToolNode


# Define the tools for the agent to use
tools = [TavilySearchResults(max_results=1)]
tool_node = ToolNode(tools)

model = ChatOpenAI(temperature=0).bind_tools(tools)

# Define the function that determines whether to continue or not
def should_continue(state: MessagesState) -> Literal["tools", END]:
    messages = state['messages']
    last_message = messages[-1]
    # If the LLM makes a tool call, then we route to the "tools" node
    if last_message.tool_calls:
        return "tools"
    # Otherwise, we stop (reply to the user)
    return END


# Define the function that calls the model
def call_model(state: MessagesState):
    messages = state['messages']
    response = model.invoke(messages)
    # We return a list, because this will get added to the existing list
    return {"messages": [response]}


# Define a new graph
workflow = StateGraph(MessagesState)

# Define the two nodes we will cycle between
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)

# Set the entrypoint as `agent`
# This means that this node is the first one called
workflow.set_entry_point("agent")

# We now add a conditional edge
workflow.add_conditional_edges(
    # First, we define the start node. We use `agent`.
    # This means these are the edges taken after the `agent` node is called.
    "agent",
    # Next, we pass in the function that will determine which node is called next.
    should_continue,
)

# We now add a normal edge from `tools` to `agent`.
# This means that after `tools` is called, `agent` node is called next.
workflow.add_edge("tools", 'agent')

# Initialize memory to persist state between graph runs
checkpointer = MemorySaver()

# Finally, we compile it!
# This compiles it into a LangChain Runnable,
# meaning you can use it as you would any other runnable.
# Note that we're (optionally) passing the memory when compiling the graph
app = workflow.compile(checkpointer=checkpointer)

# Use the Runnable
final_state = app.invoke(
    {"messages": [HumanMessage(content="what is the weather in sf")]},
    config={"configurable": {"thread_id": 42}}
)
final_state["messages"][-1].content
'The current weather in San Francisco is as follows:\n- Temperature: 60.1°F (15.6°C)\n- Condition: Partly cloudy\n- Wind: 5.6 mph (9.0 kph) from SSW\n- Humidity: 83%\n- Visibility: 9.0 miles (16.0 km)\n- UV Index: 4.0\n\nFor more details, you can visit [Weather API](https://www.weatherapi.com/).'

Now when we pass the same "thread_id", the conversation context is retained via the saved state (i.e. stored list of messages)

final_state = app.invoke(
    {"messages": [HumanMessage(content="what about ny")]},
    config={"configurable": {"thread_id": 42}}
)
final_state["messages"][-1].content
'The current weather in New York is as follows:\n- Temperature: 20.3°C (68.5°F)\n- Condition: Overcast\n- Wind: 2.2 mph from the north\n- Humidity: 65%\n- Cloud Cover: 100%\n- UV Index: 5.0\n\nFor more details, you can visit [Weather API](https://www.weatherapi.com/).'

Step-by-step Breakdown

  1. Initialize the model and tools.
    • we use ChatOpenAI as our LLM. NOTE: we need make sure the model knows that it has these tools available to call. We can do this by converting the LangChain tools into the format for OpenAI tool calling using the .bind_tools() method.
    • we define the tools we want to use - a web search tool in our case. It is really easy to create your own tools - see documentation here on how to do that here.
  2. Initialize graph with state.
    • we initialize graph (StateGraph) by passing state schema (in our case MessagesState)
    • MessagesState is a prebuilt state schema that has one attribute -- a list of LangChain Message objects, as well as logic for merging the updates from each node into the state
  3. Define graph nodes.

    There are two main nodes we need:

    • The agent node: responsible for deciding what (if any) actions to take.
    • The tools node that invokes tools: if the agent decides to take an action, this node will then execute that action.
  4. Define entry point and graph edges.

    First, we need to set the entry point for graph execution - agent node.

    Then we define one normal and one conditional edge. Conditional edge means that the destination depends on the contents of the graph's state (MessageState). In our case, the destination is not known until the agent (LLM) decides.

    • Conditional edge: after the agent is called, we should either:
      • a. Run tools if the agent said to take an action, OR
      • b. Finish (respond to the user) if the agent did not ask to run tools
    • Normal edge: after the tools are invoked, the graph should always return to the agent to decide what to do next
  5. Compile the graph.
    • When we compile the graph, we turn it into a LangChain Runnable, which automatically enables calling .invoke(), .stream() and .batch() with your inputs
    • We can also optionally pass checkpointer object for persisting state between graph runs, and enabling memory, human-in-the-loop workflows, time travel and more. In our case we use MemorySaver - a simple in-memory checkpointer
  6. Execute the graph.
    1. LangGraph adds the input message to the internal state, then passes the state to the entrypoint node, "agent".

    2. The "agent" node executes, invoking the chat model.

    3. The chat model returns an AIMessage. LangGraph adds this to the state.

    4. Graph cycles the following steps until there are no more tool_calls on AIMessage:

      • If AIMessage has tool_calls, "tools" node executes
      • The "agent" node executes again and returns AIMessage
    5. Execution progresses to the special END value and outputs the final state. And as a result, we get a list of all our chat messages as output.

Documentation

  • Tutorials: Learn to build with LangGraph through guided examples.
  • How-to Guides: Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.), these are the place to go if you want to copy and run a specific code snippet.
  • Conceptual Guides: In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more.
  • API Reference: Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more.
  • Cloud (beta): With one click, deploy LangGraph applications to LangGraph Cloud.

Contributing

For more information on how to contribute, see here.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langgraph-0.1.4.tar.gz (69.6 kB view details)

Uploaded Source

Built Distribution

langgraph-0.1.4-py3-none-any.whl (88.9 kB view details)

Uploaded Python 3

File details

Details for the file langgraph-0.1.4.tar.gz.

File metadata

  • Download URL: langgraph-0.1.4.tar.gz
  • Upload date:
  • Size: 69.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.0 CPython/3.12.4

File hashes

Hashes for langgraph-0.1.4.tar.gz
Algorithm Hash digest
SHA256 cd5c301b70d49fe4de88c4f11c9636070ff943af887615e7662df6678c86eb06
MD5 599a62eca9665b9e8f6422bab33b69c8
BLAKE2b-256 2d4faa0e5b745c52d665504ff628718754dbb0f7564ab525ce3543a0d2d0f433

See more details on using hashes here.

File details

Details for the file langgraph-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: langgraph-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 88.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.0 CPython/3.12.4

File hashes

Hashes for langgraph-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 7473fd87fc4e9f796a300be810cf6fbdcf91ca5355080c78fc502153d1b2752f
MD5 a7c10cda3cf2a0c4d1ffe02b7650b17e
BLAKE2b-256 6392eb0e92be522f90dfbd54065ee09a390f116e91018e468a4aa89468ef0be5

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page