Мазмұнға өту
2025 ж. 23 мам.·6 мин оқу

LLM стримингін тоқтату: артық токен үшін төлемеудің жолы

LLM стримингін тоқтату артық токендерді азайтады, әсіресе пайдаланушы беттен кетіп қалған кезде. Сигналдар, таймауттар, логтар және тексерістерді қарастырамыз.

LLM стримингін тоқтату: артық токен үшін төлемеудің жолы

Экран жабылғаннан кейін не бұзылады

Жабылған вкладка деген жұмыс сол сәтте тоқтады деген сөз емес. Браузер, мобильді желі, прокси және сервер тізбекті бір мезетте үзбейді. Пайдаланушы кетіп қалды, ал сұрау тағы бірнеше секунд, кейде одан да ұзақ өмір сүріп тұрады.

Бұл әсіресе жауаптарды стримдегенде байқалады. Экран жоғалды, мәтінді ешкім оқып жатқан жоқ, бірақ модель бәрібір токендер генерациялап жатыр, өйткені серверге анық тоқтату сигналы келмеді немесе ол әрі қарай жіберілмеді. Биллинг үшін айырмашылық жоқ: модель есептеп тұрса, токендер шотқа түседі.

Мәселе сирек авария сияқты көрінеді. Сырттай бәрі қалыпты болуы мүмкін: процесс аяқталды, провайдер толық жауап берді, апстрим метрикалары жасыл. Тек бұл жауаптың пайдасы қалмады, өйткені клиенттік қосылым одан бұрын өліп қалған.

Осының салдарынан бірден бірнеше нәрсе бұзылады:

  • шығындар себепсіз өседі;
  • кезек артық тапсырмаларды ұстап тұрады;
  • басқа сұраулардың кідірісі артады;
  • логтарда пайдаланушы ештеңе алмаған жерде "сәтті" деген белгі тұрады.

Ең жағымсызы — мұндай жағдайларды өткізіп алу оңай. Егер тек модель провайдерінің сәтті HTTP-жауаптарына қарасаңыз, жүйе сау болып көрінеді. Бірақ оларды клиент оқиғаларымен салыстырсаңыз, жиі үзіліс көрінеді: фронтенд ағынды жауып қойған, ал бэкенд генерацияның аяқталуын әлі күтіп тұр.

Қарапайым чатта бұл ұсақ нәрсе сияқты көрінеді. Пайдаланушы ұзын жауапты ашты, алғашқы жолдарды оқыды, экранды жапты да кете барды. Модель тағы 900 токен жазып бітірді, сервер оларды соңына дейін қабылдады, ал шот біреу бүкіл мәтінді оқып шыққандай өсті.

Ақау бір жерде болады: пайдаланушының кеткен фактісі мен генерацияның нақты тоқтауының арасында. Егер тоқтату клиенттен серверге, одан әрі провайдерге өтпесе, жүйе енді керек емес мәтінге ақша мен уақыт жұмсай береді.

Команда үшін бұл бақылау жағынан да проблема. Есептерде "сәтті" тұр, ал өнімде — бос орын немесе үзілген жауап. Мұндай сұраулар көбейгенде, шығын есебі тез дәлдігін жоғалтады.

Ақша мен уақыт қайда кетеді

Жоғалту адам вкладканы жапқан сәтте емес, сәл кейін басталады. Модель үшін сессия көбіне әлі тірі болады: клиент кетіп қалды, ал сервер мен провайдер токендерді әлі шығарып жатыр. Егер тоқтату тізбектің соңына дейін жетпесе, сіз нақты тоқтағанға дейін шыққан әр токен үшін төлейсіз.

Қысқа жауаптарда бұл байқалмайды. Ұзақ қорытындыларда, қолдау чаттарында немесе SQL генерациясында шот тез өседі. Пайдаланушы бұл 500–800 токенді оқымайды, бірақ провайдер оларды әлдеқашан есептеді, ал сервер ағынды қабылдап, өңдеп, керек болғаннан ұзақ ұстап тұрады.

