05 β Streaming (jonli javob)¶
β¬ οΈ Oldingi: 04 β Suhbat va kontekst Β· π Kitob boshi Β· Keyingi: 06 β Strukturali chiqish β‘οΈ
Bu bobda: modelning javobini u to'liq tugaguncha kutmasdan, token-token (so'z-so'z) jonli ko'rsatishni o'rganamiz.
createStreambilan oqimni qabul qilamiz, terminaldaflush()bilan harf-harf chiqaramiz, brauzerga SSE (Server-Sent Events) orqali jonli uzatamiz va JavaScriptEventSourcebilan qabul qilamiz. Shuningdek oqimdan to'liq javobni yig'ib suhbat tarixiga qo'shamiz va streaming xatolarini boshqaramiz.
Muammo: bo'sh ekran va kutish¶
Tasavvur qiling: foydalanuvchi chatbot'ingizga uzun savol berdi β "Laravel'da autentifikatsiyani qadam-baqadam tushuntir". Model batafsil, 400 so'zli javob tayyorlaydi. Lekin oddiy messages->create so'rovida javob faqat to'liq tayyor bo'lganda qaytadi. Bu 10β15 soniya davom etishi mumkin.
Shu vaqt ichida foydalanuvchi nima ko'radi? Bo'sh ekran. Yoki aylanayotgan "yuklanmoqda" belgisi. U "buzilibmi?", "ilova qotdimi?" deb o'ylaydi. Ko'pchilik shu yerda sahifani yopadi.
Hayotiy o'xshatish. Tasavvur qiling, do'stingizdan uzun maktub kutyapsiz. Ikki holat bor:
- Oddiy javob β do'stingiz butun maktubni yozib, konvertga solib, pochta orqali yuboradi. Siz hech narsa ko'rmay turib, tugagunicha kutasiz. Keyin birdan to'liq maktub keladi.
- Streaming β do'stingiz sizga qo'ng'iroq qilib, yozayotgan paytida o'qib beradi. Siz har bir jumlani u yozishi bilanoq eshitasiz. Kutish "tirik" his qilinadi β gap ketyapti, hammasi joyida.
ChatGPT yoki Claude bilan suhbatlashganingizda javob harf-harf chiqib kelishini ko'rgansiz β bu aynan ikkinchi holat, ya'ni streaming. Foydalanuvchi natijani darhol ko'ra boshlaydi, kutish sezilmaydi.
Model javobni baribir token-token ishlab chiqaradi (1-bobda token β matnning AI o'qiydigan bo'lakchasi ekanini ko'rgandik). Oddiy so'rovda SDK shu tokenlarni siz uchun yig'ib, oxirida bir butun qilib beradi. Streaming'da esa biz tokenlarni kelishi bilanoq olamiz va ekranga chiqaramiz.
Streaming faqat tezroq emas β kutishni boshqaradi
Aslida modelning umumiy javob yozish vaqti ikkala holatda deyarli bir xil. Lekin his qilinadigan tezlik tubdan farq qiladi: birinchi token 1 soniyada chiqsa, foydalanuvchi "ishlayapti" deb biladi va o'qiy boshlaydi. Bu psixologik g'alaba β texnik emas, tajriba haqida.
Yechim: createStream bilan oqim¶
Streaming so'rovi oddiy create ga juda o'xshaydi β parametrlar (model, maxTokens, messages) bir xil. Faqat metod nomi boshqacha: create o'rniga createStream.
Farqi natijada: create bitta Message obyekti qaytaradi; createStream esa iterable oqim qaytaradi β uni foreach bilan aylantirib, har bir hodisani (event) olib boramiz.
<?php
require __DIR__ . '/vendor/autoload.php';
use Anthropic\Client;
// API kalitni MUHIT O'ZGARUVCHISIDAN ol β kodga YOZMA!
$client = new Client(apiKey: getenv('ANTHROPIC_API_KEY'));
// create() o'rniga createStream() β iterable oqim qaytaradi
$stream = $client->messages->createStream(
model: 'claude-opus-4-8',
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => 'Qisqa hikoya yoz'],
],
);
// Oqimni token-token aylantiramiz
foreach ($stream as $event) {
// har bir event β javobning bir bo'lagi haqida xabar
var_dump($event->type);
}
Bu yerda $stream β bir martalik o'qiladigan oqim. foreach ichida har takrorlanishda yangi hodisa keladi. Lekin hodisalar faqat matn emas β ular javob hayotining turli bosqichlarini bildiradi.
Hodisa turlari (event types)¶
Model javobni quyidagi bosqichlar bilan "hikoya qilib" beradi. Eng muhimlari:
Hodisa turi ($event->type) |
Ma'nosi |
|---|---|
message_start |
Javob boshlandi (hali matn yo'q β meta-ma'lumot). |
content_block_start |
Yangi kontent bloki ochildi (masalan, matn bloki). |
content_block_delta |
Matnning yangi bo'lagi keldi β bizga eng kerakli! |
content_block_stop |
Joriy blok tugadi. |
message_delta |
Yakuniy meta yangilanish (masalan, stop_reason). |
message_stop |
Butun javob tugadi. |
Bizni asosan content_block_delta qiziqtiradi β aynan shu hodisalar ichida foydalanuvchiga ko'rsatadigan matn bo'laklari keladi. Qolganlari boshlanish/tugash signallari (ularni keyinroq β yig'ish va xato boshqaruvida β ishlatamiz).
Matn bo'laklarini olish va darhol chiqarish¶
Har content_block_delta hodisasi ichida delta obyekti bor. Uning turi (delta->type) text_delta bo'lganda β bu matn bo'lagi, va delta->text da haqiqiy harflar yotadi.
Nega delta->type ni ham tekshiramiz?
delta har doim ham oddiy matn bo'lavermaydi. Masalan, model fikrlash (thinking) yoki tool (function calling, 9-bob) ishlatsa, boshqa turdagi delta'lar keladi (input_json_delta va h.k.). Shuning uchun matnni ko'rsatishdan oldin delta->type === 'text_delta' ekaniga ishonch hosil qilamiz β aks holda kerakmas ma'lumotni ekranga chiqarib qo'yishimiz mumkin.
Eng muhim sintaksis β har bo'lakni olib, darhol ekranga chiqarish:
foreach ($stream as $event) {
// faqat matn bo'laklarini ushlaymiz
if ($event->type === 'content_block_delta'
&& ($event->delta->type ?? '') === 'text_delta') {
echo $event->delta->text; // bo'lakni chiqaramiz
flush(); // bufferni darhol bo'shatamiz
}
}
Bu yerda ikkita kalit narsa bor:
echo $event->delta->textβ bo'lakni chiqaradi (masalan, "Bir bor", keyin " ekan, bir", keyin " yo'q ekan..." β qism-qism).flush()β PHP odatda chiqishni bufferda to'plab, keyin birdan yuboradi.flush()esa "to'plama, hozir yubor!" deydi. Streaming'ning butun mohiyati shu β har bo'lakni darhol uzatmasak, foydalanuvchi baribir oxirida birdan ko'radi (oddiy so'rovdan farqi qolmaydi).
($event->delta->type ?? '') β nega ???
message_start kabi ba'zi hodisalarda umuman delta yo'q. Agar to'g'ridan $event->delta->type ga murojaat qilsak, "undefined property" ogohlantirishi chiqishi mumkin. ?? '' (null-coalescing) operatori "agar yo'q bo'lsa, bo'sh satr deb hisobla" deydi β kod xavfsiz ishlaydi.
To'liq CLI misol: terminalda jonli javob¶
Endi hammasini birlashtirib, buyruq satrida (terminalda) jonli oqim ko'rsatadigan to'liq dasturni yozamiz. Ishga tushirilganda javob harf-harf chiqib kelishini ko'rasiz β xuddi kimdir terganday.
<?php
// stream-cli.php β terminalda jonli AI javobi
require __DIR__ . '/vendor/autoload.php';
use Anthropic\Client;
$client = new Client(apiKey: getenv('ANTHROPIC_API_KEY'));
$savol = $argv[1] ?? 'PHP nima ekanini 3 jumlada tushuntir.';
echo "Savol: {$savol}\n";
echo "Javob: ";
$stream = $client->messages->createStream(
model: 'claude-opus-4-8',
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => $savol],
],
);
foreach ($stream as $event) {
if ($event->type === 'content_block_delta'
&& ($event->delta->type ?? '') === 'text_delta') {
echo $event->delta->text;
flush(); // har bo'lakni darhol chiqar
}
}
echo "\n"; // oxirida yangi qator
Ishga tushirish:
Natija β javob terminalda jonli paydo bo'ladi, so'z-so'z. Birinchi so'z deyarli darhol chiqadi, qolgani ortidan oqib keladi. Bu oddiy create bilan erishib bo'lmaydigan tajriba.
Terminalda flush() ham kerakmi?
Ko'p hollarda terminalda PHP CLI chiqishni darrov ko'rsatadi, lekin ba'zi sozlamalarda buferlash bo'ladi. flush() ni qoldirish β zararsiz va kafolatli. Brauzerga uzatishda esa flush() mutlaqo shart (quyida ko'ramiz).
Brauzerga oqim: SSE (Server-Sent Events)¶
Terminal yaxshi, lekin haqiqiy ilova β bu veb-sahifa. Foydalanuvchi brauzerda savol yozadi, javob jonli chiqishini ko'rishni istaydi. Buning uchun server javobni qism-qism brauzerga uzatishi kerak.
Bu vazifaning standart, sodda yechimi β SSE (Server-Sent Events).
Hayotiy o'xshatish. SSE β bu bir tomonlama radio kabi. Server (radiostansiya) doimo efirga bo'lak-bo'lak xabar uzatadi; brauzer (radio) faqat tinglaydi. WebSocket (ikki tomonlama "telefon") dan farqli, SSE faqat server -> brauzer yo'nalishida ishlaydi β AI javobini oqimda yetkazish uchun aynan shu yetarli va eng oson.
SSE'ning ishlash formati juda sodda. Server quyidagi qoidalarga amal qiladi:
- Maxsus sarlavhalar yuboradi:
Content-Type: text/event-stream(bu β "men oqim uzataman" degani) vaCache-Control: no-cache. - Har xabarni
data: ...bilan boshlab, ikkita yangi qator (\n\n) bilan tugatadi. - Har yuborgandan keyin
flush()qiladi β aks holda hammasi oxirida birdan ketadi.
To'liq SSE endpoint¶
Quyida stream.php β brauzerdan ?savol=... qabul qilib, AI javobini SSE orqali jonli uzatadigan to'liq endpoint:
<?php
// stream.php β AI javobini brauzerga SSE bilan jonli uzatadi
require __DIR__ . '/vendor/autoload.php';
use Anthropic\Client;
// --- 1. SSE sarlavhalari ---
header('Content-Type: text/event-stream'); // "bu oqim" deb belgilaymiz
header('Cache-Control: no-cache'); // kesh qilmasin
header('X-Accel-Buffering: no'); // Nginx bufferlamasin (muhim!)
// PHP chiqish buferini o'chiramiz β har bo'lak darhol ketsin
while (ob_get_level() > 0) {
ob_end_flush();
}
$client = new Client(apiKey: getenv('ANTHROPIC_API_KEY'));
// brauzerdan kelgan savol (oddiy tozalash bilan)
$savol = trim($_GET['savol'] ?? 'Salom!');
// --- 2. Oqimni boshlaymiz ---
$stream = $client->messages->createStream(
model: 'claude-opus-4-8',
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => $savol],
],
);
// --- 3. Har bo'lakni SSE xabari sifatida yuboramiz ---
foreach ($stream as $event) {
if ($event->type === 'content_block_delta'
&& ($event->delta->type ?? '') === 'text_delta') {
$matn = $event->delta->text;
// SSE'da yangi qator maxsus belgi β uni \n bilan almashtiramiz,
// brauzerda qaytadan tiklaymiz
$matn = str_replace("\n", '\\n', $matn);
echo "data: {$matn}\n\n"; // SSE xabar formati
flush(); // darhol uzat!
}
}
// --- 4. Tugadi signalini yuboramiz ---
echo "event: done\ndata: [TUGADI]\n\n";
flush();
Diqqat qiling:
X-Accel-Buffering: noβ agar serveringiz oldida Nginx tursa, u o'zi javobni buferlab, oqimni "bo'g'ib" qo'yishi mumkin. Bu sarlavha "buni qilma" deydi. Apache uchun odatda kerak emas, lekin zarar qilmaydi.str_replace("\n", '\\n', ...)β SSE protokolida\nxabar chegarasi sifatida ishlatiladi. Agar AI matni ichida haqiqiy yangi qator bo'lsa, u SSE'ni chalkashtiradi. Shuning uchun yangi qatorni\n(matn sifatida) ga aylantirib yuboramiz, brauzerda qaytarib o'giramiz.event: doneβ oxirida o'zimizning maxsus "tugadi" signalini yuboramiz. Brauzer shuni eshitib, "yozilyapti" indikatorini o'chiradi.
Foydalanuvchi savolini hech qachon ko'r-ko'rona ishonma
Bu yerda $savol to'g'ridan brauzerdan keldi. Real ilovada uni tekshiring (uzunlik chegarasi, kerakmas belgilar). Bundan ham muhimi β foydalanuvchi matni model'ni "aldab", noto'g'ri ish qildirishi mumkin (prompt injection). Bu jiddiy mavzuni 20-bobda (Xavfsizlik) batafsil ko'ramiz. Hozircha eslab qoling: foydalanuvchi kiritmasi β ishonchsiz manba.
Frontend tomoni: brauzerda EventSource¶
Server tayyor. Endi brauzer tomonida oqimni qabul qilish kerak. Brauzerlarda SSE uchun maxsus tayyor vosita bor β EventSource. U serverga ulanadi va har kelgan data: xabarni hodisa sifatida beradi.
Bu PHP kitobi bo'lgani uchun frontend'ga chuqur kirmaymiz β faqat g'oyani ko'rsatamiz (kichik HTML + JavaScript):
<!-- index.html β sodda jonli chat -->
<input id="savol" placeholder="Savolingiz..." size="40">
<button onclick="sora()">Yubor</button>
<div id="javob" style="white-space: pre-wrap; margin-top: 1rem;"></div>
<script>
function sora() {
const savol = document.getElementById('savol').value;
const javobDiv = document.getElementById('javob');
javobDiv.textContent = ''; // tozalaymiz
// serverga ulanamiz (bizning stream.php)
const manba = new EventSource('stream.php?savol=' + encodeURIComponent(savol));
// har "data:" xabari kelganda β matnni qo'shamiz
manba.onmessage = (e) => {
if (e.data === '[TUGADI]') { // o'zimizning tugash signali
manba.close(); // ulanishni yopamiz
return;
}
// \n ni qaytadan haqiqiy yangi qatorga o'giramiz
javobDiv.textContent += e.data.replaceAll('\\n', '\n');
};
// xato bo'lsa β ulanishni yopamiz
manba.onerror = () => manba.close();
}
</script>
Bu yerda asosiy g'oya:
new EventSource(url)β serverga oqim ulanishini ochadi.manba.onmessageβ hardata:xabari kelganda chaqiriladi;e.datada matn bo'lagi bor. Unidivga qo'shib boramiz β natija jonli chiqadi.manba.close()β tugagach yoki xatoda ulanishni yopamiz (aks holdaEventSourceo'zi qayta ulanishga urinaveradi).
Boshqa usul: fetch + ReadableStream
EventSource faqat GET so'rovini qo'llaydi va sarlavha qo'sholmaydi (masalan, Authorization). Murakkabroq ilovalarda ko'pincha fetch() bilan POST qilib, javob oqimini response.body.getReader() orqali o'qishadi. G'oya bir xil β qism-qism o'qish; faqat moslashuvchanroq. Boshlang'ich uchun EventSource to'liq yetarli.
Streaming + suhbat: oqimdan tarixni yig'ish¶
4-bobda suhbatni eslaysiz: har savol-javobni messages massiviga qo'shib, modelga butun tarixni qayta yuboramiz (API stateless β o'tmishni o'zi eslamaydi). Streaming'da bitta nozik nuqta bor: javob bo'lak-bo'lak keladi, lekin tarixga to'liq javobni qo'shishimiz kerak.
Yechim oddiy: oqim davomida har bo'lakni ekranga chiqarish bilan birga, bir o'zgaruvchiga to'plab boramiz. Oxirida shu to'plangan matnni assistant xabari sifatida tarixga qo'shamiz.
<?php
require __DIR__ . '/vendor/autoload.php';
use Anthropic\Client;
$client = new Client(apiKey: getenv('ANTHROPIC_API_KEY'));
// suhbat tarixi
$tarix = [
['role' => 'user', 'content' => 'Salom! Sen kimsan?'],
];
$stream = $client->messages->createStream(
model: 'claude-opus-4-8',
maxTokens: 1024,
messages: $tarix,
);
$toliqJavob = ''; // to'liq javobni shu yerga yig'amiz
foreach ($stream as $event) {
if ($event->type === 'content_block_delta'
&& ($event->delta->type ?? '') === 'text_delta') {
$bolak = $event->delta->text;
echo $bolak; // foydalanuvchiga jonli ko'rsat
flush();
$toliqJavob .= $bolak; // VA tarix uchun yig'
}
}
echo "\n";
// to'liq javobni tarixga qo'shamiz β keyingi savol kontekstida bo'lsin
$tarix[] = ['role' => 'assistant', 'content' => $toliqJavob];
// endi keyingi savolni qo'shib, yana createStream chaqirish mumkin β
// model oldingi javobini "eslaydi" (chunki biz $tarix ni qayta yubordik)
$tarix[] = ['role' => 'user', 'content' => 'Yana bir bor takrorla?'];
// $client->messages->createStream(model: ..., maxTokens: ..., messages: $tarix);
Mana shu naqsh β "ko'rsat va yig'" β jonli chatbotning yuragi: foydalanuvchi javobni oqimda ko'radi, ilova esa orqada to'liq matnni keyingi burilish uchun saqlab qoladi.
SSE endpoint'da tarixni qayerda saqlash?
Veb-ilovada $toliqJavob ni session, ma'lumotlar bazasi yoki keshda saqlaysiz (har so'rov alohida HTTP so'rov bo'lgani uchun PHP o'zgaruvchisi yashamaydi). G'oya bir xil β oqimdan yig'ib, tarix sifatida saqlash. Tarixni boshqarish 16-bob (Kesh va xarajat) da xarajat nuqtai nazaridan ham muhim β uzun tarix ko'p token, ko'p pul.
Qachon streaming, qachon oddiy create?¶
Streaming kuchli, lekin har joyda kerak emas. Tanlovni vazifa belgilaydi:
| Holat | Tavsiya | Sababi |
|---|---|---|
| Foydalanuvchi javobni ko'rib turadi (chat, yordamchi, kontent generatori) | Streaming | Kutish "tirik" his qilinadi, tajriba yaxshi. |
| Uzun javob (esse, kod, batafsil tahlil) | Streaming | Bo'sh ekran uzoq bo'lmaydi; timeout xavfi kamayadi. |
| Qisqa javob (bitta so'z, "ha/yo'q", klassifikatsiya) | Oddiy create |
Bo'lakka bo'lishdan foyda yo'q β baribir tez. |
| Fonda ishlaydigan vazifa (queue, cron, batch) | Oddiy create |
Hech kim kutmaydi; to'liq natija osonroq. |
| Strukturali chiqish (JSON, 6-bob) kerak | Oddiy create |
To'liq JSON kelishini kutish soddaroq va ishonchli. |
| Tool/function calling (9-bob) sikli | Odatda oddiy create |
Loop'da to'liq javobni tahlil qilish qulayroq. |
Streaming timeout muammosini ham yengillashtiradi
Juda uzun javoblarda oddiy create so'rovi server yoki HTTP timeout'iga uchrashi mumkin (javob juda uzoq kelmasa, ulanish uziladi). Streaming'da esa ma'lumot doimo oqib turadi β ulanish "tirik" qoladi, timeout xavfi kamayadi. Bu uzun matnlar uchun yana bir afzallik.
Xato boshqaruvi: oqim uzilsa nima bo'ladi?¶
Oddiy so'rovga qaraganda streaming'da xato ehtimoli ko'proq nuqtada bor β chunki ulanish uzoq vaqt ochiq turadi. Tarmoq uzilishi, server qayta yuklanishi yoki foydalanuvchi sahifani yopishi mumkin β va bularning hammasi javob o'rtasida sodir bo'lishi mumkin.
Asosiy himoya β foreach ni try/catch ichiga olish. SDK xatolari APIException (va undan meros olgan klasslar) sifatida keladi:
<?php
use Anthropic\Core\Exceptions\APIException;
$toliqJavob = '';
try {
$stream = $client->messages->createStream(
model: 'claude-opus-4-8',
maxTokens: 1024,
messages: [['role' => 'user', 'content' => 'Uzun maqola yoz']],
);
foreach ($stream as $event) {
if ($event->type === 'content_block_delta'
&& ($event->delta->type ?? '') === 'text_delta') {
$bolak = $event->delta->text;
echo $bolak;
flush();
$toliqJavob .= $bolak;
}
}
} catch (APIException $e) {
// oqim o'rtasida uzildi β foydalanuvchini ogohlantiramiz
echo "\n[Uzr, javob to'xtab qoldi: " . $e->getMessage() . "]";
// $toliqJavob da QISMAN javob bor β uni saqlab qolish mumkin
}
Streaming xatosida ikkita muhim jihat:
- Qisman javob β oqim uzilganda
$toliqJavobda shu paytgacha kelgan matn saqlanib qoladi. Buni tashlab yuborish shart emas: foydalanuvchiga ko'rsatib, "davom ettirishni xohlaysizmi?" deb so'rashingiz mumkin. - Foydalanuvchi ulanishni uzsa β brauzerda foydalanuvchi sahifani yopsa, SSE ulanishi uziladi. Real ilovada
connection_aborted()bilan buni aniqlab, keraksiz so'rovni to'xtatishingiz mumkin (model tokenlari β pul; behuda sarflamang).
Streaming'da SDK avtomatik retry'si cheklangan
8-bobda ko'ramizki, SDK 429/5xx xatolarda so'rovni avtomatik qayta urinadi. Lekin streaming'da oqim boshlangach β ya'ni birinchi bo'laklar kelganidan keyin β uzilsa, SDK uni o'zi qayta boshlay olmaydi (qisman matn allaqachon "ketib bo'lgan"). Shuning uchun streaming'da o'zingiz try/catch bilan tayyor turishingiz muhimroq. Xato turlari va retry strategiyasini 8-bob (Xatolar va ishonchlilik) da to'liq ochamiz.
Xulosa¶
- Streaming β modelning javobini u to'liq tugaguncha kutmasdan, token-token kelishi bilanoq ko'rsatish. Bu kutishni "tirik" qiladi va foydalanuvchi tajribasini tubdan yaxshilaydi.
$client->messages->**createStream**(...)oddiycreatebilan bir xil parametr oladi, lekin iterable oqim qaytaradi β uniforeach ($stream as $event)bilan aylantiramiz.- Bizga kerakli hodisa β
content_block_delta+delta->type === 'text_delta'; matn$event->delta->textda. Har bo'lakniechoqilib,flush()bilan darhol chiqaramiz. - Brauzerga jonli uzatish uchun SSE:
Content-Type: text/event-streamsarlavhasi +echo "data: {$matn}\n\n"; flush();. Frontend tomondaEventSourceqabul qiladi. - Streaming + suhbat: oqimdan to'liq javobni bir o'zgaruvchiga yig'ib, oxirida
assistantxabari sifatida tarixga qo'shamiz ("ko'rsat va yig'" naqshi). - Qachon: uzun/jonli UI -> streaming; qisqa, fon-ish yoki strukturali (JSON) -> oddiy
create. Streaming uzun javoblarda timeout xavfini ham kamaytiradi. - Xatolar: oqim uzoq ochiq turgani uchun
try/catch (APIException)shart; uzilganda qisman javob saqlanib qoladi β uni yo'qotmang.
Amaliy mashqlar¶
-
CLI jonli javob.
php stream-cli.php "..."dasturini terib ishga tushiring. Bir martaflush()qatorini olib tashlab, qayta ishga tushiring β farqni sezasizmi? (Buferlash bo'lsa, javob oxirida birdan chiqadi.) -
SSE endpoint.
stream.phpni va soddaindex.htmlni yarating. Brauzerda savol yozib, javob jonli chiqishini ko'ring. Keyin javob o'rtasida brauzer tabini yopib, server logigaconnection_aborted()holatini chiqaring β ulanish uzilganini aniqlang. -
Tezlik o'lchovi. Bitta uzun savolni (masalan, "PHP tarixini batafsil yoz") avval oddiy
createbilan, keyincreateStreambilan so'rang. Har holatda birinchi belgi qachon ekranga chiqqanini (mikrosekundlardamicrotime(true)bilan) o'lchang. Streaming'da "birinchi token" qancha tezroq? -
Oqimdan tarix yig'ish. "Ko'rsat va yig'" naqshidan foydalanib, ikki burilishli suhbat yozing: birinchi savol streaming bilan, javobni
$tarixga qo'shing, keyin tarixga tayanadigan ikkinchi savolni (masalan, "buni soddaroq tushuntir") yana streaming bilan so'rang. Model birinchi javobini "esladimi"? -
Xatoga chidamli oqim. Streaming kodingizni
try/catch (APIException)ga o'rab, xato bo'lganda shu paytgacha yig'ilgan qisman javobni faylga saqlang. Soxta xatoni sinab ko'rish uchun (masalan, noto'g'ri API kalit bilan) blok ishlashini tekshiring.
β¬ οΈ Oldingi: 04 β Suhbat va kontekst Β· π Kitob boshi Β· Keyingi: 06 β Strukturali chiqish β‘οΈ