← chapter

Streaming responses

Week 3 · Chapter 4 · Basic

The problem

What changes

OpenAI: one keyword

stream = client.responses.create(
    model="gpt-5.4-nano",
    input=prompt,
    stream=True,
)
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)

Gemini: separate method

stream = client.models.generate_content_stream(
    model="gemini-3.1-flash-lite",
    contents=prompt,
)
for chunk in stream:
    if chunk.text:
        print(chunk.text, end="", flush=True)

When streaming pays off

Three showcases this week

Each one is its own docker-compose project under code/showcase/<slug>/.

The two-callable pattern

def run_stream(input: str) -> Iterator[str]:
    stream = client.responses.create(..., stream=True)
    for event in stream:
        if event.type == "response.output_text.delta":
            yield event.delta

def run(input: str) -> str:
    return "".join(run_stream(input))

Backend has two endpoints

Takeaway

Streaming is one keyword argument away from a better-feeling app. The model never got faster. The experience of waiting did. Reach for it whenever the output is long enough that a reader would tab away.