Уақыт тек жауаптың өзіне кетпейді. Аяқталмай қалған стрим кезекте ілініп тұрғанда, ол воркерді, сокетті, жадты және кейде қосылым пулындағы орынды алып тұрады. Бір мұндай сұрау сирек қиындық тудырады. Ал ондаған "өлі" стрим басқа күтіп отырғандарға қосымша кідіріс береді. Қарбалас уақытта бұл анық сезіледі: трафик өспеген, бірақ жүйе баяуырақ жауап береді.

Жағдай клиент қайта сұрау жібергенде одан әрі нашарлайды. Адам кідірісті көріп, жаңартуды басады немесе чатты қайта ашады, сөйтіп бір шығынның орнына екі шығын пайда болады. Есептерде мұны кәдімгі жүктеменің өсуі деп қабылдау оңай, ал шын мәнінде артық токендердің бір бөлігі жетпей қалған тоқтатудан шыққан.

Дәл тоқтату белгісі болмаса, команда соқыр күйде таласады. Дамытушылар провайдер артық жазып бітірді деп ойлайды. Қаржы командасы шотта токен көп екенін көреді. Продакт пайдаланушылар ұзақ сұрақ қоя бастады деп шешеді. Логтарда тоқтату оқиғасы, уақыты, сұрау ID-і және тоқтаған сәттегі токен саны жоқ болса, әркімнің өз нұсқасы болады.

Егер сұрау бірнеше қабаттан өтсе — мысалы, клиент, сіздің бэкенд, API-шлюз және модель провайдері — әр кезеңде аудит ізін сақтаған пайдалы. AI Router сияқты жүйелерде мұны бір OpenAI-үйлесімді шақыру және ортақ аудит-логтар арқылы жасау оңай: сонда тоқтату сигналы қай жерде жоғалғаны және артық токендер қай жерден басталғаны тез көрінеді.

Клиенттің кеткенін қалай байқауға болады

Шағым күту кеш болады. Егер экран жабылса, вкладка жаңартылса немесе қосымша фонға кетсе, сервер әлі де токен алып, сол үшін төлеп жатуы мүмкін. Демек, тоқтатуды тапсырма өзінен-өзі бітіп болғанда емес, клиент қосылымды үзген сәтте ұстау керек.

Браузерде бұл әдетте close және abort арқылы көрінеді. Пайдаланушы басқа бетке өтті, вкладканы жапты немесе "Стоп" батырмасын басты — фронтенд дереу тоқтату сигналын жіберуі тиіс. Мобильді клиентте де ұқсас: қосымша жабылды, желі жоғалды, чат экраны жойылды. Клиент үндемесе, бұл пайдаланушы әлі жауап күтіп отыр деген сөз емес.

Бір request_id алғашқы сұраудан соңғы байтқа дейін өмір сүруі керек. Оны фронтенд, API-шлюз, кезек, воркер және провайдер шақыруы арқылы өткізіңіз. Әйтпесе сіз тек тарихтың бөліктерін көресіз: бір логта қосылым үзілуі бар, екіншісінде генерация жүріп жатыр, бірақ оларды байланыстыру мүмкін емес.

Тоқтау себептерін бірнеше нақты оқиғаға бөлген дұрыс:

  • client_abort — клиент сұрауды өзі тоқтатты;
  • network_close — қосылым үзілді;
  • upstream_timeout — провайдер уақытында жауап бермеді;
  • server_timeout — сервер күтуін өзі тоқтатты.

Бұл ұсақ нәрсе сияқты, бірақ артық токендер көбіне осы жерде тығылады. Егер бәрін "желілік қате" деп жазсаңыз, команда диалогты бірінші кім үзгенін түсінбейді.

