Where we left off

Lesson 8 streamed whole node outputs, useful for watching a multi-node pipeline progress, but each chunk still only appeared once an entire node had finished, including any model call inside it. If a node's model call takes a few seconds to write a long answer, "values" and "updates" streaming still make you wait for all of it before that node's chunk shows up. stream_mode="messages" fixes that by streaming the model's reply token by token, from inside a node, as the words are actually generated.

What we're building

Lesson 6's single model-call graph, unchanged, streamed with stream_mode="messages" so the answer prints as it's written instead of all at once at the end.

The code, piece by piece

for token_chunk, metadata in app.stream(
{"messages": [HumanMessage("Explain graphs in three short sentences.")]},
stream_mode="messages",
):
print(token_chunk.text, end="", flush=True)

stream_mode="messages" yields a (token_chunk, metadata) tuple for every small piece of output the model produces internally, this is the same token-by-token streaming a chat UI shows you. token_chunk is a message chunk (a partial AIMessageChunk, holding just that piece of text), .text gives you the piece of text itself. metadata is a dictionary telling you which node and which model call this token came from, useful once a graph has more than one node that talks to a model and you want to tell their outputs apart.

end="", flush=True on print matters here: without end="", every token would print on its own line. flush=True forces each piece to show up immediately instead of Python buffering several tokens before displaying them, which would defeat the purpose of streaming.

Why this is a different mode, not just "updates" again

"values" and "updates" (Lesson 8) both operate at the granularity of whole node outputs, a node either has finished or it hasn't, there's no in-between. "messages" reaches inside a node's model call itself and streams pieces of that call's output as they're generated, which is a finer granularity than "a node finished." A graph can use all three modes depending on what you're building: "updates" to log progress across nodes, "messages" to show one particular node's answer arriving live.

Checkpoint

  • stream_mode="messages": streams token-level chunks from any model call inside a node, as they're generated.
  • (token_chunk, metadata): each streamed item is a pair, the piece of the message and info about which node/call produced it.
  • finer granularity than "values"/"updates": those stream once per finished node, "messages" streams multiple times per model call within a single node.

If anything here still feels unclear, ask before moving to Lesson 10.