Site

Streaming — Real-Time Responses

Tutorial 7.0  •  AI / Learn

7.0 What This Teaches

Streaming lets you display model output as it is generated instead of waiting for the complete response. This tutorial covers:

7.1 Why Streaming

Without streaming, messages.create() blocks until the model finishes generating the entire response. A 500-token reply might take 3-5 seconds. During that time the user sees nothing. With streaming, the model sends tokens as it generates them. The first token typically arrives within a few hundred milliseconds. For a user watching a terminal or a UI, text appearing progressively feels much faster than a multi-second blank wait followed by a sudden wall of text. The tradeoff: streaming requires a context manager and a loop instead of a single function call. For scripts that process output programmatically and never display it to a user, the extra complexity is not worth it.

7.2 The Streaming API

The SDK provides streaming through client.messages.stream(), used as a Python context manager. Inside the with block, the stream object gives you access to text_stream - an iterator that yields each text chunk as it arrives from the API.
with client.messages.stream(...) as stream:
    for text in stream.text_stream:
        # text is one chunk - usually a word or a few characters
        print(text, end="", flush=True)
The parameters passed to stream() are the same as for messages.create(): model, max_tokens, messages, and optionally system.

7.3 Basic Streaming Example

# stream_hello.py - print tokens as they arrive.
import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=[{"role": "user", "content": "Write a Python quicksort function."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

print()  # newline after stream ends
Run this script and watch the function appear character by character. Two details in the print call matter:

7.4 Getting the Final Message Object

After the loop finishes, stream.get_final_message() returns the complete Message object with all fields populated, including usage. Call it after the loop, not inside it.
# stream_with_usage.py - stream output then read usage stats.
import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=[{"role": "user", "content": "Write a Python quicksort function."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    # get_final_message() is called after the loop, inside the with block
    final = stream.get_final_message()

print()  # newline after stream ends
print(f"\nInput tokens : {final.usage.input_tokens}")
print(f"Output tokens: {final.usage.output_tokens}")
print(f"Stop reason  : {final.stop_reason}")
get_final_message() must be called inside the with block, after the loop. Once the context manager exits, the stream connection is closed and the final message is no longer accessible.

7.5 Streaming with a System Prompt

The system= parameter works exactly the same way in streaming calls as in non-streaming calls.
# stream_system.py - streaming with a system prompt.
import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=512,
    system="You are a Python tutor. Always include type hints and a one-line docstring.",
    messages=[{"role": "user", "content": "Write a function that merges two sorted lists."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

print()

7.6 When Not to Stream

Streaming is the right choice when a user watches the terminal or a UI in real time. It adds complexity without benefit in these situations:
SituationUse streaming?Reason
Displaying output to a user in real time Yes Reduces perceived latency
Batch processing: save output to a file No No display - messages.create() is simpler
Unit tests asserting on response content No Tests need the full string; streaming adds no value
Parsing JSON from the response No JSON must be complete before parsing; collect it all first

7.7 Exercise

Exercise Modify stream_hello.py to ask for a longer explanation: change the user message to "Explain how Python's garbage collector works in detail." Add a counter variable before the loop and increment it by 1 inside the loop on each iteration. After the loop (and after printing the final newline), print the total chunk count. Run the script and observe how many chunks a longer response produces compared to a short code snippet.

7.8 Common Mistakes

Using messages.create when you meant messages.stream

client.messages.create() returns the entire response at once as a Message object. It does not return a stream. If you forget to use client.messages.stream(), you get no incremental output - just the usual blocking wait followed by the full response.

Forgetting end="" and flush=True in print()

Without end="", Python appends a newline after each chunk and the code appears one word per line. Without flush=True, Python buffers output in memory and releases it in large blocks rather than immediately - the terminal does not update until the buffer fills, which defeats the purpose of streaming. Always use both.

Calling get_final_message() inside the loop

get_final_message() blocks until the stream is complete. Calling it inside the for text in stream.text_stream loop on the first iteration will consume the rest of the stream internally, causing the loop to exit early after just one chunk. Call it after the loop finishes.

7.9 Key Terms

TermMeaning
streamingReceiving model output incrementally as it is generated, rather than waiting for the complete response
text_streamAn iterator on the stream object that yields text chunks as they arrive
context managerA Python with statement that manages setup and teardown; here it opens and closes the stream connection
chunkOne piece of text yielded by text_stream; typically a word or a few characters
flushForcing Python to send buffered output to the terminal immediately instead of waiting
get_final_messageMethod on the stream object that returns the complete Message with usage stats after streaming ends
bufferingPython's default behavior of holding output in memory and writing it in batches; disabled per print() with flush=True