Содан кейін жергілікті тоқтатуды провайдер жағында не болғанымен салыстырыңыз. Сервер abort алып, клиентке SSE-ні жауып, бірақ жоғарырақ деңгейде генерацияны тоқтатпаған болуы мүмкін. Онда пайдаланушы кетіп қалды, ал модель тағы 10–20 секунд жауап жазуды жалғастырады. Шығынды есептеу үшін екі фактіні қатар сақтаған дұрыс: клиент жағындағы тоқтату уақыты және провайдер жағындағы нақты тоқтау уақыты.

Егер олардың арасында айтарлықтай алшақтық болса, тоқтату тек жартылай жұмыс істеп тұр. Егер сізде AI Router сияқты ортақ логтары бар бір шлюз болса, бірдей идентификаторды бүкіл OpenAI-үйлесімді сұрау арқылы өткізіп, оқиғаларды тізбек бойынша жылдам салыстыру оңай.

Генерацияны қадамдап қалай тоқтатуға болады

Егер тоқтату тек интерфейсте өмір сүрсе, ақша бәрібір кетеді. Пайдаланушы экранды жапты, ал сервер модельден келген ағынды әлі оқып, артық токендер үшін төлеп тұр.

Жұмыс істейтін схема қарапайым: сұрауда бір ортақ тоқтату сигналы болуы керек. Бірі браузер үшін, бірі бэкенд үшін бөлек емес, LLM API-ға дейін баратын бір ғана шындық көзі болуы тиіс.

Әдетте схема былай көрінеді:

  1. Клиент сұрау басталған сәтте тоқтату сигналын жасайды. Пайдаланушы вкладканы жапса, "стоп" басса немесе қосымша байланысын жоғалтса, бұл сигнал бірден іске қосылады.
  2. Бэкенд сол сигналды қабылдап, өз өңдегішіне байлайды. Клиент кетсе, сервер модель жауапты өзі аяқтайды деп күтпейді.
  3. Сервер тоқтатуды әрі қарай, модельге немесе шлюзге кететін шығыс сұрауға жеткізеді.
  4. Сигнал келген бойда сервер клиентке баратын стримді жабады да, модельге кететін шығыс сұрауды дереу үзеді. Бұны қадамдардың арасында ұзақ кідіріспен жасамаңыз.
  5. Жүйе тоқтатудың қысқа растауын күтеді, әдетте 1–3 секунд. Растау келмесе, сервер сұрауды күштеп аяқтап, себебін логқа жазады.

Себепті ашық сақтау жақсы: "экран жабылды", "желі үзілді", "лимит іске қосылды", "пайдаланушы стоп басты". Кейін осы логтар арқылы ақшаның қай жерде кетіп жатқанын — мобильді желіде ме, ұзақ жауаптарда ма, әлде интерфейс қателерінде ме — оңай түсінесіз.

Жиі жіберілетін қате: команда клиентке баратын тек SSE немесе WebSocket-ті жабады, бірақ модельмен байланысқан қосылымды қозғамайды. Пайдаланушы ештеңе көрмей қалады, ал шот өсіп тұрады. Мұнда ереже қарапайым: клиент жоқ болса — генерация да жоқ.

Тексеру де қарапайым. Ұзын стрим ашыңыз, жауаптың ортасында экранды жабыңыз да, токен санағы бірден өсуді тоқтатты ма, соны қараңыз. Егер жоқ болса, тоқтату әзірге тек интерфейс деңгейінде жұмыс істеп тұр.

Сервер жағында не істеу керек

SDK-ны сол күйінде қалдырыңыз
Қазіргі код пен промпттарды қолдана беріңіз, тек base_url-ды өзгертіңіз.

Клиент қосылымды үзгенде, сервер модель жауапты бітіргенше күтпеуі керек. Қосымша abort алған бойда тапсырманы воркерден алыңыз, провайдерге баратын ағынды жабыңыз және жадты босатыңыз. Әйтпесе пайдаланушы кетіп қалғанымен, API не GPU әлі де токен мен уақыт жұмсай береді.

