AI Engineering Academy · leksjon

Forstå tokenstrømming

Forstå hvordan streaming-API-et sender delvise fullføringer etter hvert som de genereres, hvordan OpenAI-parameteren stream=True fungerer, og når strømming forbedrer brukeropplevelsen.

Leksjon 1 av 413 trinn

Forstå tokenstrømming er en gratis leksjon i AI Engineering Academy på CoddyKit. Dette er leksjon 1 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i AI Engineering Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.

Hvorfor strømming er viktig for brukeropplevelsen

Uten strømming må applikasjonen vente på at LLM-en skal generere hele svaret før den viser noe — ofte 5–30 sekunder for lange svar. Med strømming vises det første tokenet innen 200–500 ms etter at forespørselen er sendt, og de påfølgende tokenene strømmes inn etter hvert som de genereres. Dette forvandler den opplevde brukeropplevelsen fra venting til en engasjerende, levende genereringseffekt og forbedrer den opplevde responsiviteten betydelig, selv om den totale genereringstiden er identisk.

Hvordan LLM-er genererer tokener

LLM-er er autoregressive: De genererer tekst ett token om gangen, der hvert nytt token avhenger av alle tidligere tokener. Når API-et mottar en forespørsel, begynner GPU-en umiddelbart å trekke ut det første tokenet etter at ledeteksten er behandlet. Hvert påfølgende token tar omtrent like lang tid. Strømming sender hvert token til klienten så snart det er trukket ut, i stedet for å mellomlagre alle tokenene og sende hele strengen til slutt.

# Conceptual model of autoregressive generation
prompt = 'The capital of France is'

# Step 1: process full prompt, predict next token
# token_1 = sample(logits) → ' Paris'

# Step 2: append token_1 to context, predict next
# token_2 = sample(logits) → '.'

# Step 3: append token_2 to context, predict next
# token_3 = sample(logits) → '<|end|>'

# Total time: time_to_process_prompt + n_tokens * time_per_token
# With streaming: first token arrives after time_to_process_prompt (TTFT)
# Without streaming: everything arrives after TTFT + n_tokens * time_per_token

TTFT og TPOT: To ventetidsmålinger

Strømming introduserer to ulike ventetidsbegreper. TTFT (Time to First Token) er forsinkelsen fra forespørselen sendes til det første tokenet mottas — hovedsakelig bestemt av tiden det tar å behandle ledeteksten. TPOT (Time Per Output Token) er tiden mellom påfølgende tokener — bestemt av modellstørrelsen og maskinvaren. TTFT påvirker hvor raskt brukergrensesnittet reagerer, mens TPOT påvirker hvor jevnt teksten strømmes. Begge bør spores separat i observability-stacken din.

import time
from openai import OpenAI

client = OpenAI()

def measure_streaming_latency(prompt: str):
    t_start = time.perf_counter()
    t_first_token = None
    token_times = []

    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        stream=True,
    )
    for chunk in stream:
        if chunk.choices[0].delta.content:
            t_now = time.perf_counter()
            if t_first_token is None:
                t_first_token = t_now
                print(f'TTFT: {(t_first_token - t_start) * 1000:.0f}ms')
            else:
                token_times.append(t_now - token_times[-1] if token_times else t_now - t_first_token)
            token_times.append(t_now)
    print(f'TPOT avg: {1000 * (token_times[-1] - t_first_token) / max(len(token_times)-1, 1):.1f}ms')

Parameteren stream=True

Hvis du vil aktivere strømming i OpenAI SDK, må du angi stream=True i kallet til chat.completions.create. Svarstypen endres fra et ChatCompletion-objekt til en iterator av typen Stream[ChatCompletionChunk]. Hver del inneholder en delta med enten et tekstfragment i form av en content-streng eller None når tokenet er et verktøykall eller strømmingen avsluttes.

from openai import OpenAI

client = OpenAI()

# Non-streaming: wait for complete response
response = client.chat.completions.create(
    model='gpt-4o-mini',
    messages=[{'role': 'user', 'content': 'Explain RAG in one paragraph.'}],
)
full_text = response.choices[0].message.content

