Streaming steps with stream_mode
stream is an agent method that hands back each step as it happens, so you can watch what the agent is doing and see why it stopped, instead of waiting for the finished conversation from invoke.
Last updated: 27 Sep, 2026 · LangChain 1.4
updates and values
Streaming an agent is different from streaming a model's text. An agent runs as a graph of steps (a model call, then a tool call, then another model call), and stream, or astream, its async form, hands each step to you as it finishes. stream_mode chooses what each item holds. The video explains it with three nodes that add "Hi", then "my name is", then "Krish":
- updates: only what the step added, keyed by the step's name: after the third node, only "Krish". One item per step.
- values: the whole state after each step: "Hi", then "Hi" and "my name is", then all three. Each item repeats everything before it.
The video then streams a LangGraph graph, with a thread id, on "Hi, my name is Krish and I like cricket". With updates only the AI message arrives; with values the human message comes first and the AI message is appended after it. create_agent builds the same kind of graph, so here the same comparison runs on an agent with no tools. With updates, one item arrives, holding only the model's reply. With values, two items arrive: the state holding only the question, then the state holding the question and the reply.
from langchain.agents import create_agent
agent = create_agent("groq:openai/gpt-oss-120b")
question = {"messages": "Hi, My name is Krish And I like cricket"}
for chunk in agent.stream(question, stream_mode="updates"):
for step, update in chunk.items():
print(step, "->", update["messages"][-1].text)
for chunk in agent.stream(question, stream_mode="values"):
print(len(chunk["messages"]), chunk["messages"][-1].type)model -> Hello Krish! 👋 Great to meet you. Cricket is such an exciting sport—do you have a favorite team or player? Are you more into the fast‑bowling action, the strategic spin game, or maybe the thrill of a big chase? I'd love to hear what you enjoy most about cricket! 1 human 2 ai
Use updates to show progress step by step, such as "looking up the order". Use values when you need the complete state at each point. The video covers these two modes. A third mode, messages, streams the model's words token by token while the agent runs; a chat window uses this one:
from langchain.agents import create_agent
agent = create_agent("groq:openai/gpt-oss-120b")
question = {"messages": "Hi, My name is Krish And I like cricket"}
for token, metadata in agent.stream(question, stream_mode="messages"):
print(token.text, end="|", flush=True)|||||||||||||||||||||||||||||||||||||||||Hi| Kr|ish|!| |👋| Nice| to| meet| you|.| How|’s| the| cricket| season| treating| you|?| Do| you| have| a| favorite| team| or| player| you|’re| cheering| for|?| |🏏|✨|||
The run of empty pieces at the start is the model thinking: gpt-oss reasons before it answers, and those chunks carry no text. After them the reply arrives a word or two at a time. A chat window skips the empty ones with if token.text.
The video streams a LangGraph graph it builds by hand, with a thread id and memory. The examples on this page stream an agent made with create_agent instead. The modes work the same way on both, because create_agent runs on LangGraph underneath.
Every agent from the create_agent: the agent loop lesson on can be watched this way, so it is worth learning before something goes wrong. The rest of this lesson streams the shop agent from that lesson.
The stream method
for step in agent.stream(inputs, stream_mode="updates"): # one item per step
print(step) # {node_name: {"messages": [...]}}Building a bare agent
Start a fresh agent.py with lookup_order from Tools: a function the model can call, as in the last lesson.
from langchain.tools import tool
ORDERS = {"A17": "shipped on 3 March", "C40": "waiting for stock"}
@tool
def lookup_order(order_id: str) -> str:
"""Look up an order's shipping status by its id, such as A17."""
status = ORDERS.get(order_id)
return f"{order_id} {status}." if status else f"{order_id} is not an order we have."Build the same agent: one tool, one model, the shop's system prompt, nothing wrapped around the call. Add this below the tool in agent.py.
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
agent = create_agent(init_chat_model("groq:openai/gpt-oss-120b", temperature=0), tools=[lookup_order], # uses your GROQ_API_KEY
system_prompt="You are the support assistant for a small online shop. Answer in one or two short sentences, using only what the tools returned.")Streaming each step
Add these lines to the end of agent.py. They loop over stream with stream_mode="updates". Each item names the part of the agent that ran and the messages it added.
question = {"messages": [{"role": "user", "content": "Where is my order A17?"}]}
for step in agent.stream(question, stream_mode="updates"):
for name, update in step.items():
for message in update["messages"]:
print(f"{name:<6} {message.type:<4} {message.text or message.tool_calls}")model ai [{'name': 'lookup_order', 'args': {'order_id': 'A17'}, 'id': 'fc_3a38ec73-a717-4c64-a227-68207ff5a12c', 'type': 'tool_call'}]
tools tool A17 shipped on 3 March.
model ai Your order A17 was shipped on 3 March.For the finished conversation you can still call invoke and print every message. This question names two orders.
result = agent.invoke({"messages": [{"role": "user", "content": "Where are A17 and C40?"}]})
for message in result["messages"]:
message.pretty_print()================================ Human Message =================================
Where are A17 and C40?
================================== Ai Message ==================================
Tool Calls:
lookup_order (fc_fdefe3ad-7d46-4e8d-8fce-200d0b6e8300)
Call ID: fc_fdefe3ad-7d46-4e8d-8fce-200d0b6e8300
Args:
order_id: A17
================================= Tool Message =================================
Name: lookup_order
A17 shipped on 3 March.
================================== Ai Message ==================================
Tool Calls:
lookup_order (fc_7a2ab670-3501-4af0-a0d5-7985ec46ac96)
Call ID: fc_7a2ab670-3501-4af0-a0d5-7985ec46ac96
Args:
order_id: C40
================================= Tool Message =================================
Name: lookup_order
C40 waiting for stock.
================================== Ai Message ==================================
A17 has already shipped, while C40 is still waiting for stock.The model looked the two orders up one after the other: one tool call, its result, then the next call. Each round trip is another step of the loop. A model can also ask for both in a single message, which the Several tool calls at once lesson covers.
What each step showed
pretty_printfrom the messages lesson shows the tool calls with their arguments and ids, which is often enough to see why an agent did what it did.
invoke vs stream
| invoke | stream | |
|---|---|---|
| Returns | The finished conversation | One item per step |
| You see steps | Only at the end | As they happen |
| Use it to | Get the final answer | Watch and debug the loop |
When to stream steps
- Showing progress in a user interface while an agent works.
- Debugging: seeing which tool ran, with what arguments, and where the loop stopped.
values repeats every earlier message at every step, so each item grows with the conversation. Print only chunk["messages"][-1] when you want the newest one.Related
- Previous: create_agent: the agent loop
- Next: Runtime context: who is asking
- Reference: Streaming
- Stream a question with no order in it and count the steps.
- Stream with
stream_mode="values"and print how many messages each item holds. - Stream a question about B22 and find the step where the tool says it has no such order.
This is what real progress feels like.