Streaming a deep agent's steps
Streaming is running the agent with stream instead of invoke, so each step, a model reply or a tool result, reaches your code as soon as it happens instead of all at once at the end.
Last updated: 29 Sep, 2026 · Deep Agents 0.7
A deep agent can take minutes on a large task. The video waits for invoke to finish and mentions that streaming shows the work as it goes; this lesson does that. stream_mode="updates" yields one dictionary per step, keyed by the node that ran: model for a model reply, tools for tool results.
The stream call
for step in agent.stream({"messages": [...]}, stream_mode="updates"):
for node, update in step.items(): # node is "model", "tools" or a middleware step
...Building the agent
Start trip.py with search_travel, the catalog tool from Tools: a travel search the agent can call. Everything below goes in the same file, under it.
from langchain.tools import tool
CATALOG = {
"paris": {
"flight": ["Return flight Delhi to Paris: 42,000 rupees"],
"hotel": ["Seine Budget Inn, Latin Quarter: 5,200 rupees a night",
"Hotel Lumiere, Montmartre: 7,500 rupees a night",
"Le Grand Opera Hotel: 16,000 rupees a night"],
"sight": ["Eiffel Tower summit: 3,100 rupees", "Louvre Museum: 2,000 rupees",
"Seine river cruise: 1,500 rupees", "Versailles day trip: 2,600 rupees",
"Montmartre walking tour: free"],
"food": ["Cafe breakfast and bistro dinner: 3,000 rupees a day"],
},
}
@tool
def search_travel(city: str, kind: str) -> str:
"""Search the travel catalog. kind is "flight", "hotel", "sight" or "food". Prices are in rupees."""
entries = CATALOG.get(city.lower(), {}).get(kind)
return "\n".join(entries) if entries else f"The catalog has no {kind} entries for {city}."from deepagents import create_deep_agent
from langchain.chat_models import init_chat_model
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0, max_retries=6)agent = create_deep_agent(model=model, tools=[search_travel], system_prompt="You are a travel planner. Look up every price with search_travel and use only "
"what it returns. Answer in two short sentences.")Streaming a question about cheap sights
Some steps come from middleware and carry no messages, so the loop reads messages with a default of an empty list.
question = {"messages": [{"role": "user", "content": "Which two Paris sights cost the least?"}]}
for step in agent.stream(question, stream_mode="updates"):
for node, update in step.items():
for message in (update or {}).get("messages", []):
print(f"{node:<6} {message.type:<5}", message.text or [c["name"] for c in message.tool_calls])model ai ['search_travel'] tools tool Eiffel Tower summit: 3,100 rupees Louvre Museum: 2,000 rupees Seine river cruise: 1,500 rupees Versailles day trip: 2,600 rupees Montmartre walking tour: free model ai The cheapest Paris sight is the Montmartre walking tour, which is free. The next‑least‑expensive is the Seine river cruise at 1,500 rupees.
What the stream showed
- model, ai: the first step was the model asking for
search_travel. It printed before the tool ran. - tools, tool: the catalog's sight list, printed as soon as the tool returned.
- model, ai with text: the final answer, the last step.
Stream modes compared
| stream_mode | What each item is | Use it for |
|---|---|---|
"updates" | The changes one node made | Showing progress step by step |
"messages" | Tokens of model text as they are generated | Typing the answer out live |
"values" | The whole state after each step | Debugging what the agent holds |
For new applications the docs recommend event streaming, added in 0.6: agent.stream_events(..., version="v3") gives separate streams for messages, tool calls and each subagent through stream.subagents. With stream and subagents, pass subgraphs=True as well; each item then comes with a namespace that says which agent produced it. Subagents: delegating with the task tool uses it.
Where streaming helps
- A chat UI that shows "searching hotels..." while the agent works.
- Watching a long run to see where it spends its time.
- Logging every tool call without waiting for the end.
stream nothing runs until you loop over it. Creating the stream and never iterating it does no work at all.Related
- Previous: System prompt: giving the agent its job
- Next: write_todos: planning with TodoListMiddleware
- Reference: Deep Agents streaming
- Change the mode to
"values"and printlen(step["messages"])for each step. - Stream tokens with
for token, meta in agent.stream(question, stream_mode="messages"): print(token.text, end=""). - Ask a question that needs two lookups and count the
toolssteps.
Little by little, you're building something great.