Тәжірибеде бұл сервердің өзі сұрауды тоқтата алғанда ғана жұмыс істейді. Фронттағы бір ғана тоқтату жеткіліксіз. Браузер вкладканы жабуы мүмкін, мобильді қосымша фонға кетуі мүмкін, прокси сокетті жоғалтуы мүмкін. Осы жағдайлардың бәрінде сервер генерацияны жауаптың соңын күтпей өзі аяқтауы тиіс.

Таймауттар мен статустар

Барлық лимитті бір жерге араластырмаңыз. Клиент таймауты фронтендпен байланысты қадағалайды. Модель таймауты LLM-нен жауап күту уақытын шектейді. Жалпы дедлайн сұраудың берілген мерзімнен ұзақ өмір сүруіне жол бермейді. Бұл шекаралар бөлінгенде, команда тоқтау себебін тезірек көреді және желі үзілуін ұзақ генерациямен шатастырмайды.

Ұзын жауаптар үшін промпт әдетте қысқа болса да, қатаң max_tokens қойыңыз. Шамадан тыс жалпылама сұрау модельді ешкім оқымайтын ұзын мәтінге оңай алып кетеді. Аздап запас қалдырғаннан гөрі, шексіз лимит көбіне қымбатқа түседі.

cancelled статусын failed және timeout-тан бөлек сақтаңыз. Бұл әртүрлі оқиғалар. Failed — код, желі немесе провайдер қателігі. Timeout — сервер шекке жетіп, сұрауды өзі тоқтатты. Cancelled — пайдаланушы немесе жоғарғы сервис ойын өзгертті. Бұларды бір статусқа біріктірсеңіз, метрикалар өтірік айта бастайды.

Ішкі метрикаларға әр сұрау үшін бір тоқтату себебін жіберіңіз. Белгілер жиынтығы емес, бір ғана қорытынды өріс: client_abort, model_timeout, gateway_deadline немесе manual_cancel. Сонда есептерде артық токен қайда кетіп жатқанын, ал қай жерде сервис логикасында проблема барын көруге болады.

Егер сізде бірнеше модель мен провайдер болса, осы логиканы шлюз деңгейінде ұстау ыңғайлырақ. Сонда тоқтату, лимиттер және статус ережелері барлық маршрут үшін бірдей болады, ал жүйенің мінез-құлқы нақты SDK-ға аз тәуелді болады.

Төлем бәрібір өсетін қателер

Көбіне ақша бір үлкен ақаудан емес, клиент, сервер және модель провайдері арасындағы ұсақ үзілістен кетеді. Пайдаланушы экранды жапты, ал генерация тағы 10–30 секунд өмір сүріп тұр. Сол уақытта артық токендер жиналып, команда мәселені тек шоттан байқайды.

Ең жиі қате қарапайым: сіз браузерге немесе мобильді клиентке баратын тек SSE-ағынды жабасыз, бірақ модельге кететін бастапқы сұрауды тоқтатпайсыз. Интерфейс үшін бәрі ұқыпты сияқты: мәтін енді келмейді. Ал провайдер үшін ештеңе өзгермеді, ол генерация біткенше токендерді санай береді.

Екінші қате қымбатырақ: команда провайдер өзі клиенттің кеткенін түсініп, жауапты өзі үзеді деп үміттенеді. Кейде бұл жұмыс істейді, кейде жоқ. Егер қосымша мен модельдің арасында шлюз, прокси немесе OpenAI-үйлесімді қабат тұрса, тоқтату сигналы оны анық жібермесеңіз, жолда жоғалып кетуі мүмкін.

Тағы бір тұзақ — "сақтық үшін" тым жоғары max_tokens. Егер модель әдетте 300–500 токен ішінде жауап берсе, ал сіз әр жолы 4000 рұқсат етсеңіз, тоқтату сәтсіз болғанда бұл бірден қосымша шығынға айналады. Мұндай запас тек бірінші трафик толқынына дейін ғана қауіпсіз сияқты көрінеді.

