Veliki jezični modeli (LLM) su svugdje, od svakodnevnih aplikacija do naprednih alata. Korištenje ih je jednostavno. Ali što ako trebate pokrenuti vlastiti model? Bilo da ste dobro prilagodili jedan ili se bavite podacima osjetljivima na privatnost, složenost se povećava. U ovom postu podijelit ćemo ono što smo naučili tijekom izgradnje vlastitog sustava zaključivanja LLM-a. Pokrivat ćemo skladištenje i ugradnju modela, dizajniranje arhitekture usluga i rješavanje stvarnih problema kao što su usmjeravanje, streaming i upravljanje mikroslužbama. Proces je uključivao izazove, ali na kraju smo izgradili pouzdan sustav i prikupili lekcije vrijedne dijeljenja. Uvod LLM-ovi pokreću širok raspon primjena - od chatbotova i agenata radnog toka do pametnih alata za automatizaciju. dok su generacija s povećanjem pretraživanja, pozivanje alata i protokoli s više agenata važni, oni djeluju na razini iznad osnovnog motora: temeljni LLM. Mnogi projekti ovise o vanjskim pružateljima usluga, kao što su , ili , što je dovoljno za većinu slučajeva korištenja. Ali za određene aplikacije, to brzo postaje problem. Što ako pružatelj prestaje? Što ako trebate potpunu kontrolu nad zakašnjenjem, cijenom ili radnim vremenom? Najvažnije – što ako vam je stalo do privatnosti i ne možete si priuštiti slanje korisničkih podataka trećoj strani? Otvori Blizanci antropološki Otvori Blizanci antropološki To je mjesto gdje samostalni hosting postaje ključan. Uređivanje predtreniranog ili fino prilagođenog modela pruža kontrolu, sigurnost i mogućnost prilagođavanja modela specifičnim poslovnim potrebama. Izgradnja takvog sustava ne zahtijeva veliki tim ili opsežne resurse. Izgradili smo ga s skromnim proračunom, malim timom i samo nekoliko čvorova. Ovo je ograničenje utjecalo na našu arhitektonsku odluku, zahtijevajući od nas da se usredotočimo na praktičnost i učinkovitost. Opći pregled To su ključne komponente koje čine kralježnicu sustava. Formati i kodiranje. Zajednički jezik u svim uslugama važan je.To znači dosljedne formate zahtjeva / odgovora, sheme generiranja parametara, strukture povijesti dijaloga i serijacija koja radi svugdje - od frontenda do backenda do modelskih vozača. Upravljanje višestrukim modelima, vrstama zahtjeva i prioritetima domaćina zahtijeva svjesne odluke o usmjeravanju. Objasnit ćemo kako se dolazni zahtjevi korisnika usmjeravaju kroz sustav – od početne točke ulaska do odgovarajućeg radničkog čvorišta – i kako se odgovori vraćaju natrag. Model skladištenje i ugradnja.Gdje su modeli žive, i kako su oni pripremljeni za proizvodnju? Razgovarat ćemo o ključnim testovima koje treba provesti, uključujući osiguravanje pouzdanosti modela. Kako znate da stvari rade?Pokažemo vam koje metrike pratimo, kako pratimo neuspjehe i koje sonde koristimo kako bismo osigurali zdravlje i pouzdanost sustava. Shema i kodiranje podataka Odabir prave sheme za prijenos podataka ključan je.Dijeljeni format u svim uslugama pojednostavljuje integraciju, smanjuje pogreške i poboljšava prilagodljivost. Zašto je dizajniranje sheme važno Ne postoji univerzalni standard za razmjenu podataka LLM. Mnogi pružatelji slijediti sheme slične dok drugi - kao ili Mnogi od tih pružatelja nude OpenAI-kompatibilne SDK-ove koji zadržavaju istu shemu, iako često s ograničenjima ili smanjenim skupovima značajki (npr. , Ostali projekti kao što su Cilj je ujediniti ove varijacije tako što će ih obložiti u sučelje kompatibilno s OpenAI-om. Otvorenost Claude Blizanci Anthropic OpenAI-kompatibilni SDK Gemini OpenAI sloj kompatibilnosti OpenRouter Otvorenost Claude Blizanci Anthropic OpenAI-kompatibilni SDK Gemini OpenAI sloj kompatibilnosti OpenRouter Držeći se jedne unaprijed definirane sheme pružatelja ima svoje prednosti: Dobivate dobro testiran, stabilan API. Možete se osloniti na postojeće SDK-ove i alate. Međutim, postoje i stvarni nedostaci: To stvara zaključavanje dobavljača, čime je teže podržati više pružatelja. To ograničava fleksibilnost za proširenje sheme s prilagođenim značajkama potrebnim za poslovne potrebe ili zahtjeve tima za znanost podataka. Vi ste izloženi prekidima promjena ili deprecijacija izvan vaše kontrole. Te sheme često nose nasljedne ograničenja koja ograničavaju kontrolu finog zrna. Kako bismo to riješili, odlučili smo definirati naše — shemu osmišljenu oko naših potreba, koju možemo potom mapirati u različite vanjske formate kada je to potrebno. own internal data model Dizajn unutarnjih shema Prije rješavanja izazova, definirajmo problem i opišimo naša očekivanja za rješenje: Jednostavna konverzija na formate koje zahtijevaju vanjski pružatelji usluga i obrnuto. Potpuna potpora za značajke specifične za naše poslovne i podatkovne znanstvene timove. Osigurati da je shema lako proširiva za buduće zahtjeve. Počeli smo pregledavanjem glavnih LLM shema kako bismo razumjeli kako pružatelji strukturiraju poruke, parametre i izlaze. Zajednički u većini sustava, uključujući: core domain entities Poruke (npr. prompt, povijest) Parametri generacije (npr. temperatura, top_p, beam_search) Pronašli smo određene parametre, kao što su: , ili , kao što je specifično za unutarnju konfiguraciju i poslovnu logiku pružatelja. Ovi elementi leže izvan osnovne domene LLM-a i nisu dio zajedničke sheme. Umjesto toga, tretiraju se kao opcionalna proširenja. Kad god se značajka postaje široko prihvaćena ili potrebna za širu interoperabilnost, mi procjenjujemo integraciju u osnovnu shemu. service_tier usage_metadata reasoning_mode Na visokoj razini, naša shema ulaza je strukturirana pomoću ovih ključnih komponenti: Model – Koristi se kao ključ za usmjeravanje, djeluje kao identifikator usmjeravanja, omogućujući sustavu usmjeravanje zahtjeva na odgovarajući radnički čvor. Parametri generacije – postavke osnovnog modela (npr. temperatura, top_p, max_tokens). Poruke – povijest razgovora i hitne naplate. Tools – definicije alata koje model može koristiti. To nas dovodi do sljedeće sheme, predstavljene u To ilustrira strukturu i namjeru dizajna, iako su neki detalji provedbe propušteni zbog jednostavnosti. Pitanje poput Pitanje poput class ChatCompletionRequest(BaseModel): model: str # Routing key to select the appropriate model or service messages: list[Message] # Prompt and dialogue history generation_parameters: GenerationParameters # Core generation settings tools: list[Tool] # Optional tool defenitions class GenerationParameters(BaseModel): temperature: float top_p: float max_tokens: int beam_search: BeamSearchParams # Optional, non-core fields specific to certain providers provider_extensions: dict[str, Any] = {} ... # Other parameters Namjerno smo premjestili generacijske parametre u zasebno polje umjesto da ih stavimo na razinu korijena. parametara (npr. temperatura, top-p, postavke modela) i Mnoge ekipe u našem ekosustavu pohranjuju ove konstantne parametre u vanjske konfiguracijske sustave, čineći to razdvajanje praktičnim i potrebnim. konstantno varijabilna Dodatno polje zove se Unutar Ovi parametri značajno variraju među različitim LLM pružateljima, validacija i tumačenje ovih polja je — komponenta koja zna kako komunicirati s određenim pružateljem modela.Na taj način izbjegavamo nepotrebno prohodno spajanje uzrokovano redundantnom validacijom podataka u više usluga. provider_extensions GenerationParameters delegated to the final module that handles model inference Kako bi se osigurala retroaktivna kompatibilnost, uvode se nove značajke izlazne sheme kao u shemi zahtjeva. Ta polja djeluju kao zastave značajki – korisnici ih moraju postaviti kako bi se odlučili za određena ponašanja. Ovaj pristup održava osnovnu shemu stabilnom dok omogućuje progresivnu evoluciju. Na primjer, tragovi razmatranja bit će uključeni u izlaz samo ako je odgovarajuće polje postavljeno u zahtjevu. explicit, optional fields These schemas are maintained in a shared Python library and used across services to ensure consistent request and response handling. Suradnja s trećim ponuditeljima Počeli smo opisivanjem načina na koji smo izgradili vlastitu platformu – pa zašto se brinuti o kompatibilnosti između vanjskih pružatelja usluga? Generacija sintetičkih podataka za prototipiranje i eksperimentiranje naših timova za znanost podataka. Opće zadaće u kojima neki vlasnički modeli bolje rade izvan kutije. Neosjetljivi slučajevi korištenja u kojima su privatnost, latentnost ili kontrola infrastrukture manje kritične. Ukupni protok komunikacije s vanjskim pružateljima usluga može se sažeti kako slijedi: Ovaj proces uključuje sljedeće korake: Posebna LLM-Gateway usluga odgovorna za komunikaciju s pružateljem usluga prima zahtjev korisnika u našem formatu sheme. Zahtjev se pretvara u oblik specifičan za pružatelja usluga, uključujući sve dodatke. Vanjski pružatelj obradi zahtjev i vrati odgovor. LLM-Gateway Service prima odgovor i vraća ga u našu standardiziranu shemu odgovora. Ovo je shema na visokoj razini koja odvaja neke pojedinačne mikroslužbe. Detalji o specifičnim komponentama i formatu odgovora na streaming bit će obuhvaćeni u sljedećim odjeljcima. Streaming format LLM odgovori se generiraju progresivno - token po tokenu - a zatim se agregiraju u Iz perspektive korisnika, bilo putem preglednika, mobilne aplikacije ili terminala, iskustvo mora ostati To zahtijeva transportni mehanizam koji podržava . chunks fluid and responsive low-latency, real-time streaming Postoje dvije glavne mogućnosti za postizanje toga: WebSockets: Kompletan dupleksni komunikacijski kanal koji omogućuje kontinuiranu dvosmjernu interakciju između klijenta i poslužitelja. Server-Sent Events (SSE): Jednosmjerni, HTTP-based streaming protokol koji se široko koristi za ažuriranje u realnom vremenu. Websocketovi Websocketovi Server-Sent događaji (SSE) Server-Sent događaji (SSE) Zašto SSE preko WebSockets? Iako su obje opcije izvedive, — osobito za OpenAI-kompatibilne API-je i slične sustave. To je zbog nekoliko praktičnih prednosti: SSE is the more commonly used solution for standard LLM inference Jednostavnost: SSE radi preko standardnog HTTP-a, ne zahtijeva posebne nadogradnje ili pregovore. Kompatibilnost: Radi nativno u svim glavnim preglednicima bez dodatnih knjižnica. Jednosmjerni protok: Većina LLM odgovora teče samo od poslužitelja do klijenta, što je u skladu s dizajnom SSE-a. Proxy-Friendliness: SSE igra dobro sa standardnom HTTP infrastrukturom, uključujući obrnute proxyje. Nadogradnje ili pregovori Zbog tih prednosti, . SSE is typically chosen for text-only, prompt-response streaming use cases Međutim, neki novi slučajevi korištenja zahtijevaju bogatiju, nisku latenciju, dvosmjernu komunikaciju - kao što su transkripcija u stvarnom vremenu ili interakcije govora i govora. rješavanje tih potreba koristeći (za server-to-server).Ovi protokoli su bolje prikladni za kontinuirani multimodalni ulaz i izlaz. Real-time API rješenja WebSockets Real-time API rješenja Budući da se naš sustav usredotočuje isključivo na Mi se držimo s za svoju jednostavnost, kompatibilnost i usklađenost s našim modelom streaming. text-based interactions SSE Odgovor Stream sadržaj With odabrana kao transportni sloj, sljedeći korak bio je definiranje Učinkoviti streaming zahtijeva više od samo sirovog teksta – mora pružiti dovoljnu količinu za potporu potrošačima u daljnjem tijeku, kao što su korisnički sučelja i alati za automatizaciju. SSE what structure, metadata, and context Metapodatci na razini glave. Osnovne identifikacijske informacije, kao što je ID zahtjeva. Temeljni ishod – žetoni ili nizovi generirani modelom – isporučuju se progresivno dok se sekvence (n) prenose natrag, dijelom po dijelom.Svaka generacija može se sastojati od više sekvencija (n = 2, n = 4) .Ove sekvence se generiraju neovisno i prenose paralelno, svaka podijeljena u svoj vlastiti skup progresivnih dijelova. Upotreba i metapodatci na razini tokena. Ovo uključuje broj generiranih tokena, podatke o vremenu i opcionalnu dijagnostiku kao što su logprobe ili tragovi razmatranja. Ovo se može koristiti za obračunavanje, debugiranje ili evaluaciju modela. Nakon što smo definirali strukturu protumačenog odgovora, također smo razmotrili nekoliko nefunkcionalnih zahtjeva bitnih za pouzdanost i buduću evoluciju. Naš stream dizajn namjerava biti: Strukturirano – jasno razlikuje vrste sadržaja i granice događaja. — capable of carrying optional metadata without breaking existing clients. Extensible Robustno – otporno na nepravilno oblikovane, odgođene ili djelomične podatke. U mnogim slučajevima, kao što su ili - višestruke sekvence (dodatke) generiraju se paralelno kao dio zahtjeva za jednu generaciju. side-by-side comparison diverse sampling Najopsežniji format za streaming odgovore definiran je u Prema specifikaciji, jedna generacija može uključivati više sekvencija u Arheološki: OpenAI API referencija choices OpenAI API referencija Odluke Array Može sadržavati više od jednog elementa ako je n veći od 1. choices Array Može sadržavati više od jednog elementa ako je n veći od 1. Iako, u praksi, pojedinačni komadi obično sadrže samo jedan delta, format omogućuje višestruke ažuriranja sekvence po komadiću.Važno je uzeti u obzir ovo, budući da bi buduće ažuriranja mogle šire iskoristiti ovu mogućnost. Namijenjen je za potporu ovoj strukturi. official Python SDK official Python SDK Izabrali smo slijediti istu strukturu kako bismo osigurali kompatibilnost s širokim rasponom potencijalnih značajki.Diagram ispod ilustrira primjer iz naše implementacije, gdje se jedna generacija sastoji od tri sekvence, prenesene u šest komada tijekom vremena: Ovaj dio označava početak cijele generacije. ne sadrži nikakav stvarni sadržaj, ali uključuje zajedničke metapodatke, kao što su ID generacije, vremenski žig i uloga (npr. asistent, itd.). Chunk 2 – Sequence Start (Green & Purple). Dvije sekvence počinju emitirati paralelno. svaka je označena jedinstvenim identifikatorom kako bi se razlikovala od drugih. The third sequence starts (blue), while the first two sequences (green and purple) stream incremental content via delta events. Chunk 3 — Sequence Start (Blue) & Sequence Delta. The green and blue sequences continue streaming deltas. The purple sequence finishes — this includes a structured finish_reason (like stop, length, etc.). Chunk 4 — Midstream Updates & Finish (Purple). Članak 5 – Preostala sekvenca završava. i zelene i plave sekvence su završene. Životni ciklus svake sekvence sada je potpuno zatvoren između svojih početnih i završnih oznaka. This chunk closes the generation and may include global usage statistics, final token counts, latency info, or other diagnostics. Chunk 6 — Generation Finish. Kao što možete vidjeti, kako bi struja bila robusna i lakša za analiziranje, odlučili smo , umjesto da se oslanja na implicitne mehanizme kao što su null provjere, EOF-ovi ili čarobni žetoni. Ovaj strukturirani pristup pojednostavljuje analizu u daljnjem tijeku, osobito u okruženjima u kojima se paralelno prenosi više završetaka, a također poboljšava debugabilnost i izolaciju grešaka tijekom razvoja i inspekcije vremena rada. explicitly signal Start and Finish events for both the overall generation and each individual sequence Moreover, we introduce an additional chunk that carries structured information about failures. Some errors — such as malformed requests or authorization issues — can be surfaced directly via standard HTTP response codes. However, if an error occurs , imamo dvije opcije: ili naglo prekidanje HTTP toka ili emitiranje dobro formiranog događaja pogreške SSE. Odabrali smo potonji. naglo zatvaranje veze otežava klijentima da razlikuju između mrežnih problema i stvarnih neuspjeha modela / usluge. Korištenjem namjenskog pogrešnog dijela omogućujemo pouzdanije otkrivanje i širenje problema tijekom streaming-a. Error during the generation process Backend usluge i tok zahtjeva At the center of the system is a single entrypoint: Rješava osnovne probleme kao što su autentikacija, praćenje korištenja i provedba kvota, oblikovanje zahtjeva i usmjeravanje na temelju određenog modela. Iako može izgledati kao da Gateway nosi puno odgovornosti, svaki zadatak je namjerno jednostavan i modularan. Za vanjske pružatelje usluga, prilagođava zahtjeve svojim API-jima i mapira odgovore natrag u ujedinjen format. Za samohostovane modele, zahtjevi se usmjeravaju izravno na unutarnje sustave koristeći našu vlastitu ujedinjenu shemu. LLM-Gateway Self-Hosted Models As mentioned earlier, is well-suited for streaming responses to end users, but it’s not a practical choice for . When a request arrives, it must be routed to a suitable worker node for model inference, and the result streamed back. While some systems handle this using chained HTTP proxies and header-based routing, in our experience, this approach becomes difficult to manage and evolve as the logic grows in complexity. Server-Sent Events (SSE) internal backend communication Our internal infrastructure needs to support: Prioritetno planiranje - Zahtjevi mogu imati različite razine hitnosti (npr. interaktivni i serijski), a zadaci s visokim prioritetom moraju se rješavati prvo. Hardware-aware usmjeravanje - Određeni čvorovi rade na veće performanse GPU-a i treba dati prednost; drugi služe kao preopterećenja kapaciteta. Svaki radnik je konfiguriran tako da podržava samo podskup modela, na temelju kompatibilnosti hardvera i ograničenja resursa. Kako bi se riješili ti zahtjevi, koristimo to decouple task routing from result delivery. This design provides better flexibility and resilience under varying load and routing conditions. We use for this purpose, though other brokers could also be viable depending on your latency, throughput, and operational preferences. RabbitMQ was a natural fit given its maturity and alignment with our existing tooling. message broker RabbitMQ RabbitMQ RabbitMQ Sada ćemo detaljnije pogledati kako se ovaj sustav primjenjuje u praksi: Koristimo , omogućujući nam usmjeravanje zahtjeva na temelju kompatibilnosti modela i sposobnosti čvorova. dedicated queues per model Usluga LLM-Gateway (predstavljena kao korisnik) pokreće HTTP zahtjev za pokretanje zadatka za generiranje teksta. Zahtjev rješava Rasporednik, koji odabire odgovarajući red (označen zeleno na slici) na temelju traženog modela i priloži mu poruku. Odgovarajući Inference Worker (samo jedan radnik je prikazan za jednostavnost, ali ima ih mnogo) pretplatnik u red prikuplja zadatak i započinje obradu. The worker streams the response chunk-by-chunk into the , to which the . Streaming the Response. Response Queue Scheduler replica handling the request is subscribed The Scheduler listens to the reply queue and receives the response chunks as they arrive. Receiving Response Chunks. The chunks are converted to SSE format and streamed to the client. SSE Streaming. To handle , izbjegavamo preterivanje brokera poruka: large payloads Instead of embedding large input or output data directly in the task, we upload it to an . external S3-compatible store Referenca (kao što je URL ili ID resursa) uključena je u metapodatke zadatka, a radnik preuzima stvarni sadržaj kada je to potrebno. Primjena dizajna s RabbitMQ-om Kada je riječ o Svaki is a regular RabbitMQ , dedicated to handling a single model type. We require Što se može postići korištenjem . In this setup, messages with higher priority values are delivered and processed before lower priority ones. For , gdje bi poruke trebale biti usmjerene na najuspješnije dostupne čvorove, Potrošači s višim prioritetom primaju poruke dok su aktivni; potrošači s nižim prioritetom primaju poruke samo kada su poruke s višim prioritetom blokirane ili nedostupne. routing and publishing messages Request Queue Ograda priority-aware scheduling message priorities hardware-aware routing Potrošački prioriteti Ograda message priorities Potrošački prioriteti Ako je gubitak poruke neprihvatljiv, sljedeće mora biti na mjestu: Izdavač potvrđuje da je posrednik primio i pohranio poruku. and so data survives restarts. Durable queues persistent messages Oni također podržavaju pojednostavljene poruke i potrošačke prioritete od RabbitMQ 4.0. Publisher confirms Publisher confirms Quorum queues Kvorum čeka simplified message and consumer priorities as of RabbitMQ 4.0 So far, we’ve covered how tasks are published — but how is the Prvi korak je razumjeti kako Rad u RabbitMQ. posrednik podržava koncept nazvan , koji su vezani za jednu vezu i automatski se brišu kada se ta veza zatvori. streamed response temporary queues exclusive queues exclusive queues exclusive queues Mi stvaramo , ensuring it’s automatically cleaned up when the replica shuts down. However, this introduces a challenge: while each service replica has a single RabbitMQ queue, it must handle . one exclusive queue per Scheduler service replica many requests in parallel Da bismo to riješili, tretiramo RabbitMQ red kao , routing responses to the correct Scheduler replica. Each user request is assigned a , which is included in every response chunk. Inside the , we maintain an additional with short-lived in-memory queues — one per active request. Incoming chunks are matched to these queues based on the identifier and forwarded accordingly. These in-memory queues are discarded once the request completes, while the RabbitMQ queue persists for the lifetime of the service replica. transport layer unique identifier Scheduler in-memory routing layer Shematski to izgleda kako slijedi: A central dispatcher within the Scheduler dispatches chunks to the appropriate in-memory queue, each managed by a dedicated handler. Handlers then stream the chunks to users using SSE-protocol. Inferencija There are several mature frameworks available for efficient LLM inference, such as and Ti sustavi su dizajnirani za and generate response tokens in real time, often with features like continuous batching and GPU memory optimization. In our setup, we use kao motor za zaključivanje jezgra, uz nekoliko prilagođenih izmjena: Sljedeći Sljedeći process multiple sequences in parallel vLLM Sljedeći Sljedeći Sljedeći SGLANG — to better suit our generation logic and support structured constraints. Custom beam search implementation Podrška strukturiranim shemama izlaza – omogućuje modelima da vraćaju izlaze u skladu s formatima specifičnim za tvrtku. Kroz iskustvo smo naučili da čak i manja ažuriranja knjižnica mogu — bilo u kvaliteti ispuštanja, determinizmu ili uzajamnom ponašanju. Zbog toga smo uspostavili robusnu testnu cijev: significantly alter model behavior Testiranje stresa kako bi se otkrili problemi istovremenosti, curenje pamćenja ili regresije stabilnosti. Determinizam testiranja kako bi se osigurali dosljedni rezultati za fiksna sjemena i skupove parametara. to cover a wide range of generation settings, without going overboard. Parameter grid testing Skladištenje i razmještanje Većina modernih sustava djeluje u — either in the cloud or within Kubernetes (K8s). While this setup works well for typical backend services, it introduces challenges around LLM modeli mogu biti , and baking model weights directly into Docker images — quickly becomes problematic: containerized environments model weight storage tens or even hundreds of gigabytes in size Usporene izgradnje – čak i s višestupanjskim izgradnjama i cachingom, prijenos velikih modelskih datoteka tijekom faze izgradnje može dramatično povećati vrijeme CI-ja. Sporo postavljanje – svako postavljanje zahtijeva povlačenje masivnih slika, što može potrajati nekoliko minuta i uzrokovati prekide ili kašnjenja. Neefikasnost resursa – ni registri Docker ni čvorovi Kubernetes nisu optimizirani za rukovanje iznimno velikim slikama, što rezultira povećanom upotrebom skladišta i opterećenjem širine pojasa. Da bismo to riješili, razdvojili smo from the Docker image lifecycle. Our models are stored in an , and fetched just before inference service startup. To improve startup time and avoid redundant downloads, we also use Slijedeći članakKako izračunati težinu modela na svakom čvoru model storage external S3-compatible object storage Lokalni uporni volumeni (PVC) Lokalni uporni volumeni (PVC) Lokalni uporni volumeni (PVC) promatranja Takav sustav – izgrađen na - zahtijeva osigurati pouzdanost i učinkovitost na razini. streaming, message queues, and real-time token generation robust observability Osim standardnih mjerila na razini usluge (CPU, memorija, stopa pogreške itd.), smatrali smo da je važno pratiti sljedeće: — monitoring the number of pending messages, current queue size, and number of active consumers helps detect task distribution bottlenecks and imbalances in worker utilization. Queue depth, message backlog, and consumer count Token/chunk prolaz – praćenje broja tokena ili čunjeva odgovora generiranih po sekundi pomaže identificirati latenciju ili regresije prolaza. Distributed tracking – kako bi se utvrdilo gdje zahtjevi ne uspiju ili stagniraju preko komponenata (gateway, posrednik, radnici itd.). Zdravstvene provjere inferencijskog motora – budući da se procesi zaključivanja mogu srušiti u rijetkim uvjetima (npr. loši unos ili ekstremne vrijednosti parametara), proaktivno praćenje vitalnosti i spremnosti je ključno. Distribuirani tracer Distribuirani tracer Further Improvements While our system is production-ready, there are still important challenges and opportunities for optimization: Korištenje distribuiranog KV-cachea za povećanje performansi zaključivanja. Podržava otkazivanje zahtjeva za očuvanje računala kada izlazi više nisu potrebni. Creating a for data science teams. simple model delivery pipeline Conclusion While building a reliable and provider-independent LLM serving system can seem complex at first, it doesn’t require reinventing the wheel. Each component — streaming via SSE, task distribution through message brokers, and inference handled by runtimes like vLLM — serves a clear purpose and is grounded in existing, well-supported tools. With the right structure in place, it’s possible to create a maintainable and adaptable setup that meets production requirements without unnecessary complexity. In the next post, we’ll explore more advanced topics such as distributed KV-caching, handling multiple models across replicas, and deployment workflows suited to ML-oriented teams. Autori Točka , Stanislav Šimovolos Stanislav Shimovolos Stanislav Šimovolos Tochka , Maxim Afanasyev Maxim Afanasyev Maksim Afanasjev Priznanja Radovi izvršeni u Toskani Dmitrij Kryukov Dmitrij Kryukov Dmitrij Kryukov