# Streaming: receive tokens incrementally
stream = client.chat.completions.create(
    model='gpt-4o-mini',
    messages=[{'role': 'user', 'content': 'Explain RAG in one paragraph.'}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:  # delta can be None for non-content chunks
        print(delta, end='', flush=True)
print()  # newline at end

Akkumulere hele svaret

I mange applikasjonsflyter trenger du både å strømme tokener til brukergrensesnittet for å gi rask respons og å akkumulere hele svarteksten for videre behandling, for eksempel logging, mellomlagring eller flere trinn i pipelinen. Mønsteret er enkelt: iterer over strømmen, skriv ut eller send hver del til klienten, og sett samtidig sammen innholdet til en hel streng.

def stream_and_accumulate(prompt: str) -> str:
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        stream=True,
    )

    full_text = ''
    finish_reason = None

    for chunk in stream:
        choice = chunk.choices[0]
        delta = choice.delta.content
        if delta:
            print(delta, end='', flush=True)  # real-time display
            full_text += delta               # accumulate
        if choice.finish_reason:
            finish_reason = choice.finish_reason

    print()  # newline
    print(f'Finished: {finish_reason}, total chars: {len(full_text)}')
    return full_text

Strømming med bruksstatistikk

Som standard inneholder strømmingssvaret ikke statistikk over tokenbruk (ledeteksttokener og fullføringstokener). For å ta dem med sender du stream_options={'include_usage': True}. Bruksdataene kommer i den siste delen etter at innholdsstrømmen er avsluttet. Dette er viktig for kostnadssporing og overvåking av hastighetsgrenser i produksjonsapplikasjoner.

stream = client.chat.completions.create(
    model='gpt-4o-mini',
    messages=[{'role': 'user', 'content': 'What is a vector database?'}],
    stream=True,
    stream_options={'include_usage': True},  # include token counts
)

full_text = ''
usage = None

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        full_text += chunk.choices[0].delta.content
    if chunk.usage:  # arrives in the final chunk
        usage = chunk.usage

if usage:
    print(f'Prompt tokens: {usage.prompt_tokens}')
    print(f'Completion tokens: {usage.completion_tokens}')
    print(f'Total tokens: {usage.total_tokens}')

Når du ikke bør bruke strømming

Strømming er ikke alltid det riktige valget. Unngå strømming når: (1) du trenger hele svaret før du gjør noe med det, for eksempel ved JSON-tolking eller registrering av verktøykall; (2) svaret er svært kort (under 30 tokener), slik at kostnadene ved strømmingen gir mer forsinkelse enn den sparer; eller (3) du behandler mange forespørsler i batch, der gjennomstrømming er viktigere enn ventetiden for det enkelte svaret. I disse tilfellene er standardkall uten strømming enklere og like raske.

Strømming med Anthropic- og Gemini-API-er

Strømming er tilgjengelig i API-ene til alle store LLM-leverandører, ikke bare OpenAI. Mønsteret er likt, men SDK-grensesnittene varierer noe. Anthropic sitt Python-SDK bruker client.messages.stream() som en kontekstbehandler, mens Gemini bruker generate_content(stream=True). Når du bygger leverandøruavhengige applikasjoner, bør du abstrahere strømmingsgrensesnittet bak en felles generatorfunksjon.

import anthropic

ant_client = anthropic.Anthropic(api_key='YOUR_KEY')

# Anthropic streaming
with ant_client.messages.stream(
    model='claude-sonnet-4-5',
    max_tokens=1024,
    messages=[{'role': 'user', 'content': 'Explain hybrid search briefly.'}],
) as stream:
    for text in stream.text_stream:
        print(text, end='', flush=True)

# Final message with usage stats
final_msg = stream.get_final_message()
print(f'\nInput tokens: {final_msg.usage.input_tokens}')
print(f'Output tokens: {final_msg.usage.output_tokens}')

Generatorbasert strømmingsgrensesnitt

Et ryddig arkitekturmønster pakker strømmingen inn i en Python-generatorfunksjon som gir fra seg tokenstrenger. Dette kobler strømmingslogikken fra logikken som bruker resultatet — kallere kan iterere over generatoren, skrive til en fil, videresende til en WebSocket eller samle resultatet i en streng uten at strømmingskoden trenger å vite hvordan resultatet brukes. Dette er grunnlaget for de fleste produksjons-API-er med strømming.

from typing import Generator

def stream_completion(
    messages: list[dict],
    model: str = 'gpt-4o-mini',
    **kwargs,
) -> Generator[str, None, None]:
    stream = client.chat.completions.create(
        model=model,
        messages=messages,
        stream=True,
        **kwargs,
    )
    for chunk in stream:
        delta = chunk.choices[0].delta.content
        if delta:
            yield delta

# Usage: pipe to stdout
for token in stream_completion([{'role': 'user', 'content': 'Hello!'}]):
    print(token, end='', flush=True)

# Usage: accumulate
full = ''.join(stream_completion([{'role': 'user', 'content': 'Hello!'}]))

Strømming i terminal- og CLI-applikasjoner

I terminalapplikasjoner ser strømmede resultater ut som skriving — hvert tegn vises umiddelbart etter hvert som det genereres. Det viktigste er å bruke flush=True i hvert print-kall. Uten flushing mellomlagrer Python resultatet til et linjeskift kommer, noe som undergraver hensikten med strømming. Du kan også bruke sys.stdout.write(token) etterfulgt av sys.stdout.flush() for bedre kontroll over formateringen av resultatet.

import sys

def stream_to_terminal(messages: list[dict]):
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True,
    )
    token_count = 0
    for chunk in stream:
        delta = chunk.choices[0].delta.content
        if delta:
            sys.stdout.write(delta)  # no newline added
            sys.stdout.flush()       # MUST flush or output buffers
            token_count += 1
    print()  # final newline
    print(f'({token_count} tokens generated)')