Сұрау трассировкасы да жиі бұзылады. Қосымшада ішкі chat_id бар, шлюз өз request_id-ін жасайды, ал провайдер тағы бір идентификатор қайтарады. Егер бұларды бір-бірімен байланыстырмасаңыз, серверге нақты қай сұрауды тоқтату керегін түсіну қиын.

Әдетте мәселе былай көрінеді:

  • фронт қосылымды жапты, бірақ бэкенд cancel-ді әрі қарай жібермеді;
  • сервер cancel жіберді, бірақ провайдер request_id-ін сақтамады;
  • тоқтату шлюзге жетті, бірақ соңғы модельге жетпеді;
  • команда логтарда генерацияның нақты қай жерде тоқтағанын тексермейді;
  • жоғары max_tokens тым қымбат запас қалдырады.

Тағы бір таза ұйымдастырушылық қате бар: көп адам клиенттегі қатені ғана тексереді, ал әр провайдердегі нақты тоқтау фактісін қарамайды. Ал бұл бір нәрсе емес. Бір провайдер генерацияны бірден үзеді, екіншісі ағымдағы буферді аяқтайды, үшіншісі тоқтатудың нақты статусын мүлде бермейді.

Егер сіздің қосымша мен модельдердің арасында бір ортақ шлюз болса, идентификаторлар тізбегін түгел сақтаңыз: клиент сұрауы, шлюздегі ID және провайдердегі ID. Содан кейін тоқтатуды интерфейс бойынша емес, токен логтары мен сұраудың өмір сүру уақыты бойынша салыстырыңыз. Әйтпесе экранда бәрі тәп-тәуір көрінеді, ал шот өсе береді.

Күнделікті сценарийден мысал

Модельдерді GPU-да іске қосыңыз
Егер сізге data residency мен төмен кідіріс керек болса, AI Router инфрақұрылымын таңдаңыз.

Пайдаланушы қолдау чат ашты, тариф шарттары туралы сұрақ қойды да, қосымшаны бірден жапты. Мұндай жағдай жиі болады: адамды біреу алаңдатты, қоңырау келді немесе ол жай ғана кейін оралғысы келді. Экранда мәтін ағыны енді көрінбейді, бірақ серверлік сұрау әлі тірі.

Фронтенд экранды жауып, оқиғаларға жазылуды алып тастады, ал бэкенд тізбек бойынша әрі қарай ештеңе хабарламады. Тоқтату сигналы модельге жетпеді, сондықтан ол стримдеуді сабырмен жалғастыра берді. Келесі 20–30 секундта ол тағы бірнеше абзац жазып тастады, бірақ оларды оқитын ешкім болмады.

Сырт көзге бәрі зиянсыз көрінді. Пайдаланушы шағымданбады, интерфейсте қате болған жоқ, чат жай ғана "жоғалып" кетті. Бірақ биллингте артық токендер жиналып жатты, ал командада сұрауды өңдеу уақыты мен воркер жүктемесі өсті.

Әдетте ақау осылай бұзылады: клиент кетіп қалды, ал бэкенд генерацияның бітуін әлі күтіп, чанктерді оқып, олар үшін қарапайым сәтті жауап сияқты төлеп тұр. Егер мұндай сессиялар күніне жүздеген болса, шығын сезіледі. Тіпті бір аяқталмаған диалогқа 300–500 артық токеннің өзі тез-ақ елеулі сомаға айналады.

Түзетуден кейін команда модельді өзгертпеді. Ол сұрау тізбегінің мінез-құлқын өзгертті:

  • фронтенд экран жабылған бойда тоқтату оқиғасын жібереді;
  • API-шлюз abort-ты клиентпен байланысты үзбей, сол сұраудың ішіне өткізеді;
  • бэкенд стрим оқуды аяқтап, тапсырманы ретрайсыз жабады;
  • метрикалар тоқтатылған жауаптар мен клиент кеткеннен кейінгі токендерді бөлек санайды.

Айырмашылық әдетте бірінші күннің өзінде көрінеді. Бұрын сұрау пайдаланушы бір секундта жоғалып кетсе де, табиғи соңына дейін жетіп қалатын. Түзетуден кейін ағын бірден тоқтайды да, модель жүздеген пайдасыз токенді "айтып бітіре" алмайды.

