LangGraphLangGraph 1.2 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson

Watching it work

A long run should not be a blank screen. Swap invoke for stream and you get each step as it finishes.

python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START

class State(TypedDict):
    category: str
    reply: str
python
builder = StateGraph(State)
builder.add_node("categorise", lambda s: {"category": "billing"})
builder.add_node("write_reply", lambda s: {"reply": "We will refund it."})
builder.add_edge(START, "categorise")
builder.add_edge("categorise", "write_reply")
graph = builder.compile()

Stream it

Example
for step in graph.stream({"category": "", "reply": ""}):
    print(step)

Each item is a dictionary with the node's name as the key and what that node changed as the value. That is exactly what an interface needs in order to say which step is running.

Asking for something else

What you just saw is the default, called updates. Ask for values instead and you get the whole state after each step rather than only the change.

Example
for step in graph.stream({"category": "", "reply": ""}, stream_mode="values"):
    print(step)

Three items this time, not two. The first is the state before anything ran, which updates had nothing to say about.

ModeYou getUse it for
updatesWhat each node changedA progress log. The default.
valuesThe whole state after each stepRedrawing a screen from the current state.
messagesWords from the model as they arriveTyping out a reply live.
customAnything a node chooses to sendProgress from inside one long node.

Words as they arrive

The mode people actually want is messages. It hands you what the model is saying while it is still saying it, which is how a chat window types out an answer.

Example
from pretend_model import PretendModel
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, MessagesState

builder = StateGraph(MessagesState)
builder.add_node("call_model", lambda s: {"messages": [PretendModel().invoke(s["messages"])]})
builder.add_edge(START, "call_model")

for chunk, info in builder.compile().stream(
    {"messages": [HumanMessage("Where is order A17?")]}, stream_mode="messages"
):
    print(info["langgraph_node"], "->", repr(chunk.content))

One chunk here, because our stand-in writes its whole answer at once. A real model sends a few characters at a time and this loop runs dozens of times, which is where the effect comes from.

A second format exists
There is a newer output format, asked for with version="v2", where every chunk is a dictionary with type, ns and data keys instead of the shape changing per mode. The older one is still the default and still works. Reach for v2 when you handle several modes at once and want one shape to unpack.
Try it yourself
  • Print only list(step)[0] in the first example, so it reads as a list of node names.
  • Pass stream_mode=["updates", "values"] and look at what comes out.
  • Stream the agent loop from lesson 18 and watch it go round.

Every expert started right here.