Tokenien suoratoiston ymmärtäminen
Ymmärrä, miten streaming API lähettää osittaisia täydennyksiä niiden muodostuessa, miten OpenAI:n stream=True-parametri toimii ja milloin suoratoisto parantaa käyttökokemusta.
Tokenien suoratoiston ymmärtäminen on ilmainen AI Engineering Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu AI Engineering Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. AI Engineering Academy-kurssilla on yhteensä 4 oppituntia.
Miksi suoratoisto on tärkeää käyttökokemuksen kannalta
Ilman suoratoistoa sovelluksesi on odotettava, että LLM luo koko vastauksen, ennen kuin se näyttää mitään — pitkissä vastauksissa usein 5–30 sekuntia. Suoratoiston ansiosta ensimmäinen token näkyy 200–500 ms:n kuluessa pyynnön lähettämisestä, ja seuraavat tokenit saapuvat suoratoistona heti niiden luonnin jälkeen. Tämä muuttaa käyttäjän kokeman kokemuksen odottamisesta kiinnostavaksi reaaliaikaiseksi luonniksi ja parantaa koettua reagointinopeutta huomattavasti, vaikka kokonaisluontiaika pysyy samana.
Miten LLM:t luovat tokeneita
LLM:t ovat autoregressiivisia: ne luovat tekstiä yhden tokenin kerrallaan siten, että jokainen uusi token perustuu kaikkiin aiempiin tokeneihin. Kun API vastaanottaa pyynnön, GPU aloittaa ensimmäisen tokenin otannan heti kehotteen käsittelyn jälkeen. Jokaisen seuraavan tokenin luominen kestää suunnilleen saman ajan. Suoratoisto lähettää jokaisen tokenin asiakkaalle heti otannan jälkeen sen sijaan, että kaikki tokenit puskuroitaisiin ja lähetettäisiin lopuksi yhtenä kokonaisena merkkijonona.
# 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_tokenTTFT ja TPOT: kaksi viivemittaria
Suoratoisto tuo mukanaan kaksi erillistä viivekäsitettä. TTFT (Time to First Token) on pyynnön lähettämisestä ensimmäisen tokenin vastaanottamiseen kuluva aika, johon kehotteen käsittely vaikuttaa eniten. TPOT (Time Per Output Token) on peräkkäisten tokenien välinen aika, jonka määrittävät mallin koko ja laitteisto. TTFT vaikuttaa siihen, kuinka nopeasti käyttöliittymä reagoi; TPOT vaikuttaa tekstin suoratoiston sujuvuuteen. Molempia tulee seurata erikseen havainnointijärjestelmässä.
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')stream=True-parametri
Suoratoiston käyttöönotto OpenAI SDK:ssa edellyttää asetuksen stream=True määrittämistä kutsussa chat.completions.create. Vastauksen tyyppi muuttuu ChatCompletion-objektista Stream[ChatCompletionChunk]-iteraattoriksi. Jokainen osa sisältää delta-kentän, jossa on joko content-merkkijonon katkelma tai None, jos token on työkalukutsu tai suoratoisto on päättymässä.
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 endKoko vastauksen kokoaminen
Monissa sovelluksen työnkuluissa tarvitset sekä tokenien suoratoistoa käyttöliittymään reagointinopeuden vuoksi että koko vastaustekstin kokoamista jatkokäsittelyä, kuten lokitusta, välimuistia tai putken seuraavia vaiheita, varten. Menettely on yksinkertainen: käy suoratoisto läpi, tulosta tai välitä jokainen osa asiakkaalle ja yhdistä samalla sisältö kokonaiseksi merkkijonoksi.
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_textSuoratoisto käyttötietojen kanssa
Oletusarvoisesti suoratoistovastaus ei sisällä tokenien käyttötietoja (kehotteen tokenit, valmistuneet tokenit). Voit sisällyttää ne välittämällä asetuksen stream_options={'include_usage': True}. Käyttötiedot saapuvat viimeisessä osassa sisältövirran päätyttyä. Tämä on tärkeää tuotantosovellusten kustannusten seurannassa ja nopeusrajoitusten valvonnassa.
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}')Milloin suoratoistoa ei pidä käyttää
Suoratoisto ei ole aina oikea valinta. Vältä suoratoistoa, kun: (1) tarvitset koko vastauksen ennen kuin voit tehdä sillä mitään, esimerkiksi JSON-jäsennystä tai työkalukutsun tunnistamista varten; (2) vastaus on erittäin lyhyt (alle 30 tokenia), jolloin suoratoiston aiheuttama lisäkäsittely lisää viivettä enemmän kuin säästää sitä; tai (3) käsittelet eräajona monia pyyntöjä, jolloin läpimeno on tärkeämpää kuin yksittäisen vastauksen viive. Näissä tapauksissa tavalliset suoratoistamattomat kutsut ovat yksinkertaisempia ja yhtä nopeita.
Suoratoisto Anthropic- ja Gemini-rajapinnoilla
Suoratoisto on saatavilla kaikissa tärkeimmissä LLM-palveluntarjoajien rajapinnoissa, ei vain OpenAI:ssa. Menettely on samankaltainen, mutta SDK-rajapinnat eroavat hieman toisistaan. Anthropicin Python SDK käyttää client.messages.stream()-kutsua kontekstinhallintana, kun taas Gemini käyttää kutsua generate_content(stream=True). Kun rakennat palveluntarjoajasta riippumattomia sovelluksia, sijoita suoratoistorajapinta yhteisen generaattorifunktion taakse.
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}')Generaattoriin perustuva suoratoistorajapinta
Selkeä arkkitehtuurimalli käärii suoratoiston Python-generaattorifunktioon, joka palauttaa token-merkkijonoja yield-lauseilla. Tämä irrottaa suoratoistologiikan kulutuslogiikasta — kutsuja voi iteroida generaattorin yli, kirjoittaa tiedostoon, välittää tuloksen WebSocketiin tai koota sen merkkijonoksi ilman, että suoratoistokoodi tietää, miten sen tulosta käytetään. Tämä muodostaa useimpien tuotantokäyttöön tarkoitettujen suoratoisto-API:en perustan.
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!'}]))Suoratoisto pääte- ja CLI-sovelluksissa
Päätesovelluksissa suoratoistettu tuloste näyttää samalta kuin kirjoittaminen — jokainen merkki ilmestyy heti sen luonnin jälkeen. Keskeinen vaatimus on käyttää asetusta flush=True jokaisessa print-kutsussa. Ilman tyhjennystä Python puskuroi tulosteen rivinvaihtoon asti, mikä kumoaa suoratoiston hyödyn. Voit myös käyttää kutsua sys.stdout.write(token) ja sen jälkeen kutsua sys.stdout.flush(), jos haluat hallita tulosteen muotoilua tarkemmin.
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)')Suoratoisto ja virheistä palautuminen
Suoratoisto vaikeuttaa virheenkäsittelyä, koska virhe voi tapahtua suoratoiston puolivälissä sen jälkeen, kun osa tokeneista on jo lähetetty asiakkaalle. Suositeltava toimintamalli on ympäröidä suoratoiston iteraatio try/except-lohkolla ja virheen sattuessa joko lähettää asiakkaalle virhesentinelli tai sulkea suoratoisto hallitusti. Määritä aina koko suoratoistolle aikakatkaisu, jotta tilanteet, joissa palvelin aloittaa suoratoiston mutta pysähtyy kesken luonnin, voidaan käsitellä.
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 timeoutPikatarkistus
Testaa tämän oppitunnin avulla, ymmärrätkö LLM-tokenien suoratoistoa.
Oppitunnin yhteenveto
Tässä oppitunnissa opitte, että streaming lähettää jokaisen generoidun tokenin asiakkaalle heti sen näytteenoton jälkeen, mikä parantaa merkittävästi koettua reagointinopeutta, TTFT ja TPOT ovat kaksi keskeistä viivemittaria, joita kannattaa seurata erikseen, ja stream=True muuttaa OpenAI SDK:n vastauksen iteraattoriksi, jonka osia käsittelette for-silmukalla. Kapseloikaa streamit generaattorifunktioihin, jotta rajapinnasta tulee selkeä ja uudelleenkäytettävä. Seuraavaksi toteutamme asynkronisen streamauksen Python SDK:lla.
Opi Python tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 30
- Oppitunnit
- 120
Usein kysytyt kysymykset
Onko oppitunti ”Tokenien suoratoiston ymmärtäminen” ilmainen?
Kyllä – oppitunnin ”Tokenien suoratoiston ymmärtäminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko AI Engineering Academy-kurssin, päivitä CoddyKit PROhon. AI Engineering Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Tokenien suoratoiston ymmärtäminen”?
Ymmärrä, miten streaming API lähettää osittaisia täydennyksiä niiden muodostuessa, miten OpenAI:n stream=True-parametri toimii ja milloin suoratoisto parantaa käyttökokemusta. Harjoittelet AI Engineering Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni AI Engineering Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin AI Engineering Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.
Kuinka kauan ”Tokenien suoratoiston ymmärtäminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä AI Engineering Academy-oppitunnilla?
Kyllä. Jokainen AI Engineering Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Tokenien suoratoiston ymmärtäminen
- Suoratoistojen käsittely Python SDK:lla
- Suoratoisto FastAPIssa Server-Sent Events -tapahtumilla
- Työkalukutsujen käsittely suoratoistovastauksissa