Miért érdekel ez téged?
Egy production AI alkalmazás tipikusan nem csak egy backend és egy LLM API. Ami a demóban két doboz és egy nyíl, az élesben egy tucatnyi együttműködő komponens, amelyeknek akkor is helyt kell állniuk, ha a provider lelassul, egy tool eldől, vagy egyszerre ezer kérés érkezik.
Gondolj rá úgy, mint egy étteremre. A demó az, amikor otthon főzöl egy adag ételt egy barátodnak: minden kézből megy, nincs rendszer, és ha elrontod, újrakezded. A production rendszer egy működő étterem: van étkező (frontend), pincérek (API), konyha (orchestrator), beszállítók (model és tool gateway), raktár (adatbázisok) és egészségügyi ellenőrzés (policy, audit). Ha bármelyik láncszem kiesik csúcsidőben, a vendég ezt azonnal megérzi — és nem jön vissza.
Ez a réteg az, ahol a DevOps- és szoftverfejlesztési tudásod (lásd 18. Szoftverfejlesztés) közvetlenül kamatozik. A senior AI engineert épp az különbözteti meg a lelkes kezdőtől, hogy nem csak jó promptot ír, hanem meg tud tervezni egy olyan rendszert, amelyre rá lehet bízni valós felhasználókat és valós pénzt.
Konkrétan miért számít ez neked? Mert a demó és a production közötti szakadék általában nem hetekben, hanem hónapokban mérhető munka — és a legtöbb csapat alábecsüli. Egy chatbot-prototípus egy hétvége alatt összerakható; ugyanaz a chatbot úgy, hogy 99,9%-os rendelkezésre állással, per-tenant költségkorláttal, auditálható döntésekkel és graceful degradationnel fut, jellemzően egy több hónapos, több emberes projekt. Ha érted a komponenseket és a köztük lévő függőségeket, akkor előre látod ezt a munkát, ahelyett hogy egyesével, éles incidensek árán fedeznéd fel.
Fő komponensek
Mielőtt a listát végigvennénk, érdemes fejben tartani, hogyan folyik keresztül egy kérés a rendszeren. A cél nem az, hogy minden alkalmazásba mind a tizennyolc komponenst beépítsd — hanem hogy tudd, melyik mit old meg, és tudatosan döntsd el, mire van szükséged. Egy egyszerű chat-alkalmazás megél négy-öt komponenssel; egy hosszú futású, tranzakciós agent-platform mindet igényli.
[Frontend / Streaming UI]
│ (SSE / WebSocket)
▼
[Application API] ──► [Policy engine] (jogosultság, input-szabályok)
│
▼
[Agent orchestrator] ──► [Queue] ──► [Workflow engine] (hosszú futású feladatok)
│
┌────┼─────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
[Model [Tool [Memory [Vector / [Sandbox]
gateway] gateway] service] search index]
│ │ │ │
▼ ▼ ▼ ▼
[LLM [külső [State store / [Object
providerek] toolok/API-k] Relational DB] storage]
Mindent átfog: [Tracing / Observability] · [Secrets / Identity] · [Audit log] · [Eval service]
A vízszintes rétegek a kérés útját mutatják, a kereszttartó komponensek (tracing, secrets, audit, eval) pedig mindenre ráépülnek. Nézzük végig, mit csinál pontosan mindegyik.
A kérés útja komponensekre bontva
Mielőtt a definíciókba merülnénk, kövessünk végig egy konkrét kérést, hogy a komponensek ne absztrakt dobozok maradjanak. Tegyük fel, hogy egy felhasználó beírja: „Foglald össze a tavalyi Q3 pénzügyi jelentést, és küldd el a csapatnak." A frontend elküldi a kérést az API-nak SSE fölött. Az API authentikál (ki ez a felhasználó, mely tenanthoz tartozik), majd a policy engine ellenőrzi: van-e joga ehhez a dokumentumhoz, és az „email küldése" tool engedélyezett-e neki. Az orchestrator elindítja az agent loopot: először a vector indexen keres rá a Q3 jelentés chunkjaira, a model gateway-n át összefoglaltatja a modellel, majd a tool gateway-n keresztül meghívná az email-toolt — amely emberi jóváhagyást kér, mert pénzügyi adat megy kifelé. Közben minden lépés trace-elődik, a tokenhasználat logolódik, a döntés bekerül az audit logba. Ez a séta megmutatja: egyetlen, ártatlannak tűnő mondat is átfut a rendszer szinte minden komponensén.
- Frontend és streaming UI A felhasználói felület, amely nem egyben, hanem tokenről tokenre jeleníti meg a választ (Server-Sent Events vagy WebSocket felett). AI-nál ez nem luxus: a modell lassú — egy hosszabb válasz time-to-first-token értéke tipikusan 0,5-2 másodperc, a teljes válasz akár 10-30 másodperc is lehet —, így a streaming és a progress indication tartja a felhasználót türelemben. Ha egyben, betöltő ikonnal várakoztatnád 20 másodpercig, a felhasználók fele elhagyná az oldalt. Az UX-oldalról ezt a 19. Product/UX fejezet fejti ki bővebben.
- Application API A rendszer nyilvános belépési pontja: authentikál, validálja a bemenetet, kezeli a sessiont, és továbbítja a kérést az orchestratornak. Ez a „pincér", aki felveszi a rendelést és tudja, kihez tartozik — de maga nem főz. Tipikusan FastAPI vagy hasonló async framework, mert a legtöbb ideje amúgy is I/O-várakozással telik (a modell válaszára vár). Ne tegyél ide üzleti logikát vagy hosszú műveletet: az API dolga a fogadás és a továbbítás, nem a feldolgozás.
- Agent orchestrator Az agy, amely levezényli az agent loopot: eldönti a következő lépést, hív modellt vagy toolt, értékeli az eredményt, frissíti az állapotot. Ő tudja, hol tart a feladat, és mikor kell leállni. Egyszerű esetben ez néhány sor kód (egy while ciklus tool callinggal); komplex esetben egy dedikált agent-framework (lásd 5. Agentek). Fontos design-döntés: az orchestrator állapotát ne csak a memóriában tartsd, mert ha a process újraindul, elveszik — ezt a workflow engine és a state store oldja meg.
- Model gateway Központi kapu minden LLM-hívás elé: itt fut össze a provider-választás, az auth, a rate limiting, a retry, a fallback és a költségkontroll. Annyira fontos komponens, hogy külön szekciót kap alább — ez az egyik legjellemzőbb dolog, amit egy production rendszer tartalmaz, egy demó pedig nem. Ha egyetlen komponenst építesz meg elsőként a demó után, ez legyen az.
- Tool gateway A model gateway megfelelője a toolok felé: egységes réteg, amelyen keresztül az agent külső API-kat, adatbázisokat és MCP-szervereket ér el. Itt kényszeríthető ki a tool allowlist, a per-user jogosultság, az argumentum-policy és a timeout — vagyis hogy az agent ne kaphasson nagyobb jogot, mint amennyi feltétlenül kell (lásd 15. AI Security). Konkrét példa: a „töröld a rekordot" tool csak admin szerepű felhasználó kontextusában legyen elérhető, függetlenül attól, hogy az agent „úgy dönt", hogy meghívná. A tool engineering részleteit a 7. Tool engineering fejezet adja.
- Workflow engine A hosszú futású, több lépéses folyamatok megbízható végrehajtója: checkpoint, resumability, retry policy, compensation. Ha egy folyamat félúton elhasal, ne kelljen elölről kezdeni. A durable execution részleteit a 9. State és memory fejezet tárgyalja — itt az a lényeg, hogy a workflow engine egy önálló infrastruktúra-komponens (pl. Temporal-szerű). Gondolj egy 15 lépéses agent-feladatra, ami órákig fut: ha a 12. lépésnél újraindul a worker, a workflow engine a checkpointból folytat, nem az elejéről — ezzel a már elköltött modelhívások pénze sem vész el.
- Queue Üzenetsor, amely szétkapcsolja a kérés fogadását a feldolgozásától. A lassú LLM- és tool-hívásokat nem szinkron várakoztatod, hanem betolod egy sorba, és egy worker dolgozza fel. Olyan, mint a postai csomagfeldolgozó szalag: nem a pultnál csomagolnak, a felvétel és a feldolgozás elválik. Ez adja a rendszer terhelhetőségét és a backpressure kezelését: egy forgalmi csúcsban a sor felduzzad, de a rendszer nem esik össze — csak lassabban válaszol.
- State store Gyors, gyakran kulcs-érték alapú tároló (tipikusan Redis) a session-állapotnak, a working memorynak, a distributed lockoknak és a rate-limit számlálóknak. Ez a rendszer „rövid távú memóriája": mikroszekundumos elérés, de nem az igazság végső forrása — ha elveszik, a rendszernek túl kell élnie. Tipikus hiba ide tenni olyan adatot, aminek tartósan meg kell maradnia (pl. számlázási tétel); az a relational database dolga.
- Relational database A tranzakciós igazság forrása (tipikusan PostgreSQL): felhasználók, jogosultságok, számlázás, üzleti entitások, workflow-állapot. Amit konzisztensen, ACID-garanciákkal kell tárolni, az ide kerül — nem az LLM „emlékezetébe". Az LLM ugyanis nemdeterminisztikus és hallucinálhat; egy pénzügyi egyenleget sosem bízol rá, hogy „emlékezzen" rá, azt lekérdezed a DB-ből, és beadod neki kontextusként.
- Object storage Nagy, nem strukturált fájlok tárolója (S3-szerű): feltöltött dokumentumok, képek, audiofájlok, generált artifactok, trace-exportok. Olcsó és skálázható a bájtok tömegéhez — nagyságrendileg havi néhány cent gigabájtonként —, de nem keresel benne, csak tárolsz. A keresést a vector/search index adja; az object storage tartja a nyers bájtokat, az index a jelentést.
- Vector/search index A RAG motorja: dense (vektor) és sparse (BM25) keresés, metadata-szűréssel. Ide indexeled a dokumentumok chunkjait, hogy jelentés alapján visszakereshesd őket. Egy 50 oldalas PDF tipikusan 30-40 chunkra bomlik; egy közepes vállalati tudásbázis akár több millió chunkot is tartalmazhat. Lehet dedikált vector database vagy PostgreSQL + pgvector — a részleteket a 4. RAG fejezet adja.
- Memory service A tartós agent-memória kezelője: mit jegyezzen meg, mit felejtsen el, hogyan kérje vissza, hogyan verziózza, és hogyan tartsa szét a tenantokat. Nem ugyanaz, mint a nyers vector index — ez a memória logikai rétege (working, episodic, semantic, procedural), amelyet a 9. State és memory részletez. Kritikus, hogy a memória tenant-izolált legyen: egy ügyfél agentje soha ne „emlékezzen" egy másik ügyfél adatára — ez egyszerre adatvédelmi és security kérdés.
- Policy engine A modellen kívül kikényszerített szabályok motorja: ki mit tehet, mely tooloknál kell emberi jóváhagyás, milyen tranzakciós limitek élnek. Kulcsfontosságú elv, hogy a system prompt nem biztonsági kontroll — a valódi szabályokat itt, determinisztikus kódban érvényesíted, nem a modell jóindulatára bízva. Ha azt írod a promptba, hogy „ne utalj át 1000 eurónál többet", egy ügyes prompt injectionnel ez megkerülhető; ha a policy engine-ben, kódban tiltod, akkor nem.
- Sandbox Izolált végrehajtási környezet a modell által írt kódnak: CPU-, memória- és időlimit, hálózati egress control, secret isolation, teljes execution trace. Ha az agent kódot futtat, azt sosem a saját processzedben teszed — olyan ez, mint a laboratóriumi bukótér: bent történhet a robbanás, kint nem. A sandbox tipikusan egy eldobható konténer vagy microVM, amely a futás után teljesen megsemmisül, így egy rosszindulatú vagy hibás kód sem tud kárt tenni a rendszerben.
- Eval service A minőségmérés infrastruktúrája: golden datasetek, graderek, offline regression és online (shadow, canary) eval. Nem egyszeri szkript, hanem folyamatosan futó szolgáltatás, amely CI-ben kapuként és production trace-eken mintavételezve is működik. Ez a fejlesztés motorja (lásd 11. Evals). Enélkül minden promptmódosítás vagy modellváltás vakrepülés: nem tudod, javítottál-e vagy rontottál.
- Tracing és observability Az a réteg, amely láthatóvá teszi, mi történik a fekete dobozban: minden model call, retrieval, tool call, retry, tokenhasználat és költség. AI-nál egyetlen „request duration" metrika használhatatlanul kevés — a teljes trace kell, mert egy 12 másodperces kérésnél tudnod kell, hogy azt egy lassú retrieval, három retry vagy a modell maga okozta-e. Ezt önálló fejezet, a 14. Observability tárgyalja.
- Secrets és identity A titkok (API-kulcsok, tokenek) és az identitás központi kezelése. Provider-kulcsok soha nem szórva a kódban, hanem secret brokerből; a felhasználói identitás pedig scoped tokenként terjed végig a rendszeren, hogy minden tool a helyes auth contextben fusson (OAuth/OIDC). Ha egy kulcs kiszivárog egy Git-repóból, az nem elméleti kockázat: automata botok percek alatt megtalálják és lehúzzák a kereted.
- Audit log Megváltoztathatatlan napló arról, ki mit kért, milyen döntés született, és milyen műveletet hajtott végre a rendszer. Nem a debug-loggal azonos: ez a jogi és compliance bizonyíték. Egy pénzügyi vagy egészségügyi AI-rendszernél nem opció — utólag rekonstruálhatónak kell lennie minden lényeges lépésnek. Append-only, ideálisan write-once tárolón, hogy még egy kompromittált admin se tudja utólag átírni a nyomokat.
Miből mennyi kell? Az érettségi szintek
A komponensek nem egyszerre, hanem érettségi szintekben kerülnek be. Hasznos, ha van egy mentális térképed arról, melyik szinten mi az elvárt minimum — így nem építesz túl korán platformot, de nem is maradsz alul, amikor már valós felhasználóid vannak.
| Szint | Tipikus komponensek | Mikor elég ennyi? |
|---|---|---|
| Prototípus | Frontend + API + közvetlen provider-hívás | Belső demó, koncepcióbizonyítás, néhány felhasználó |
| Korai production | + Model gateway, relational DB, state store, tracing | Első valós felhasználók, egyetlen tenant, kontrollált terhelés |
| Skálázódó termék | + Queue, workflow engine, vector index, policy engine, eval service | Több tenant, tranzakciós műveletek, hosszú futású feladatok |
| Vállalati / szabályozott | + Tool gateway, sandbox, memory service, audit log, secrets/identity, regional routing | Compliance, adatrezidencia, kód-execution, magas rendelkezésre állás |
Amit ebből érdemes elvinni: minden szint egy konkrét fájdalomra válasz, nem önmagáért való. A queue akkor jön, amikor a szinkron várakozás elkezd timeoutolni; a policy engine akkor, amikor először bíznál valós műveletet az agentre; az audit log akkor, amikor a compliance vagy a jog megköveteli a rekonstruálhatóságot.
Gyakori hibák a komponensek elhelyezésében
- Az LLM-et használni adatbázis helyett Tranzakciós igazságot (egyenleg, jogosultság, számla) sosem az LLM „memóriájára" bízol. A modell nemdeterminisztikus és hallucinál — a strukturált igazság a relational database dolga, a modell csak olvassa és értelmezi.
- Üzleti logikát tenni az API-rétegbe Az API a fogadás és továbbítás helye. Ha hosszú vagy összetett műveletet raksz bele, a rendszer nem skálázódik és nem tesztelhető rendesen. Az orchestrator és a workflow engine a logika helye.
- Szabályokat a system promptba írni „Sose csinálj X-et" a promptban nem kontroll, hanem javaslat, amit egy prompt injection felülír. A kikényszerített szabály a policy engine-be és a tool gateway-be tartozik, determinisztikus kódként.
- Szinkron feldolgozni a lassú munkát Ha egy több perces agent-feladatot szinkron, HTTP-kérésen belül próbálsz kiszolgálni, a kapcsolat timeoutol és a rendszer eldől terhelés alatt. Az ilyet queue-ba és workerbe kell tenni.
Model gateway
A model gateway a legkonkrétabb, leginkább implementálható komponens ebben a fejezetben — érdemes mélyebben megérteni. Egy vékony réteg, amelyen keresztül minden LLM-hívás megy: az alkalmazáskódod nem közvetlenül a provider SDK-ját hívja, hanem a saját gateway-edet. Ez ugyanaz az elv, mint egy API gateway vagy egy reverse proxy a hagyományos backendekben — egy központi kapu, ahol egy helyen kikényszerítesz mindent, ami minden hívásra igaz.
Miért éri meg ezt megépíteni? Mert enélkül a provider-logika szétszóródik a kódbázisban: minden helyen külön retry, külön kulcskezelés, külön költségszámítás. A gateway-jel egy helyre kerül a szabályozás — és ha holnap providert váltasz, egyetlen komponenst írsz át, nem húszat.
Az ábra a gateway belső döntési útját mutatja: minden bejövő hívás átmegy ugyanazon a szűrősoron — budget, allowlist, routing, redaction —, mielőtt kimenne a providerhez, és minden kimenő válasz naplózódik. Nézzük végig, mit old meg pontosan ez a réteg.
- Provider routing A gateway dönti el, melyik provider és melyik modell kapja az adott kérést — feladat, költség, régió vagy terheltség alapján. Így az alkalmazáskód „adj egy összefoglalót" absztrakcióban gondolkodhat, a konkrét modellválasztás pedig konfiguráció kérdése marad, nem szétszórt kódé. Tipikus routing-szabály: az egyszerű osztályozó feladatok mennek egy olcsó, kis modellhez, a komplex reasoning egy nagyobbhoz — így a költséged töredékére csökkenhet a naiv „mindent a legnagyobb modellel" megoldáshoz képest.
- Auth A provider-kulcsok kezelése egy helyen: a gateway veszi ki őket a secret brokerből, forgatja őket, és sosem engedi, hogy az alkalmazáskód közvetlenül lássa őket. Egy kompromittált kulcsot így egy helyen cserélsz, nem vadászod végig a repókat. Ráadásul több kulcsot is kezelhet párhuzamosan (key rotation), hogy egy csere ne okozzon leállást.
- Quota Felhasználónkénti, tenantonkénti vagy csapatonkénti kvóta: hány kérést vagy mennyi tokent használhat el egy adott szereplő egy időszakban. Ez véd a „egy ügyfél elviszi az egész keretet" helyzet ellen, és alapja a fair használatnak és a költségallokációnak. Például: egy free-tier felhasználó napi 50 kérést kap, egy fizetős korlátlant — ezt a gateway kényszeríti ki, nem az UI.
- Rate limiting A kimenő kérések ütemezése a provider percenkénti kérés- és token-limitjeihez igazítva. A gateway sorba állítja és lassítja a forgalmat, hogy ne fusson bele 429-es hibákba — mint egy forgalomirányító, aki adagolja az autókat a szűk hídra. Egy tipikus provider-limit percenként néhány százezer token; ha ezt túlléped, a provider elutasít, és a gateway feladata, hogy ez sose történjen meg.
- Retry Átmeneti hibáknál (429, 500, timeout) automatikus újrapróbálkozás exponential backoff-fal és jitterrel. Fontos a különbség: csak a retryable hibákat próbáld újra — egy 400-as (rossz kérés) ismétlése értelmetlen, csak pénzt és időt éget. A retry-nak van egy alattomos veszélye is: ha nem idempotens a hívás (pl. a tool ténylegesen küld egy emailt), a retry duplikálhatja a mellékhatást.
- Timeout Minden hívásra kőbe vésett időkorlát. LLM-nél ez trükkös, mert a válasz lassú lehet — de a végtelen várakozás elfogadhatatlan: leköti az erőforrásokat, és a felhasználót válasz nélkül hagyja. A streaming és a nem streaming hívásnak eltérő timeout-stratégiája van: streamingnél nem a teljes válaszra, hanem a token-közötti csendre (inter-token timeout) érdemes időzíteni.
- Fallback Ha az elsődleges provider vagy modell nem elérhető, a gateway automatikusan átvált egy másikra. Például: ha az „A" provider leáll, menjen a kérés a „B"-hez, akár kicsit gyengébb, de elérhető modellhez. A cél a rendelkezésre állás — jobb egy kicsit gyengébb válasz, mint semmi. Fontos, hogy a fallback modellt is teszteld evalokkal, különben egy kimaradás közben csendben rossz minőséget szolgálsz ki.
- Circuit breaker Ha egy provider sorozatosan hibázik, a gateway egy időre „kinyitja az áramkört", és meg sem próbálja hívni — a fallbackre terel. Ez pontosan úgy működik, mint egy elektromos kismegszakító: túlterhelésnél lekapcsol, hogy ne égjen le a ház. Enélkül egy döglődő provider végtelen retry-jai az egész rendszeredet földbe döngölik. A breaker jellemzően három állapotot ismer: closed (minden megy), open (minden blokkolva), half-open (óvatos próbálkozás a gyógyulás tesztelésére).
- Model allowlist Csak engedélyezett modellek hívhatók a gateway-en át. Így nem fordulhat elő, hogy valaki véletlenül egy nem jóváhagyott, drága vagy compliance szempontból tiltott modellt használ. A gateway a döntőbíró: ami nincs a listán, az nem megy át. Ez egyben a model drift elleni védelem első lépése is — csak validált verziók kerülnek a listára.
- Regional routing Adatrezidencia és latency miatt a kérés a megfelelő régió endpointjára megy — pl. egy EU-s felhasználó adata EU-s régióban maradjon. GDPR-környezetben ez gyakran nem opcionális, hanem jogi követelmény. Egy magyar vagy EU-s ügyfélnek épített rendszernél ez az egyik első kérdés, amit a jogi csapat feltesz: „hol dolgozzák fel az adatot?"
- Budget enforcement Kemény költségplafon: ha egy tenant vagy feature eléri a napi/havi keretét, a gateway blokkol vagy olcsóbb modellre vált. Ez az a szabály, ami megakadályozza, hogy egy elszabadult agent-loop egyetlen éjszaka alatt elköltse a havi büdzsét. Valós rémtörténet-minta: egy végtelen ciklusba került agent, ami óránként több ezer hívást indított — budget enforcement nélkül reggelre több ezer euró kára lehet.
- Request logging Minden hívás strukturált naplózása: melyik modell, mennyi input/output/reasoning token, mennyi ideig tartott, mennyibe került. Ez táplálja az observability és a költségallokáció rétegét — a gateway a természetes hely, ahol ez az adat egyben keletkezik. Ebből épül fel a per-tenant költségjelentés és a lassú-hívás elemzés is.
- PII-redaction Érzékeny személyes adatok kiszűrése vagy maszkolása, mielőtt a kérés kimenne a providerhez, illetve mielőtt logolódna. Így egy telefonszám vagy TAJ-szám nem szivárog el harmadik félhez vagy a debug-logokba. Az adatvédelmi vonatkozásokat a 14. Observability is érinti. Vigyázz: az agresszív redaction ronthatja a válasz minőségét (ha épp a nevet kellett volna feldolgozni), ezért a redaction szabályait gondosan kell hangolni.
- Provider-specific konfigurációk Minden provider máshogy kezeli a paramétereket, a hibakódokat, a streaming formátumot és a tool calling szintaxist. A gateway elrejti ezeket a különbségeket egy egységes interfész mögé — az alkalmazáskódod egyféleképpen hív, a gateway fordít le a provider nyelvére. Ez az adapter minta: egy közös belső formátum, és providerenként egy fordítóréteg.
- Verziópinnelés A modellverzió rögzítése, hogy egy csendes provider-frissítés ne változtassa meg észrevétlenül a viselkedést és ne rontsa el az evaljaidat. A gateway garantálja, hogy addig ugyanaz a pinnelt verzió fut, amíg tudatosan, evalokkal validálva nem váltasz — így a model drift kezelhetővé válik. Soha ne használj „latest" aliast productionban: egy éjszakai modellfrissítés miatt reggel máshogy viselkedhet a rendszered, és nem fogod tudni, miért.
async def call_model(request, ctx):
if not budget.has_room(ctx.tenant): # budget enforcement
raise BudgetExceeded()
model = router.pick(request, region=ctx.region) # provider routing
if model not in ALLOWLIST: # model allowlist
raise ModelNotAllowed(model)
request = redact_pii(request) # PII-redaction
for provider in [model.primary, model.fallback]:
if breaker.is_open(provider): # circuit breaker
continue
try:
resp = await with_retry(provider.call, request, timeout=30)
log_usage(ctx, provider, resp) # request logging
return resp
except TransientError:
breaker.record_failure(provider)
raise AllProvidersDown()
Mit tanulj ebből a vázból? Hogy a gateway nem egy nagy, monolit doboz, hanem egy jól felismerhető sorrend: előbb a kapuk (budget, allowlist), aztán a transzformáció (redaction), végül a hívás ismételt próbákkal és breaker-védelem alatt. Minden komment egy-egy önálló felelősség, és mindegyik tesztelhető külön. Egy éles gateway persze ennél jóval részletesebb (metrikák, tracing, streaming-kezelés), de a csontváz ez marad.
Döntési szempontok: építsem vagy vegyem?
A model gateway kapcsán a leggyakoribb kérdés, hogy saját kódban írd-e meg, vagy használj kész, LiteLLM-szerű routing-proxyt. Nincs egyetlen jó válasz — a rendszered mérete és követelményei döntenek.
Kész megoldás / proxy
- Gyorsan indulsz, sok providert egységesen kezel out-of-the-box.
- A standard funkciók (routing, retry, fallback, költségkövetés) készen jönnek.
- Ideális korai és közepes fázisban, amikor a fókusz a termékfeature, nem az infrastruktúra.
Saját gateway
- Speciális policy-, budget- vagy compliance-logika, amit a kész eszköz nem fed le.
- Szoros integráció a saját identity- és audit-rétegeddel.
- Nagy volumen, ahol a proxy overhead-je vagy a vendor lock-in már számít.
Gyakori köztes út: kész proxyval indulsz, és csak azokat a rétegeket írod saját kódban, amelyek valóban egyediek (pl. a per-tenant budget enforcement összekötése a számlázással). A frameworkválasztás tágabb szempontjait a 17. Frameworkök fejezet tárgyalja.
Distributed systems alapok
Egy production AI-rendszer elosztott rendszer: több szolgáltatás, hálózaton át kommunikálva, ahol bármi bármikor elromolhat. Ezek a fogalmak nem AI-specifikusak — a klasszikus szoftverfejlesztésből jönnek, és részletesen a 18. Szoftverfejlesztés fejezet tárgyalja őket. Itt csak azt mutatjuk meg, miért különösen fontosak AI-kontextusban, ahol a hívások lassúak, drágák és nemdeterminisztikusak.
- Async programozás Mivel egy LLM- vagy tool-hívás másodpercekig tarthat, nem engedheted meg, hogy egy szál tétlenül várjon rá. Async/await-tel egyetlen worker közben sok másik kérést kiszolgál. AI-nál ez alap, nem finomhangolás: a rendszer nagy része I/O-várakozás — miközben a modell „gondolkodik", a CPU-d szinte semmit nem dolgozik, így egy szinkron megoldás ezerszeres erőforrás-pazarlás lenne.
- Queue-k A lassú munkát nem szinkron végzed, hanem sorba teszed, és workerek dolgozzák fel. Ez adja a terhelhetőséget és a hibatűrést: ha épp túl sok a kérés, a sor kompenzál, nem esik össze a rendszer. Egy órákig futó agent-feladat eleve queue-ba való — a felhasználó egy „elindítottam" választ kap azonnal, az eredményről pedig értesítést, amikor kész.
- Event-driven architecture A komponensek eseményekkel kommunikálnak, nem közvetlen, szinkron hívásokkal. „A dokumentum feltöltődött" esemény elindíthatja az indexelést, anélkül hogy a feltöltő tudna az indexelőről. Ez lazán csatolt, jól skálázható rendszert ad: új feldolgozót (pl. vírusellenőrzés) úgy adsz hozzá, hogy csak feliratkozik ugyanarra az eseményre, a meglévő kódot nem kell módosítani.
- Idempotencia Ugyanaz a művelet többször végrehajtva ugyanazt az eredményt adja, mellékhatás nélkül. Elosztott rendszerben elkerülhetetlen, hogy egy üzenet duplán érkezik — idempotency key nélkül egy retry kétszer küldené el ugyanazt az emailt vagy vonná le kétszer a pénzt. Olyan, mint a lift hívógombja: hiába nyomod ötször, egyszer jön. Agentnél kritikus, mert a retry a normál működés része, nem kivétel.
- Eventual consistency Az elosztott állapot nem azonnal, hanem „végül" lesz konzisztens minden csomóponton. Egy frissen indexelt dokumentum lehet, hogy a keresésben csak pár másodperc múlva jelenik meg. Ezzel a rendszer és az UX tervezésénél számolni kell — nem bug, hanem az elosztottság ára. UX-oldalon ezt „feldolgozás alatt" jelzéssel kezeled, nem azzal, hogy azonnali frissességet ígérsz.
- Backpressure Ha a bejövő kérések gyorsabban érkeznek, mint ahogy fel tudod dolgozni, jelezned kell „lassíts" — sorhossz-limittel, elutasítással vagy throttlinggal. Enélkül a rendszer memóriája megtelik és összeomlik. Olyan, mint a vízcsap: ha a lefolyó nem bírja, elzárod, nem hagyod túlfolyni. AI-nál ez különösen gyors probléma, mert a lassú hívások miatt a sor hamar felduzzad.
- Distributed lock Ha több worker ugyanarra az erőforrásra pályázik (pl. egy long-running agent állapotára), lock biztosítja, hogy egyszerre csak egy nyúljon hozzá. Olyan, mint a repülőgép mosdaján a „foglalt" tábla — jelzi a többieknek, hogy várni kell. A lease-alapú lockok időkorláttal védenek a beragadás ellen: ha a lockot tartó worker meghal, a lease lejár, és más átveheti, nem ragad be örökre a rendszer.
- Retry és exponential backoff Átmeneti hiba után újrapróbálkozol, de egyre növekvő szünetekkel (1s, 2s, 4s…) és véletlen jitterrel, hogy ne rohanjátok le egyszerre a lábadozó szolgáltatást. AI-nál ez különösen fontos, mert a providerek rate limitjei és átmeneti kimaradásai mindennaposak. A jitter (véletlen zaj a várakozási időben) azért kell, hogy ne mind ugyanabban a másodpercben próbálkozzon újra ezer kliens — az újabb lavinát okozna.
- Circuit breaker Ugyanaz az elv, mint a model gateway-nél: ha egy downstream szolgáltatás folyamatosan hibázik, egy időre leállítod a hívását, hogy ne pazarolj erőforrást és ne terjedjen tovább a hiba. A retry és a circuit breaker párban véd: az egyik a rövid zökkenőket, a másik a tartós kiesést kezeli. Enélkül a retry-k önmagukban felerősíthetik a bajt (retry storm).
- Saga/compensation Több lépéses, elosztott folyamatnál nincs egyetlen nagy tranzakció — ha egy késői lépés elhasal, kompenzáló műveletekkel „csinálod vissza" a korábbiakat. Mint egy szállodai foglalás: ha a repülőjegy nem jött össze, lemondod a már lefoglalt szobát. Agentnél ez kritikus, mert a folyamat félúton is elakadhat, és nincs olyan luxus, hogy egy tucat külső API-hívást egyetlen adatbázis-tranzakcióba zárj.
- Cache invalidation A gyorsítótár csak addig hasznos, amíg friss. El kell döntened, mikor és hogyan érvényteleníted — különben elavult adatot szolgálsz ki. AI-nál a prompt- és semantic caching (lásd 12. Optimalizáció) sokat spórol, de ha a mögöttes tudás változik, a cache-t frissíteni kell, különben régi válaszokat adsz. A semantic cache-nél külön csapda, hogy „elég hasonló" kérdésre régi választ ad — a hasonlósági küszöböt gondosan kell hangolni.
- Concurrency control Az egyidejű módosítások kezelése, hogy ne írja felül egyik művelet a másikat (pl. optimista lockolás verziószámmal). Ha két agent-lépés párhuzamosan frissíti ugyanazt az állapotot, kontroll nélkül elveszik az egyik írás — az elosztott állapotnál ez valós veszély. Az optimista megközelítés: írás előtt ellenőrzöd, változott-e a verzió, és ha igen, újraolvasol és újrapróbálsz.
- Cancellation propagation Ha a felhasználó megszakítja a kérést, a leállításnak végig kell terjednie a láncon: álljon le a modellhívás, a tool és a háttérmunka is. Egy elárvult, tovább futó LLM-hívás fölöslegesen égeti a pénzt és a kapacitást. Ezt szándékosan végig kell vezetni a rendszeren — magától nem történik meg. Streaming chatnél különösen látványos: ha a felhasználó bezárja a fület, a token-generálást is le kell állítani, nem hagyni, hogy a semmibe generáljon 20 másodpercig.
async def send_email_once(idem_key, payload):
# Ha ezt a kulcsot már láttuk, ne küldjük el újra
if await store.exists(idem_key):
return await store.get_result(idem_key) # a korábbi eredmény
result = await email_provider.send(payload) # tényleges mellékhatás
await store.save(idem_key, result, ttl=86400) # 24h-ig emlékszünk rá
return result
# Az idem_key jellemzően a kérésből származó stabil hash,
# nem véletlen érték — különben egy retry új kulcsot kapna.
Mit tanulj ebből? Hogy az idempotencia nem elmélet, hanem néhány sor, ami megvéd attól, hogy egy ártatlan retry kétszer küldjön ki egy emailt vagy kétszer terheljen egy kártyát. A kulcs stabilitása a lényeg: ha a kulcs a kérés tartalmából származik, akkor a retry ugyanazt a kulcsot kapja, és a rendszer felismeri a duplikációt.
Gyakori hibák elosztott AI-rendszerekben
- Retry nem-idempotens műveleten A leggyakoribb és legdrágább hiba: a gateway automatikusan újrapróbál egy tool-hívást, ami valós mellékhatással jár (fizetés, email). Idempotency key nélkül ez duplikál. Minden mellékhatással járó toolnak idempotensnek kell lennie.
- Timeout nélküli hívás Egy modellhívás timeout nélkül a végtelenségig lóghat, lefoglalva egy workert. Elég néhány ilyen, és az összes workered beragad — a rendszer „él", de nem válaszol. Minden hálózati hívásnak legyen kőbe vésett timeoutja.
- Retry storm circuit breaker nélkül Ha egy provider lelassul, a retry-k megsokszorozzák a terhelést rajta, épp amikor a legkevésbé bírja — így egy kis zökkenőből teljes kiesés lesz. A circuit breaker az, ami megtöri ezt a spirált.
- Elárvult háttérmunka A felhasználó elnavigál, de az agent-loop és a modellhívások tovább futnak, égetve a pénzt. Cancellation propagation nélkül ezt nem veszed észre, csak a hónap végi számlán.
Megbízhatóság és graceful degradation
Egy production AI-rendszernél a kérdés nem az, hogy elromlik-e valami, hanem hogy mikor — és hogy amikor elromlik, a rendszer szépen, fokozatosan épül le, vagy látványosan összeomlik. A graceful degradation azt jelenti, hogy a rendszer csökkentett funkcionalitással is tovább szolgál, ahelyett hogy teljesen leállna. Ez az a gondolkodásmód, ami a distributed systems mintákat egységes stratégiává köti össze.
A degradation lépcsői
Amikor egy komponens gyengélkedik, jellemzően nem bináris a döntés (megy / nem megy), hanem több fokozatban lehet visszavenni. Egy jól tervezett rendszer ezeken a lépcsőkön ereszkedik lefelé, mielőtt teljesen feladná.
- Modell-fallback Ha az elsődleges modell lassú vagy elérhetetlen, egy gyengébb, de működő modellre váltasz. A felhasználó kicsit rosszabb választ kap, de kap választ — ez szinte mindig jobb, mint a hibaüzenet.
- Feature-kikapcsolás Ha a vector index túlterhelt, ideiglenesen kikapcsolod a RAG-ot és a modell csak a saját tudásából válaszol, egy figyelmeztetéssel. A rendszer magja tovább él, csak egy réteg esik ki.
- Cache-elt válasz kiszolgálása Kiesés alatt egy kicsit régebbi, cache-elt válasz gyakran elfogadhatóbb, mint a hiba — különösen olvasás-jellegű, nem tranzakciós kéréseknél.
- Sorbaállítás azonnali feldolgozás helyett Ha a kapacitás elfogyott, a kérést queue-ba teszed és „hamarosan értesítünk" választ adsz, ahelyett hogy elutasítanál. A backpressure így nem elutasítás, hanem késleltetés.
Health check és observability-kapcsolat
Ahhoz, hogy a rendszer tudjon degradálni, tudnia kell, hogy baj van. Ehhez minden komponensnek van egy health checkje (él-e, elérhető-e a függősége), és a gateway, illetve az orchestrator ezekre reagál. A tényleges belátás — mi lassult, hol égett el a token, melyik retry mentett meg — a trace-ekből jön; ezt önálló fejezet, a 14. Observability tárgyalja. A kettő szorosan összetartozik: a degradation a reakció, az observability az érzékszerv. Vak rendszer nem tud okosan degradálni.
Összefoglalás
Egy production AI alkalmazás nem egy backend és egy LLM-hívás, hanem együttműködő komponensek rendszere: frontend és streaming UI, application API, agent orchestrator, model és tool gateway, workflow engine, queue, adat- és állapottárolók, memory service, policy engine, sandbox, eval service, valamint a mindent átfogó observability, secrets/identity és audit log. Nem kell mindet egyszerre megépíteni — de tudnod kell, melyik mit old meg, hogy tudatosan válassz, és az érettségi szinteknek megfelelően vezesd be őket, ahogy a valós fájdalom kikényszeríti.
A model gateway a legkézzelfoghatóbb tanulság: egyetlen központi kapu, ahol egyszerre kényszeríted ki a megbízhatóságot, a költségkontrollt és a compliance-t — a szétszórt provider-logika helyett. Az alapszabály, hogy az alkalmazáskód sose hívja közvetlenül a provider SDK-ját. A distributed systems minták (async, queue, idempotencia, backpressure, retry/backoff, circuit breaker, saga) pedig azok, amelyek felkészítik a rendszert a valóságra, ahol a hálózat, a provider és a terhelés sosem ideális — és ezek fogják össze a graceful degradation stratégiáját is.
Ha ezt a réteget érted és meg tudod tervezni, akkor a következő kérdés már az, hogyan látsz bele a működésébe és hogyan biztosítod — erről szólnak a következő fejezetek.