Продакт команда үшін бұл әсері жоғары, құны төмен түзетулердің бірі. UX-ті өзгертпейсіз, промпттарды қайта жазбайсыз және жаңа модель іздемейсіз. Сіз жай ғана ешкім көрмеген мәтін үшін төлеуді тоқтатасыз.

Релиз алдында жылдам тексеріс

Лимиттерді кілт бойынша ұстаңыз
Клиент кеткеннен кейін стрим ұзақ өмір сүретін жерде артық шығынды шектеңіз.

Релиз алдында кәдімгі сценарийді әдейі бұзатын тест керек. Ұзын жауапты іске қосыңыз, ортасына дейін күтіңіз де, вкладканы немесе экранды жабыңыз. Егер бәрі дұрыс бапталған болса, токен шығыны бірден дерлік тоқтайды, 20–30 секундтан кейін емес.

Тек интерфейске емес, бүкіл жүйеге қараңыз. Қосымша "тоқтатылды" деп көрсетуі мүмкін, бірақ сервер әлі қосылымды ұстап тұрса, шлюз әлі жауап бөліктерін қабылдап жатса, биллинг әлі токен санап жатуы мүмкін.

Шығаруға дейін бес нәрсені тексеріңіз:

  • вкладка жабылғаннан кейін сервер бірнеше секунд ішінде тоқтату сигналын алады;
  • токен саны мен сұрау бағасы ұзақ құйрықсыз, бірден дерлік тоқтайды;
  • бір сұраудың статусы қосымшада, шлюзде және есеп жүйесінде бірдей;
  • логта request_id, тоқтату себебі және нақты тоқтау уақыты сақталады;
  • тест баяу желіде де, ретрай кезінде де өтеді.

Қайта сұрауларды бөлек тексеріңіз. Жиі қате былай көрінеді: клиент стримді үзді, кітапхана оны уақытша ақау деп ойлап, сол сұрауды қайта жіберді. Пайдаланушы әлдеқашан кетіп қалды, ал жүйе екі рет төледі.

Бүкіл тізбек бойынша бір request_id-ті салыстырған пайдалы. Қосымшада сіз пайдаланушының экранды жапқан сәтін көресіз. Шлюзде — тоқтатуды. Биллингте — жүйе қанша токен есептен шығарғанын. Егер осы үш нүктенің арасында айырмашылық болса, релиз әлі дайын емес.

Егер сіз ортақ шлюз арқылы жұмыс істесеңіз, аудит-логты да тексеріңіз. Ол сұрау қай жерде керек уақыттан ұзақ өмір сүргенін тез көрсетеді: клиентте ме, сіздің серверде ме, әлде провайдер жағында ма.

Тағы бір қарапайым тест жасаңыз. Телефоннан нашар желіде ұзын генерацияны іске қосыңыз, қосымшаны фонға жіберіп, бір минуттан кейін қайтып келіңіз. Сонда жүйе нақты тоқтату мен қысқа байланыс үзілуін ажырата ала ма, соны білесіз.

Жақсы нәтиже қарапайым көрінеді: пайдаланушы кетті, генерация тоқтады, токендер енді есептелмейді, ал логтарда не болғаны және қашан болғаны анық жазылып тұр.

Кейін не енгізу керек

Түзетуден кейін жұмыс бітпейді. Қарапайым тексерістерді қоймасаңыз, артық токендер бір аптадан кейін қайта оралады: біреу таймаутты өзгертеді, біреу қымбатырақ модельді қосады, біреу экран жабылғаннан кейінгі фондық сұрауды тоқтатуды ұмытады.

Алдымен клиенттік сессиядан ұзақ өмір сүретін жауаптарға алерт қосыңыз. Егер пайдаланушы чатты 15 секунд бұрын жапса, ал генерация әлі жүріп жатса, бұл қазірдің өзінде тексеруге себеп. Мұндай алерттерді бір оқиғаға емес, сағаттық немесе күндік үлеске қарап жасаған дұрыс, әйтпесе команда шуға батып кетеді.

