Skip to main content
For new applications, we recommend event streaming—the typed-projection API introduced in LangChain v1.3. Event streaming gives you separate iterators per projection (messages, values, tool calls, subgraphs) so you can consume them independently instead of branching on stream_mode chunks.
LangChain implements a streaming system to surface real-time updates. Streaming is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs.

Overview

LangChain’s streaming system lets you surface live feedback from agent runs to your application. What’s possible with LangChain streaming: See the common patterns section below for additional end-to-end examples.

Supported stream modes

Pass one or more of the following stream modes as a list to the stream or astream methods:

Agent progress

To stream agent progress, use the stream or astream methods with stream_mode="updates". This emits an event after every agent step. For example, if you have an agent that calls a tool once, you should see the following updates:
  • LLM node: AIMessage with tool call requests
  • Tool node: ToolMessage with execution result
  • LLM node: Final AI response
Pass a thread_id via config so the conversation is checkpointed and follow-up turns can resume the same history. thread_id is independent of stream_mode; you can also pass context alongside it for per-run data your tools read from runtime.context.
Output
Persisting conversation history with thread_id requires the agent to be configured with a checkpointer. On LangSmith deployments a checkpointer is provisioned automatically. Locally, pass one explicitly, for example create_agent(..., checkpointer=InMemorySaver()). The remaining snippets on this page omit thread_id for brevity, but you should pass it in production.

LLM tokens

To stream tokens as they are produced by the LLM, use stream_mode="messages". Below you can see the output of the agent streaming tool calls and the final response.
Streaming LLM tokens
Output

Custom updates

To stream updates from tools as they are executed, you can use get_stream_writer.
Streaming custom updates
Output
If you add get_stream_writer inside your tool, you won’t be able to invoke the tool outside of a LangGraph execution context.

Stream multiple modes

You can specify multiple streaming modes by passing stream mode as a list: stream_mode=["updates", "custom"]. Each streamed chunk is a StreamPart dict with type, ns, and data keys. Use chunk["type"] to determine the stream mode and chunk["data"] to access the payload.
Streaming multiple modes
Output

Common patterns

Below are examples showing common use cases for streaming.

Streaming thinking / reasoning tokens

Some models perform internal reasoning before producing a final answer. You can stream these thinking / reasoning tokens as they’re generated by filtering standard content blocks for the type "reasoning".
Reasoning output must be enabled on the model.See the reasoning section and your provider’s integration page for configuration details.To quickly check a model’s reasoning support, see models.dev.
To stream thinking tokens from an agent, use stream_mode="messages" and filter for reasoning content blocks:
Output
This works the same way regardless of the model provider—LangChain normalizes provider-specific formats (Anthropic thinking blocks, OpenAI reasoning summaries, etc.) into a standard "reasoning" content block type via the content_blocks property. To stream reasoning tokens directly from a chat model (without an agent), see streaming with chat models.

Streaming tool calls

You may want to stream both:
  1. Partial JSON as tool calls are generated
  2. The completed, parsed tool calls that are executed
Specifying stream_mode="messages" will stream incremental message chunks generated by all LLM calls in the agent. To access the completed messages with parsed tool calls:
  1. If those messages are tracked in the state (as in the model node of create_agent), use stream_mode=["messages", "updates"] to access completed messages through state updates (demonstrated below).
  2. If those messages are not tracked in the state, use custom updates or aggregate the chunks during the streaming loop (next section).
Refer to the section below on streaming from sub-agents if your agent includes multiple LLMs.
Output

Accessing completed messages

If completed messages are tracked in an agent’s state, you can use stream_mode=["messages", "updates"] as demonstrated in the Streaming tool calls section to access completed messages during streaming.
In some cases, completed messages are not reflected in state updates. If you have access to the agent internals, you can use custom updates to access these messages during streaming. Otherwise, you can aggregate message chunks in the streaming loop (see below). Consider the below example, where we incorporate a stream writer into a simplified guardrail middleware. This middleware demonstrates tool calling to generate a structured “safe / unsafe” evaluation (one could also use structured outputs for this):
We can then incorporate this middleware into our agent and include its custom stream events:
Output
Alternatively, if you aren’t able to add custom events to the stream, you can aggregate message chunks within the streaming loop:

Streaming with human-in-the-loop

To handle human-in-the-loop interrupts, we build on the above example:
  1. We configure the agent with human-in-the-loop middleware and a checkpointer
  2. We collect interrupts generated during the "updates" stream mode
  3. We respond to those interrupts with a command
Output
We next collect a decision for each interrupt. Importantly, the order of decisions must match the order of actions we collected. To illustrate, we will edit one tool call and accept the other:
Output
We can then resume by passing a command into the same streaming loop:
Output

Streaming from sub-agents

When there are multiple LLMs at any point in an agent, it’s often necessary to disambiguate the source of messages as they are generated. To do this, pass a name to each agent when creating it. This name is then available in metadata via the lc_agent_name key when streaming in "messages" mode. Below, we update the streaming tool calls example:
  1. We replace our tool with a call_weather_agent tool that invokes an agent internally
  2. We add a name to each agent
  3. We specify subgraphs=True when creating the stream
  4. Our stream processing is identical to before, but we add logic to keep track of what agent is active using create_agent’s name parameter
When you set a name on an agent, that name is also attached to any AIMessages generated by that agent.
First we construct the agent:
Next, we add logic to the streaming loop to report which agent is emitting tokens:
Output

Disable streaming

In some applications you might need to disable streaming of individual tokens for a given model. This is useful when:
  • Working with multi-agent systems to control which agents stream their output
  • Mixing models that support streaming with those that do not
  • Deploying to LangSmith and wanting to prevent certain model outputs from being streamed to the client
Set streaming=False when initializing the model.
When deploying to LangSmith, set streaming=False on any models whose output you don’t want streamed to the client. This is configured in your graph code before deployment.
Not all chat model integrations support the streaming parameter. If your model doesn’t support it, use disable_streaming=True instead. This parameter is available on all chat models via the base class.
See the LangGraph streaming guide for more details.

v2 streaming format

Requires LangGraph >= 1.1.
Pass version="v2" to stream() or astream() to get a unified output format. Every chunk is a StreamPart dict with type, ns, and data keys — the same shape regardless of stream mode or number of modes:
The v2 format also improves invoke() — it returns a GraphOutput object with .value and .interrupts attributes, cleanly separating state from interrupt metadata:
See the LangGraph streaming docs for more details on the v2 format, including type narrowing, Pydantic/dataclass coercion, and subgraph streaming.