Strømming og gjenoppretting etter feil

Strømming gjør feilhåndtering mer komplisert fordi en feil kan oppstå midt i strømmen, etter at du allerede har sendt noen tokener til klienten. Det anbefalte mønsteret er å pakke iterasjonen over strømmen inn i en try/except-blokk og ved feil enten sende et feilsentinel til klienten eller lukke strømmen på en ryddig måte. Implementer alltid en tidsavbruddsgrense for hele strømmen, slik at du håndterer tilfeller der serveren begynner å strømme, men deretter stopper midt i genereringen.

import signal

def stream_with_timeout(messages, timeout_seconds=30):
    def timeout_handler(signum, frame):
        raise TimeoutError('LLM stream timed out')

    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(timeout_seconds)

    try:
        stream = client.chat.completions.create(
            model='gpt-4o-mini',
            messages=messages,
            stream=True,
        )
        for chunk in stream:
            delta = chunk.choices[0].delta.content
            if delta:
                yield delta
    except TimeoutError:
        yield '\n[Response timed out]'
    except Exception as e:
        yield f'\n[Error: {str(e)}]'
    finally:
        signal.alarm(0)  # cancel timeout

Rask kontroll

Test forståelsen din av strømming av LLM-tokener fra denne leksjonen.

Oppsummering av leksjonen

I denne leksjonen har De lært: strømming sender hvert genererte token til klienten så snart det er samplet, noe som forbedrer den opplevde responsiviteten betydelig, TTFT og TPOT er de to viktigste latenstidsmålingene som bør følges separat, og stream=True endrer OpenAI SDK-responsen til en chunk-iterator som De bruker med en for-løkke. Pakk strømmer inn i generatorfunksjoner for å få et ryddig og gjenbrukbart grensesnitt. Deretter implementerer vi asynkron strømming med Python SDK-et.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
30
Leksjoner
120

Ofte stilte spørsmål

Er leksjonen «Forstå tokenstrømming» gratis?

Ja – hele teksten i «Forstå tokenstrømming» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av AI Engineering Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Forstå tokenstrømming»?

Forstå hvordan streaming-API-et sender delvise fullføringer etter hvert som de genereres, hvordan OpenAI-parameteren stream=True fungerer, og når strømming forbedrer brukeropplevelsen. Du øver på AI Engineering Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med AI Engineering Academy?

Ingen tidligere erfaring er nødvendig. AI Engineering Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Forstå tokenstrømming»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne AI Engineering Academy-leksjonen?

Ja. Alle AI Engineering Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Forstå tokenstrømming
  2. Konsumere strømmer med Python SDK
  3. Strømming i FastAPI med Server-Sent Events
  4. Håndtere verktøykall i strømmende svar
← Tilbake til AI Engineering Academy