Бір панельге не жинау керек

Шашыраңқы графиктер көп көмектеспейді. Тоқтатулар бір жерде, таймауттар басқа жерде, ал модель бойынша шығын үшінші жерде тұрса, шот өсімінің себебі жоғалып кетеді.

Кемінде төрт метриканы қатар ұстаңыз:

  • клиент өзі қанша стримді үзді;
  • сервер таймаутпен қанша сұрауды тоқтатты;
  • клиент сессиясы үзілгеннен кейін қанша токен кетті;
  • қай модельдерде тоқтаудан кейін ең қымбат құйрық пайда болады.

Мұндай панельден тек артық шығынды ғана емес, оның қайдан шыққанын да көруге болады. Мысалы, қысқа жауаптарда ағыс аз, ал қымбат модельдегі ұзын промпттар пайдаланушы кеткеннен кейін де 20–30 секунд генерацияны жалғастырып жатады.

Келесі қадам — лимиттерді қайта қарау. Қымбат модельдер үшін max_tokens-ті қаттырақ шектеген дұрыс, ал ұзын промпттар үшін бөлек қатаң сервер таймаутын қойған дұрыс. Бұл запас кеңдігін аздап тарылтады, бірақ шотты жақсы қорғайды. Тәжірибеде жиі екі ереже жеткілікті: ұзын контекстті себепсіз ең қымбат модельге жібермеу және клиент жоғалып кеткенде стримді шексіз ұстамау.

Егер сізде бірнеше команда және модельдерге бірнеше маршрут болса, бақылауды шлюз деңгейіне шығару ыңғайлы. AI Router-да маршрутизацияны, аудит-логтарды және API кілті бойынша лимиттерді орталықтандырып ұстауға болады, бұны әр сервисте қайта құраудың қажеті жоқ. Бұл бір чат hosted-модельге бара жатқанда, екіншісі сыртқы провайдер арқылы өткенде, ал тоқтату мен шығынды есептеу ережелері ортақ қалуы керек болғанда әсіресе ыңғайлы.

Үлкен қайта жасауға кіріспей неден бастау керек

Бірден барлық өнімді қозғамаңыз. Продакшнде стримингі бар бір чаттан немесе бір ассистенттен бастаңыз да, екі нәрсені өлшеңіз: қазір клиент жоғалғаннан кейін қанша токен кетіп жатыр және жаңа тоқтату логикасынан кейін қанша кетеді.

Дейін және кейінгі салыстыру әсерді тез көрсетеді. Егер артық токендер кемінде 30–40% азайса, сізде қалған командаға жеткілікті дәлел бар. Егер өзгеріс аз болса, мәселе, сірә, тоқтату сигналының өзінде емес, сервер тізбегінде, ретрайларда немесе маршрутизацияда.

Осының бәрінің мәні өте практикалық. Пайдаланушы экранды жапты — генерация тоқтауы тиіс. Егер олай болмаса, жүйе ақша жұмсайды, метриканы бұрмалайды және әлі жауап күтіп отырғандарға кедергі жасайды. Бұл үзілісті неғұрлым ерте ұстасаңыз, шоттағы артық токендер соғұрлым аз болады.

Жиі қойылатын сұрақтар

Неге экранды жапқаннан кейін токендер бәрібір есептен шыға береді?

Өйткені жабылған экран әрдайым бүкіл тізбекті бірден үзбейді. Браузер немесе қосымша кетіп қалғанымен, сіздің серверіңіз бен модель провайдері сұрауды әлі ашық ұстап, токендерді стримдеуді жалғастырады. Егер abort соңына дейін LLM API-ға жетпесе, биллинг шыққан токендерді санай береді.

Тек SSE немесе WebSocket-ті жабу жеткілікті ме?

Жоқ. Егер сіз тек клиентке баратын стримді жапсаңыз, модель сервер немесе провайдер жағында мәтінді әрі қарай генерациялай беруі мүмкін. Клиенттік стримді де, модельге кететін бастапқы сұрауды да бір ортақ тоқтату сигналы арқылы тоқтатыңыз.

Клиенттің кеткенін, ал генерацияның әлі жүріп жатқанын қалай түсінуге болады?

Бір request_id-ті фронтенд, бэкенд, шлюз және модель шақыруы арқылы өткізіңіз. Сосын клиенттік қосылым үзілуінің уақытын, тоқтату себебін және провайдер жағындағы нақты тоқтау уақытын логқа жазыңыз. Егер осы сәттердің арасында құйрық болса, тоқтату толық жұмыс істемей тұр деген сөз.

Логқа қандай тоқтату себептерін жазған дұрыс?

Оларды бөлек ұстаңыз. Әдетте client_abort, network_close, server_timeout, upstream_timeout және manual_cancel жеткілікті. Сонда сұрауды алғаш кім тоқтатқанын және артық шығын қай жерде пайда болғанын бірден көресіз.

Тоқтату мен істен шығуды шатастырмас үшін таймауттарды қалай баптаған дұрыс?

Лимиттерді рөліне қарай бөліңіз. Клиенттік таймаут интерфейспен байланысқа жауап береді, модель таймауты провайдерден келетін жауап күту уақытын шектейді, ал жалпы дедлайн сұраудың тым ұзақ өмір сүруіне жол бермейді. Бұларды бір лимитке араластырсаңыз, команда кейін қай жері бұзылғанын ұзақ таласады.

Тоқтату жұмыс істеп тұрса да, `max_tokens`-ті шектеу керек пе?

Иә, көбіне қажет. Егер әдеттегі жауап 300–500 токеннің ішінде бітсе, max_tokens-ті 4000 деп жай ғана сақтық үшін қоя салмаңыз. Тоқтату қалып қойса, жоғары max_tokens бір тасталған стримді тез арада қымбат шотқа айналдырады.

Неге байланыс үзілгеннен кейін кейде екінші дәл сондай сұрау пайда болады?

Көбіне кітапхана қысқа үзілісті уақытша қате деп қабылдап, сол сұрауды қайта жібереді. Клиенттегі, шлюздегі және сервердегі ретрайларды тексеріңіз, әсіресе стриминг үшін. Егер пайдаланушы кетіп қалса, сұрауды қайталаудың қажеті жоқ.

Релиз алдында тоқтатуды қалай тез тексеруге болады?

Длинный стримті ашып, ортасына келгенде экранды жабыңыз. Сосын токендер, баға және сұраудың өмір сүру уақыты бірден өсуін тоқтатты ма, соны тексеріңіз. Егер интерфейс "тоқтатылды" деп көрсетіп тұрса, бірақ биллинг әлі 10–30 секунд жүрсе, релизді шығаруға әлі ерте.

Неге есептерде бәрі дұрыс сияқты көрінеді, ал пайдаланушы жауапты көрмейді?

Өйткені провайдердегі success пайдаланушы жауапты алды дегенді білдірмейді. Клиент одан бұрын кетіп қалған болуы мүмкін, ал сервер бәрібір ағынды соңына дейін оқып бітіреді. Апстримдегі сәттілікті клиент оқиғаларымен салыстырыңыз, әйтпесе метрикалар өнім ақша жоғалтып жатқан жерде бәрі сау деп көрсетеді.

Осындай сценарийлерде AI Router сияқты бірыңғай шлюз не береді?

Пайдалысы — тоқтату, лимиттер және аудитті бір қабатқа жинау. AI Router арқылы OpenAI-үйлесімді сұраулар жібере аласыз, ортақ лог жүргізе аласыз және бір request_id-ті бүкіл тізбекпен өткізе аласыз. Сонда тоқтату сигналы қай жерде жоғалғанын және артық токендер қай жерден басталғанын табу жеңілдейді.