Combining control flow (edges) and state updates (nodes) can be very useful. For instance, you might want to execute state updates and decide which node to transition to next within the same node. LangGraph provides a way to achieve this by returning an object from the Command node function:
def my_node(state: State) -> Command[Literal["my_other_node"]]: return Command( # state update update={"foo": "bar"}, # control flow goto="my_other_node" )
Let’s create a simple graph containing 3 nodes: A, B, and C. We will first execute node A, and then based on the output of node A, decide whether to transition to node B or node C.
import random
from typing_extensions import TypedDict, Literal
from langgraph.graph import StateGraph, START
from langgraph.types import Command
class State(TypedDict): foo: str
# Define the nodes
def node_a(state: State) -> Command[Literal["node_b", "node_c"]]: print("Called A") value = random.choice(["a", "b"])
# This is another way to write a conditional edge function if value == "a": goto = "node_b" else: goto = "node_c"
# Here it shows how Command allows you to update the graph state and route to the next node simultaneously return Command( # state update update={"foo": value}, # route to an edge goto=goto, )
# Nodes B and C are unchanged
def node_b(state: State): print("Called B") return {"foo": state["foo"] + "b"}
def node_c(state: State): print("Called C") return {"foo": state["foo"] + "c"}
Now, we can create a StateGraph using the nodes defined above. Note that this graph does not have conditional edges for routing! This is because the control flow is defined using Command inside node_a.
Now let’s start defining our graph, paying attention to the commented sections:
builder = StateGraph(State)
builder.add_edge(START, "node_a")
builder.add_node(node_a)
builder.add_node(node_b)
builder.add_node(node_c)
# Note: There are no edges connecting nodes A, B, and C!
graph = builder.compile()
print(graph.invoke({"foo": ""}))
Called A
Called C
{'foo': 'bc'}
The flow of the graph is as follows: