AI Engineering Academy · पाठ

टोकन स्ट्रीमिंग को समझना

समझें कि स्ट्रीमिंग एपीआई निर्माण के साथ-साथ आंशिक पूर्णताएँ कैसे भेजती है, OpenAI का stream=True पैरामीटर कैसे काम करता है और स्ट्रीमिंग उपयोगकर्ता अनुभव को कब बेहतर बनाती है।

पाठ 1, कुल 4 में से13 चरण

टोकन स्ट्रीमिंग को समझना, CoddyKit पर AI Engineering Academy का एक निःशुल्क पाठ है। यह 4 में से 1वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह AI Engineering Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। AI Engineering Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

उपयोगकर्ता अनुभव के लिए स्ट्रीमिंग क्यों महत्वपूर्ण है

स्ट्रीमिंग के बिना आपका अनुप्रयोग कुछ भी प्रदर्शित करने से पहले LLM द्वारा पूरा उत्तर तैयार किए जाने तक प्रतीक्षा करता है — लंबे उत्तरों के लिए अक्सर 5-30 सेकंड तक। स्ट्रीमिंग के साथ अनुरोध भेजने के 200-500ms के भीतर पहला टोकन दिखाई देता है और उसके बाद के टोकन बनते ही आते रहते हैं। इससे उपयोगकर्ता का अनुभव प्रतीक्षा करने से बदलकर एक आकर्षक लाइव निर्माण प्रभाव में बदल जाता है और महसूस होने वाली प्रतिक्रियाशीलता नाटकीय रूप से बेहतर होती है, भले ही कुल निर्माण समय समान रहे।

LLM टोकन कैसे बनाते हैं

LLM ऑटोरेग्रेसिव होते हैं: वे एक बार में एक टोकन के अनुसार पाठ बनाते हैं, और प्रत्येक नया टोकन पिछले सभी टोकनों पर निर्भर होता है। जब API को अनुरोध मिलता है, तो prompt संसाधित होने के तुरंत बाद GPU पहला टोकन चुनना शुरू कर देता है। प्रत्येक अगला टोकन लगभग उतना ही समय लेता है। स्ट्रीमिंग प्रत्येक टोकन के चुने जाते ही उसे client को भेजती है, बजाय इसके कि सभी टोकनों को संचित करके अंत में पूरी स्ट्रिंग भेजी जाए।

# 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 और TPOT: विलंबता के दो मापदंड

स्ट्रीमिंग विलंबता की दो अलग-अलग अवधारणाएँ प्रस्तुत करती है। TTFT (पहले टोकन तक का समय) अनुरोध भेजने से पहला टोकन प्राप्त होने तक की देरी है — इस पर prompt संसाधित करने का समय सबसे अधिक प्रभाव डालता है। TPOT (प्रत्येक आउटपुट टोकन का समय) लगातार आने वाले टोकनों के बीच का समय है — यह मॉडल के आकार और हार्डवेयर से निर्धारित होता है। TTFT यह प्रभावित करता है कि UI कितनी जल्दी प्रतिक्रिया देता है; TPOT यह प्रभावित करता है कि पाठ कितनी सहजता से स्ट्रीम होता है। आपके निगरानी तंत्र में दोनों को अलग-अलग दर्ज किया जाना चाहिए।

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 पैरामीटर

OpenAI SDK में स्ट्रीमिंग सक्षम करने के लिए stream=True को chat.completions.create कॉल में सेट करना आवश्यक है। प्रतिक्रिया का प्रकार ChatCompletion ऑब्जेक्ट से बदलकर Stream[ChatCompletionChunk] इटरेटर हो जाता है। प्रत्येक chunk में delta होता है, जिसमें या तो content स्ट्रिंग का अंश होता है या None, जब टोकन किसी टूल कॉल का हो या स्ट्रीम समाप्त हो रही हो।

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

पूरी प्रतिक्रिया को संचित करना

कई अनुप्रयोग प्रवाहों में आपको प्रतिक्रियाशीलता के लिए UI पर टोकन स्ट्रीम करने और लॉगिंग, कैशिंग या आगे की प्रक्रिया के चरणों जैसे बाद के प्रसंस्करण के लिए पूरी प्रतिक्रिया का पाठ संचित करने — दोनों की आवश्यकता होती है। तरीका सरल है: स्ट्रीम पर पुनरावृत्ति करें, प्रत्येक chunk को client तक प्रिंट या yield करें, और साथ-साथ उसकी सामग्री को जोड़कर एक पूरी स्ट्रिंग बनाएँ।

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

उपयोग आँकड़ों के साथ स्ट्रीमिंग

डिफ़ॉल्ट रूप से स्ट्रीमिंग प्रतिक्रिया में टोकन उपयोग के आँकड़े (prompt टोकन, completion टोकन) शामिल नहीं होते। इन्हें शामिल करने के लिए stream_options={'include_usage': True} भेजें। उपयोग संबंधी डेटा content stream समाप्त होने के बाद अंतिम chunk में आता है। उत्पादन अनुप्रयोगों में लागत दर्ज करने और दर-सीमा की निगरानी के लिए यह महत्वपूर्ण है।

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}')

स्ट्रीमिंग कब न करें

स्ट्रीमिंग हमेशा सही विकल्प नहीं होती। इन स्थितियों में स्ट्रीमिंग से बचें: (1) किसी काम को करने से पहले आपको पूरी प्रतिक्रिया की आवश्यकता हो, जैसे JSON पार्स करना या टूल कॉल का पता लगाना; (2) प्रतिक्रिया बहुत छोटी हो (30 टोकन से कम), जहाँ स्ट्रीमिंग का अतिरिक्त भार बचाए गए समय से अधिक देरी जोड़ता हो; या (3) आप बहुत से अनुरोधों का बैच प्रसंस्करण कर रहे हों, जहाँ व्यक्तिगत प्रतिक्रिया की विलंबता से अधिक महत्वपूर्ण थ्रूपुट हो। इन मामलों में सामान्य गैर-स्ट्रीमिंग कॉल सरल और उतनी ही तेज़ होती हैं।

Anthropic और Gemini API के साथ स्ट्रीमिंग

स्ट्रीमिंग केवल OpenAI ही नहीं, बल्कि सभी प्रमुख LLM प्रदाता API में उपलब्ध है। तरीका समान है, लेकिन SDK इंटरफ़ेस में थोड़ा अंतर होता है। Anthropic का Python SDK संदर्भ प्रबंधक के रूप में client.messages.stream() का उपयोग करता है, जबकि Gemini generate_content(stream=True) का उपयोग करता है। प्रदाता-स्वतंत्र अनुप्रयोग बनाते समय स्ट्रीमिंग इंटरफ़ेस को एक सामान्य जनरेटर फ़ंक्शन के पीछे अमूर्त करें।

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}')

जनरेटर-आधारित स्ट्रीमिंग इंटरफ़ेस

एक साफ़ वास्तुकला पैटर्न स्ट्रीमिंग को ऐसे Python जनरेटर फ़ंक्शन में लपेटता है जो टोकन स्ट्रिंग yield करता है। इससे स्ट्रीमिंग तर्क और उपभोग तर्क अलग हो जाते हैं — कॉल करने वाले जनरेटर पर पुनरावृत्ति कर सकते हैं, किसी file में लिख सकते हैं, WebSocket को अग्रेषित कर सकते हैं या स्ट्रिंग में संचित कर सकते हैं, और स्ट्रीमिंग कोड को यह जानने की आवश्यकता नहीं होती कि उसके आउटपुट का उपयोग कैसे किया जा रहा है। यही अधिकांश उत्पादन स्ट्रीमिंग API का आधार है।

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!'}]))

टर्मिनल और CLI अनुप्रयोगों में स्ट्रीमिंग

टर्मिनल अनुप्रयोगों में स्ट्रीम किया गया आउटपुट टाइप करने जैसा दिखाई देता है — प्रत्येक वर्ण बनते ही तुरंत दिखाई देता है। मुख्य आवश्यकता प्रत्येक print कॉल में flush=True का उपयोग करना है। flush किए बिना Python आउटपुट को newline आने तक बफ़र करता है, जिससे स्ट्रीमिंग का उद्देश्य ही विफल हो जाता है। आउटपुट के प्रारूपण पर अधिक नियंत्रण के लिए आप sys.stdout.write(token) और उसके बाद sys.stdout.flush() का भी उपयोग कर सकते हैं।

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)')

स्ट्रीमिंग और त्रुटि से उबरना

स्ट्रीमिंग त्रुटि प्रबंधन को जटिल बना देती है, क्योंकि कुछ टोकन client को भेजे जाने के बाद स्ट्रीम के बीच में विफलता हो सकती है। अनुशंसित तरीका यह है कि स्ट्रीम पर पुनरावृत्ति को try/except ब्लॉक में लपेटें और त्रुटि होने पर या तो client को त्रुटि-संकेत भेजें या स्ट्रीम को ठीक से बंद करें। उन स्थितियों से निपटने के लिए पूरी स्ट्रीम पर हमेशा एक समय-सीमा लागू करें, जिनमें सर्वर स्ट्रीम करना शुरू करने के बाद निर्माण के बीच में रुक जाता है।

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

त्वरित जाँच

इस पाठ में LLM टोकन स्ट्रीमिंग की अपनी समझ की जाँच करें।

पाठ का पुनरावलोकन

इस पाठ में आपने सीखा: स्ट्रीमिंग प्रत्येक जनरेट किए गए टोकन को सैंपल किए जाते ही क्लाइंट को भेजती है, जिससे उपयोगकर्ता को प्रतिक्रिया काफी तेज़ महसूस होती है; TTFT और TPOT अलग-अलग ट्रैक किए जाने वाले दो प्रमुख विलंबता मेट्रिक्स हैं; और stream=True OpenAI SDK की प्रतिक्रिया को चंक इटरेटर में बदल देता है, जिसका उपयोग आप for लूप से करते हैं। साफ़ और दोबारा उपयोग किए जा सकने वाले इंटरफ़ेस के लिए स्ट्रीम को जनरेटर फ़ंक्शन में रैप करें। अब हम Python SDK के साथ async स्ट्रीमिंग लागू करेंगे।

शुरुआत निःशुल्क

एआई शिक्षक के साथ Python सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
30
पाठ
120

अक्सर पूछे जाने वाले प्रश्न

क्या “टोकन स्ट्रीमिंग को समझना” पाठ निःशुल्क है?

हाँ—“टोकन स्ट्रीमिंग को समझना” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और AI Engineering Academy पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। AI Engineering Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“टोकन स्ट्रीमिंग को समझना” में मैं क्या सीखूँगा?

समझें कि स्ट्रीमिंग एपीआई निर्माण के साथ-साथ आंशिक पूर्णताएँ कैसे भेजती है, OpenAI का stream=True पैरामीटर कैसे काम करता है और स्ट्रीमिंग उपयोगकर्ता अनुभव को कब बेहतर बनाती है। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ AI Engineering Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या AI Engineering Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर AI Engineering Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 1वाँ पाठ है।

“टोकन स्ट्रीमिंग को समझना” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस AI Engineering Academy पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर AI Engineering Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. टोकन स्ट्रीमिंग को समझना
  2. Python SDK से स्ट्रीम का उपयोग करना
  3. Server-Sent Events के साथ FastAPI में स्ट्रीमिंग
  4. स्ट्रीम की गई प्रतिक्रियाओं में टूल कॉल संभालना
← AI Engineering Academy पर वापस जाएँ