</> LLMOps / GenAI Production

0 / 16 szakasz kész
Utoljára szakmailag felülvizsgálva: 2026-05-14 Verzió-mátrix Output: előre megírt eredmény
Section 00

LLMOps / GenAI Production OpenAI MLflow

A kurzus az éles GenAI és RAG alkalmazások üzemeltetésének teljes életciklusát fedi le. Megtanulod, hogyan kezeld a promptokat kódként (version control, A/B testing, rollback), hogyan készíts eval datasetet a minőség mérésére, hogyan detektáld a hallucinációt, hogyan monitorozd a válaszidőt, és hogyan építs guardrails rendszert a biztonság érdekében.

A kurzus során a WebShop Pro fiktív webáruház ügyfélszolgálati chatbotját építjük fel éles használatra alkalmas szintre. Ez a gyakorlati projekt végigkíséri az összes fogalmat: a prompt tervezéstől a skálázásig.

Előfeltételek: Python alapismeretek, REST API fogalmak, alapvető ML ismeretek. Az AIOps & MLOps kurzus elvégzése ajánlott, de nem kötelező.

Tartalom

Prompt management, evaluation, A/B testing, monitoring, guardrails, deployment, scaling

Projekt

Éles használatra alkalmas RAG chatbot a WebShop Pro ügyfélszolgálatához

Szójegyzék

RAG · Guardrails · Hallucination

Section 01

LLMOps fogalmak

Az LLMOps az MLOps kiterjesztése nagy nyelvi modellek (LLM) specifikus kihívásaira. Míg a hagyományos MLOps a modell tanítására és deploymentjére fókuszál, az LLMOps olyan új problémákat is kezel, mint a prompt management, a kontextus optimalizálása, a hallucináció ellenőrzése és a tokenalapú költségkezelés.

Miért más az LLM-ek üzemeltetése? A hagyományos ML modellekkel ellentétben az LLM-eket ritkán tanítjuk újra — ehelyett a prompt engineering, a RAG pipeline és a guardrails képezik a minőség alapját. A modellek fekete dobozok, ezért az eval és a monitoring sokkal kritikusabb szerepet kap. A válaszidő, a tokenköltség és a biztonság egyensúlyozása folyamatos feladat.

Éles környezetben egy LLM alkalmazás sikeressége nem a modell képességein múlik, hanem azon, hogyan kezeljük a promptokat, hogyan mérjük a minőséget, hogyan védjük a rendszert a visszaélésektől, és hogyan biztosítjuk a megbízható működést.

FogalomLeírás
Prompt EngineeringSystem/user prompt tervezés és tesztelés
RAGRetrieval-Augmented Generation
Eval DatasetTesztadat a minőség mérésére
GuardrailsBiztonsági szűrők és korlátok
HallucinationAI által generált hamis információ
LatencyVálaszidő monitorozás
[1]
# LLMOps stack overview
stack = {
    'LLM': 'OpenAI GPT-4o',
    'Embedding': 'text-embedding-3-small',
    'Vector DB': 'ChromaDB',
    'Framework': 'LangChain',
    'Tracking': 'MLflow',
    'Serving': 'FastAPI',
    'Monitoring': 'Prometheus + Grafana'
}
for k, v in stack.items():
    print(f'{k:12s}: {v}')
Output:
LLM         : OpenAI GPT-4o
Embedding    : text-embedding-3-small
Vector DB    : ChromaDB
Framework    : LangChain
Tracking     : MLflow
Serving      : FastAPI
Monitoring   : Prometheus + Grafana
Section 02

Prompt versioning

A prompt versioning a promptok forráskódként való kezelését jelenti: minden prompt módosítás naplózott, verziózott és visszavonható, pontosan úgy, mint a szoftveres kód. Ez magában foglalja a version controlt, az A/B testinget és a rollback lehetőségét.

Miért kritikus? Egy LLM alkalmazásban a system prompt a viselkedés legfontosabb meghatározója. Ha megváltoztatod a promptot, a válaszok minősége drámaian megváltozhat — akár jobbra, akár rosszabbra. Verziózás nélkül lehetetlen visszanyomozni, melyik prompt változat milyen eredményt hozott, és nincs lehetőség a visszaállításra sem.

A folyamat: A kódban három prompt verziót naplózunk MLflow-ba: v1 (generikus), v2 (kontextus-specifikus) és v3 (guardrails-szel kiegészített). Minden verzió egy MLflow run-ként van rögzítve, így a teljes history nyomon követhető, és bármelyik verzió aktiválható.

Tipp: Használj strukturált prompt tárolást (pl. YAML fájlok vagy adatbázis), és a prompt változtatásokat mindig párosítsd eval futtatással, hogy a hatás azonnal mérhető legyen.

[2]
import mlflow

mlflow.set_experiment('/webshop/chatbot-prompts')

prompts = {
    'v1': 'You are a helpful customer service agent.',
    'v2': 'You are a helpful customer service agent for WebShop Pro. Always be polite and concise.',
    'v3': 'You are a WebShop Pro agent. Answer only about orders, products, returns. If unsure, say so.'
}

for version, prompt in prompts.items():
    with mlflow.start_run(run_name=f'prompt-{version}'):
        mlflow.log_param('prompt', prompt)
        mlflow.log_param('version', version)
        mlflow.set_tag('type', 'system_prompt')
Output:
Logged 3 prompt versions
v1: generic, v2: with context, v3: with guardrails
Section 03

Evaluation dataset

Az evaluation dataset (eval dataset) egy kézzel összeállított tesztadat-halmaz, amely kérdés-válasz párokat és az elvárt válaszokat tartalmazza. Ez a kiindulópontja minden LLM minőségmérésnek: a modell válaszait ehhez az aranystandardhoz hasonlítjuk.

Miért szükséges? Az LLM-ek outputja nem determinisztikus — ugyanarra a kérdésre is különböző válaszokat adhatnak. Eval dataset nélkül csak szubjektív ítéletre vagyunk utalva, ami nem skálázható és nem reprodukálható. Az eval dataset objektív, mérhető alapot ad a minőség nyomon követéséhez.

A folyamat: A kódban 5 kategóriát fedünk le: policy (visszaküldési szabályzat), order_status (rendelés státusz), product (termékinformáció), guardrail (hatókörön kívüli kérdés) és account (fiókkezelés). Minden minta tartalmazza a kérdést, az elvárt választ és a kategóriát. Ezt a datasetet a későbbi eval és regression tesztek fogják használni.

Tipp: Az eval datasetet folyamatosan bővítsd: minden éles hibát (amikor a chatbot rosszul válaszolt) adj hozzá tesztesetként. Így a dataset egyre jobban lefedi a valós edge case-eket. Célozz meg legalább 50-100 mintát kategóriánként.

[3]
eval_dataset = [
    {'question': 'What is the return policy?', 'expected': 'Returns within 30 days', 'category': 'policy'},
    {'question': 'Where is my order #12345?', 'expected': 'Order status lookup', 'category': 'order_status'},
    {'question': 'Do you sell laptops?', 'expected': 'Yes, Laptop Pro 16', 'category': 'product'},
    {'question': 'What is the weather?', 'expected': 'OUT_OF_SCOPE', 'category': 'guardrail'},
    {'question': 'How to reset password?', 'expected': 'Account settings', 'category': 'account'},
]

import json
with open('eval/qa_dataset.json', 'w') as f:
    json.dump(eval_dataset, f, indent=2)
print(f'Eval dataset: {len(eval_dataset)} samples')
Output:
Eval dataset: 5 samples across 5 categories
Saved to eval/qa_dataset.json
Section 04

Hallucination detection

A hallucináció akkor fordul elő, amikor az AI magabiztosan olyan információt generál, ami nem fedi le a valóságot vagy nem található meg a megadott kontextusban. Ez az LLM-ek egyik legkomolyabb kockázata: a válasz hihetőnek hangzik, de téves. A detektálás és prevenció kulcsfontosságú minden production GenAI rendszerben.

Miért veszélyes? Egy ügyfélszolgálati chatbotban a hallucináció közvetlen üzleti kárt okozhat: ha a chatbot 90 napos visszaküldési határidőt mond 30 nap helyett, az ügyfél jogosan fog panaszt tenni. A hallucináció rontja a felhasználói bizalmat és jogi kockázatot is jelenthet.

A folyamat: A kódban egy LLM-alapú hallucináció ellenőrzőt implementálunk: a kontextust, a kérdést és a választ beadja egy másik LLM-nek, amely eldönti, hogy a válasz teljes mértékben alátámasztott-e a kontextus által. A példában a válasz „90 days"-t mond, de a kontextus „30 days"-t ír — a detektor ezt helyesen azonosítja.

Tipp: Több rétegű védelem alkalmazz: (1) RAG-val korlátozd a kontextust, (2) hallucináció detektorral ellenőrizd a választ, (3) guardrails-szel szűrd a kimenetet, és (4) használd a temperature=0 beállítást a determinisztikusabb válaszok érdekében.

[4]
import openai

def check_hallucination(question, answer, context):
    'Check if answer is grounded in context'
    prompt = f"""
    Context: {context}
    Question: {question}
    Answer: {answer}
    
    Is the answer fully supported by the context? Answer YES or NO.
    """
    response = openai.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        temperature=0
    )
    return response.choices[0].message.content.strip()

result = check_hallucination(
    'What is the return policy?',
    'You can return within 90 days for free.',  # Hallucination!
    'Return policy: 30 days, shipping fee applies.'
)
print(f'Hallucination check: {result}')
Output:
Hallucination check: NO
Reason: Answer claims 90 days but context says 30 days
Section 05

RAG pipeline production

A production RAG pipeline a Retrieval-Augmented Generation ipari szabványa: a felhasználói kérdésre először releváns dokumentumokat keresünk vissza (retrieval), majd azokat kontextusként beadva generáljuk a választ (generation). A fejlett RAG rendszerek rerankingot (eredmények újrasorrendezése relevancia szerint), forráshivatkozást (citation) és kontextus-ablak optimalizációt is alkalmaznak.

Miért jobb, mint a sima LLM? Egy alap LLM csak a tanító adatait „tudja" — nem ismeri a cég termékeit, árait, szabályzatait. A RAG a válaszadást a tényleges dokumentumokra alapozza, ami drasztikusan csökkenti a hallucinációt és naprakész információt biztosít a dokumentumtár frissítésével.

A folyamat: A kódban a LangChain keretrendszert használjuk: ChromaDB vektor adatbázisból visszakeressük a top-5 releváns dokumentumot, majd a ChatPromptTemplate segítségével a kontextust és a kérdést egy structúrátlan promptba foglaljuk. Az LLM a kontextusra hivatkozva válaszol, és forrásokat is megjelöl.

Tipp: Éles környezetben használj top-k értéket 3-5 között (túl sok kontextus rontja a minőséget és növeli a költséget), alkalmazz reranking modellt (pl. Cohere Rerank), és a chunking stratégiát optimalizáld a dokumentumtípusnak megfelelően.

[5]
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate

# RAG pipeline
llm = ChatOpenAI(model='gpt-4o', temperature=0)
retriever = Chroma(persist_directory='chroma_db').as_retriever(k=5)

prompt = ChatPromptTemplate.from_messages([
    ('system', 'Answer based on context. If unsure, say so. Cite sources.'),
    ('user', 'Context: {context}\n\nQuestion: {question}')
])

def rag_query(question):
    docs = retriever.invoke(question)
    context = '\n'.join(d.page_content for d in docs)
    chain = prompt | llm
    return chain.invoke({'context': context, 'question': question})

response = rag_query('What is the return policy?')
print(response.content)
Output:
Based on the return policy document:
- Returns accepted within 30 days of purchase
- Shipping fee of $5.99 applies
- Items must be in original packaging

Source: returns_policy.pdf
Section 06

Latency monitoring

A latency monitoring a válaszidő folyamatos mérését és riasztását jelenti. Production LLM rendszereknél a válaszidő kritikus UX-tényező: ha a chatbot 10 másodpercig gondolkodik, a felhasználók frusztrálódnak és elhagyják a beszélgetést. A Prometheus és Grafana kombinációval valós idejű metrikákat és alerteket építhetünk.

Mértékegységek: A legfontosabb mutatók: p50 (medián), p95 (95. percentilis) és p99 válaszidő, a kérelmek száma percenként (requests/min), és a hibaarány (error rate). A p95/p99 különösen fontos, mert a „legrosszabb eseteket" mutatja — ha ez túl magas, a felhasználói élmény romlik.

A folyamat: A kódban Prometheus Histogram metrikát használunk a kérés-időtartam mérésére, Counter metrikát a kérések és hibák számolására. A @request_duration.time() dekorátor automatikusan méri a függvény végrehajtási idejét. A hibakezelés (try/except) biztosítja, hogy a hibák is naplózásra kerüljenek.

Tipp: Állíts be alerteket: ha a p95 válaszidő meghaladja az 5 másodpercet, vagy a hibaarány meghaladja az 1%-ot, automatikus riasztás küldése. Érdemes SLA-t (Service Level Agreement) definiálni: pl. „p95 < 3s, availability > 99.5%".

[6]
import time
import prometheus_client as prom

# Metrics
request_duration = prom.Histogram('llm_request_duration_seconds', 'LLM request duration')
request_total = prom.Counter('llm_requests_total', 'Total LLM requests')
error_total = prom.Counter('llm_errors_total', 'Total LLM errors')

@request_duration.time()
def chat_with_monitoring(question):
    request_total.inc()
    try:
        start = time.time()
        response = rag_query(question)
        latency = time.time() - start
        print(f'Latency: {latency:.2f}s')
        return response
    except Exception as e:
        error_total.inc()
        raise
Output:
Latency: 1.23s (p50: 1.1s, p95: 2.5s, p99: 4.1s)
Requests: 1500/min
Errors: 0.2%
Section 07

Guardrails és safety

A guardrails (biztonsági korlátok) olyan szűrők, amelyek garantálják, hogy az AI ne adjon ki káros, nemkívánatos vagy jogilag problematikus választ. Három fő területet fednek le: toxicitás (sértő, agresszív tartalom szűrése), PII szivárgás (személyes adatok, email címek, telefonszámok védelme) és topic restriction (a chatbot csak a meghatározott témákban válaszoljon).

Miért kritikus? Egy ügyfélszolgálati chatbot a cég arca. Ha trágár választ ad, kiszivárogtat személyes adatokat, vagy politikai kérdésekre válaszol, az márkakárosodást és jogi következményeket vonhat maga után. A guardrails a utolsó védelmi vonal a generáció után.

A folyamat: A kódban a Guardrails AI könyvtárat használjuk: ToxicLanguage szűri a mérgező tartalmat, PIIFilter védi a személyes adatokat, NoOffTopic pedig biztosítja, hogy a chatbot csak a megengedett témákban (rendelések, termékek, visszaküldés, szállítás) válaszoljon. A szűrés mind a bemeneten (input), mind a kimeneten (output) megtörténik.

Tipp: A guardrails küszöbértékokat a kockázati profilhoz igazítsd: egészségügyi chatbotnál szigorúbb, belső FAQ botnál lazább. Teszteld a guardrails-t szándékosan káros inputokkal (red teaming), hogy megbizonyosodj a hatékonyságáról.

[7]
from guardrails import Guard
from guardrails.hub import ToxicLanguage, PIIFilter, NoOffTopic

guard = Guard().use_many(
    ToxicLanguage(threshold=0.8, validation_method='sentence'),
    PIIFilter(pii_entities=['EMAIL', 'PHONE', 'SSN']),
    NoOffTopic(
        valid_topics=['orders', 'products', 'returns', 'shipping'],
        model='gpt-4o-mini'
    )
)

def safe_chat(question):
    # Check input
    guard.validate(question)
    # Generate response
    answer = rag_query(question)
    # Check output
    guard.validate(answer.content)
    return answer
Output:
Guardrails active:
- ToxicLanguage: threshold 0.8
- PIIFilter: EMAIL, PHONE, SSN
- NoOffTopic: orders, products, returns, shipping

All checks passed!
Section 08

A/B testing prompts

Az A/B testing két prompt verzió párhuzamos futtatását jelenti valós felhasználói kéréseken, hogy adatvezérelt döntést hozhassunk arról, melyik prompt teljesít jobban. A forgalom véletlenszerűen oszlik meg az A és B variáns között, és a teljesítményt objektív metrikákkal (latencia, válaszhossz, elégedettség) mérjük.

Miért jobb, mint a tesztelés? Belső teszteléssel sosem fedezhető fel, hogy a valós felhasználók hogyan reagálnak az új promptról. Az A/B tesztelés biztosítja, hogy a döntés nem vélemyényen, hanem mérhető adatokon alapul. Különösen fontos, ha a prompt módosításának nem egyértelmű a hatása.

A folyamat: A kódban minden bejövő kérésnél véletlenszerűen választunk az A vagy B prompt variáns között. Minden kérésnél MLflow-ba naplózzuk a latenciát és a válasz hosszát, variáns szerint bontva. Elegendő adat (pl. 1000 kérés/variáns) összegyűlése után statisztikailag összehasonlíthatók a variánsok.

Tipp: Ne egyszerre több dolgot tesztelj (csak egy változtatás A/B tesztenként). Definiálj előre egy „győztes" kritériumot (pl. elégedettség +5% és latencia növekedés <10%), és ne a teszt eredménye alapján döntsd el, mi a sikeres — az ad hoc döntés torzítja az eredményt.

[8]
import random
import mlflow

prompt_a = 'You are a helpful agent. Be concise.'
prompt_b = 'You are a WebShop Pro expert. Answer with bullet points.'

def ab_test_chat(question):
    variant = random.choice(['A', 'B'])
    prompt = prompt_a if variant == 'A' else prompt_b
    
    start = time.time()
    response = call_llm(prompt, question)
    latency = time.time() - start
    
    mlflow.log_metrics({
        f'latency_{variant}': latency,
        f'response_length_{variant}': len(response),
    })
    return response, variant

# After 1000 requests:
# Variant A: avg latency 1.1s, avg length 85 chars
# Variant B: avg latency 1.3s, avg length 120 chars, 15% better satisfaction
Output:
A/B Test Results (1000 requests each):
Variant A: latency=1.1s, satisfaction=72%
Variant B: latency=1.3s, satisfaction=87%
Winner: Variant B (+15% satisfaction)
Section 09

Fallback model strategy

A fallback model stratégia biztosítja a szolgáltatás folytonosságát, ha a primer LLM nem elérhető vagy túl lassú. A lánc lényege egyszerű: először a legjobb minőségű modellt próbáljuk, hiba vagy timeout esetén olcsóbb/gyorsabb modellre váltunk, végső esetben pedig cache-elt vagy szabályalapú választ adunk.

Miért szükséges? Az LLM API-k nem 100%-ban megbízhatóak: rate limit, szerveroldali hiba, hálózati probléma vagy átmeneti lassulás bármikor előfordulhat. Fallback nélkül a teljes chatbot leállna. Fallbackkel a rendszer kontrolláltan degradálódik: lehet, hogy a válasz kevésbé részletes, de a felhasználó nem marad válasz nélkül.

A folyamat: A kódban három szintet látunk: erős modell, gyors/olcsóbb modell, majd cached-search. A konkrét modellneveket mindig konfigurációból kezeld, mert a szolgáltatók modellkínálata és árazása változik. A chat_with_fallback függvény végigmegy a listán, és az első sikeresen válaszoló szintet használja.

Tipp: A fallback eseményeket külön naplózd (MLflow-ban vagy observability eszközben), és heti szinten elemezd, milyen gyakran aktiválódik a fallback. Ha túl gyakran, az arra utal, hogy a primer modell SLA-ja, timeout beállítása vagy rate limit kezelése javításra szorul.

[9]
# A max_cost_per_req csak felső becslés átlagos kérdés-válasz hosszra.
# Az aktuális tokenárakat konfigurációból töltsd, ne égesd be a kódba.
models = [
    {'name': 'gpt-4o',        'max_latency': 3.0, 'max_cost_per_req': 0.015},
    {'name': 'gpt-4o-mini',   'max_latency': 2.0, 'max_cost_per_req': 0.0008},
    {'name': 'cached-search', 'max_latency': 0.2, 'max_cost_per_req': 0.0001},
]

def chat_with_fallback(question, context):
    for model in models:
        try:
            response = call_llm(model['name'], question, context, timeout=model['max_latency'])
            return {'response': response, 'model': model['name']}
        except (Timeout, RateLimit, APIError):
            print(f'{model["name"]} failed, trying fallback...')
    return {'response': 'Sorry, all models are busy. Please try again.', 'model': 'fallback'}
Output:
gpt-4o: timeout after 3.0s
gpt-4o-mini: success (1.2s)
Using fallback model: gpt-4o-mini
Section 10

Streaming responses

A streaming responses (token-by-token streamelés) technika lényege, hogy a szerver nem várja meg, amíg a teljes válasz elkészül, hanem azonnal, tokenenként küldi az adatot a kliensnek. Ez drasztikusan javítja a felhasználói élményt: a felhasználó az első token megjelenésétől (Time To First Byte, TTFB) kezdve látja a válasz épülését.

Miért fontos? Egy tipikus LLM válasz 1-5 másodperc alatt generálódik teljes egészében. Ha a felhasználó ennyi ideig egy üres képernyőt lát, az frusztráló. Streamelés esetén a TTFB 200-300 ms, és a válasz fokozatosan épül fel — hasonlóan a ChatGPT felhasználói élményhez.

A folyamat: A kódban FastAPI StreamingResponse-t használunk, amely egy aszinkron generátor függvényből kapja az adatot. Az OpenAI API stream=True paraméterrel hívjuk, és a async for chunk ciklussal minden generált tokent azonnal továbbítjuk a kliensnek.

Fontos: a streaming a time-to-first-byte (TTFB) percepcióját javítja, de a teljes válasz latency ugyanaz marad (vagy minimálisan rosszabb a streamelt átvitel többlete miatt). Tehát a UX érzete jobb, de a system throughput nem nő — egy chatbot user várása alatt jól, de batch inferenciánál nincs előnye.

Tipp: A streamelés során is naplózd a teljes válaszidőt és a TTFB-t. Élesben fontos, hogy a hálózati buffering minimalizálva legyen — használj media_type='text/event-stream' formátumot SSE (Server-Sent Events) implementációhoz.

[10]
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

@app.post('/chat/stream')
async def chat_stream(question: str):
    async def generate():
        stream = await openai.chat.completions.create(
            model='gpt-4o',
            messages=[{'role': 'user', 'content': question}],
            stream=True
        )
        async for chunk in stream:
            if chunk.choices[0].delta.content:
                yield chunk.choices[0].delta.content
    
    return StreamingResponse(generate(), media_type='text/plain')
Output:
POST /chat/stream
Token-by-token streaming
TTFB: 0.3s, Total: 1.5s
Section 11

Cost optimization

A költségoptimalizálás az LLM üzemeltetés egyik legfontosabb része: egy éles chatbot havi százezres kéréseivel a költségek gyorsan elfuthatnak. A fő stratégiák: exact-match / semantic caching (hasonló vagy azonos kérdésekre cache-elt válasz), provider-szintű prompt caching, modell routing (egyszerű kérdésre olcsóbb modell), Batch API használata és prompt optimalizálás (rövidebb prompt = kevesebb token).

Miért fontos? Az LLM költség általában a bemeneti tokenekből, kimeneti tokenekből, modellválasztásból és opcionális tool-hívásokból áll. A pontos árak idővel változnak, ezért nem jó gyakorlat a példakódban látott számokat örökre beégetni. Kezeld az árlistát konfigurációként, és rendszeresen egyeztesd a szolgáltató pricing oldalával vagy billing exportjával.

Prompt caching: ha sok kérés ugyanazzal a hosszú system prompttal vagy dokumentum-prefixszel indul, a provider-szintű prompt caching jelentősen csökkentheti az input token költséget és a válaszidőt. A pontos működés szolgáltatónként eltér: van, ahol explicit cache marker kell, máshol automatikus prefix-cache működik. A mérnöki tanulság ugyanaz: tartsd stabilan az ismétlődő prompt prefixet, és mérd a cache hit rate-et.

A folyamat: A kódban egy egyszerű exact-match cache implementációt mutatunk be (lásd lentebb a megkülönböztetést a valódi semantic cache-től). A táblázat összefoglalja a fő stratégiákat és azok várható hatását. A modell routing intelligens kialakítása gyakran a legnagyobb hatású optimalizálás.

Tipp: Kövesd naponta a token-fogyasztást és a költséget modellenként. Állíts be riasztást, ha a napi költség meghaladja a budget 120%-át. A cache hit rate-et is monitorozd: ha 60% alatt van, érdemes a cache stratégia finomításán gondolkodni.

StratégiaVárható hatás
Exact-match / semantic cachingKevesebb ismételt LLM-hívás
Provider-szintű prompt cachingOlcsóbb és gyorsabb ismétlődő prefixek
Kisebb modell egyszerű kérdésekreAlacsonyabb tokenköltség elfogadható minőség mellett
Batch APIOlcsóbb offline, nem interaktív feldolgozás
Prompt rövidítésKevesebb input token és kisebb latency
[11]
# Exact-match prompt cache (NEM semantic!)
from langchain.cache import InMemoryCache
import hashlib

class ExactMatchCache:
    def __init__(self):
        self.cache = {}

    def lookup(self, question):
        # Csak akkor talál, ha a kerdes szorol szora azonos (lowercase utan)
        q_hash = hashlib.md5(question.lower().encode()).hexdigest()
        return self.cache.get(q_hash)

    def store(self, question, answer):
        q_hash = hashlib.md5(question.lower().encode()).hexdigest()
        self.cache[q_hash] = answer

cache = ExactMatchCache()
# Tipikus 1000 query/nap eseten ~$X/ho megtakaritas,
# az aktualis modellar es cache-hit aranyszama fuggvenyeben.
print('Exact-match cache active. Saját költségbecsléshez használd a provider cost calculator-t.')
Output:
Exact-match cache active.
Tipikus cache hit rate: 30-50% FAQ-jellegű forgalomnál.
Saját számoláshoz: OpenAI / Anthropic cost calculator.
Exact-match vs. valódi semantic cache

A példakód exact-match cache: csak akkor talál, ha a kérdés szóról szóra azonos (lowercase után). Valódi semantic cache működés: a kérdést embedding-be konvertáljuk, és cosine similarity küszöbérték (pl. >0.95) felett talált korábbi kérdés válaszát adjuk vissza. Eszközök: GPTCache, Redis Stack vector search, vagy egyszerű sentence-transformers + ChromaDB lokális megoldás.

Section 12

RAG eval: RAGAS framework

A RAGAS framework (Retrieval Augmented Generation Assessment) a RAG rendszerek minőségének ipari szabványos mérőeszköze. Három kulcsmetrikát mér: faithfulness (a válasz hűsége a kontextushoz), answer relevancy (a válasz relevanciája a kérdéshez) és context precision (a visszakeresett dokumentumok relevanciája).

Miért fontos? Egy RAG rendszer teljesítménye több tényezőtől függ: jó dokumentumokat keres-e vissza, jól használja-e a kontextust, és releváns választ generál-e. A RAGAS ezeket a dimenziókat külön-külön méri, így pontosan azonosítható, hol van probléma a pipeline-ban.

A folyamat: A kódban az eval dataset-et és a három metrikát átadjuk a evaluate függvénynek, amely minden kérdésre kiszámolja a metrikákat és átlagolja az eredményt. A cél: minden metrika > 0.85. Ha bármelyik ez alá esik, a pipeline megfelelő pontján kell optimalizálni.

Tipp: A RAGAS eredményeket ne csak egyszer futtasd le, hanem integráld a CI/CD pipeline-ba. Minden prompt vagy modell változtatás után automatikusan fusson le, és hasonlítsa össze az előző eredményekkel. Ha bármelyik metrika romlik, a deployment automatikusan leáll.

[12]
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
from datasets import Dataset
import pandas as pd

# Eval dataset készítése (kérdés, generált válasz, retrieve-elt kontextus, ground truth)
eval_data = pd.DataFrame({
    "question": [
        "Mennyibe kerül a szállítás Budapestre?",
        "Mi a visszaküldési határidő?",
    ],
    "answer": [
        "A szállítás Budapestre 2 munkanap.",
        "14 napon belül lehet visszaküldeni.",
    ],
    "contexts": [
        ["A standard szállítási idő Budapesten 2 munkanap, vidéken 3 munkanap."],
        ["Az elállás 14 napon belül jelezhető. A terméknek sérülésmentesnek kell lennie."],
    ],
    "ground_truth": [
        "2 munkanap Budapesten",
        "14 nap",
    ],
})

dataset = Dataset.from_pandas(eval_data)

# RAGAS metrikák (LLM-as-judge alapú; OPENAI_API_KEY szükséges)
result = evaluate(
    dataset=dataset,
    metrics=[
        faithfulness,        # válasz a kontextuson alapul-e
        answer_relevancy,    # válasz releváns-e a kérdésre
        context_precision,   # a kontextus része-e a ground truth-nak
        context_recall,      # a ground truth ott van-e a kontextusban
    ],
)

print(result)
# {'faithfulness': 0.95, 'answer_relevancy': 0.92, 'context_precision': 0.88, 'context_recall': 0.90}
Output:
{'faithfulness': 0.95, 'answer_relevancy': 0.92, 'context_precision': 0.88, 'context_recall': 0.90}

Target: minden metrika > 0.85
Section 13

Deployment: FastAPI serving

A FastAPI deployment az LLM szolgáltatás REST API-ként való kiszolgálását jelenti. A FastAPI keretrendszer automatikus OpenAPI dokumentációt, Pydantic adatvalidációt és aszinkron kéréskezelést biztosít — mindez elengedhetetlen egy éles chatbot API-nál.

Miért FastAPI? A chatbot API-nak megbízhatóan, gyorsan és dokumentáltan kell működnie. A FastAPI automatikusan generál Swagger UI-t (tesztelhető dokumentáció), a Pydantic modellek pedig garantálják a bemeneti adatok helyességét. Az aszinkron támogatás miatt több ezer párhuzamos kérést is képes kezelni.

A folyamat: A kódban definiálunk ChatRequest (kérdés + opcionális session ID) és ChatResponse (válasz + források + használt modell + latencia) Pydantic modelleket. A /chat végpont fogadja a kérést, meghívja a RAG pipeline-t, és strukturált JSON választ ad vissza, beleértve a forrásdokumentumokat és a válaszidőt.

Tipp: Éles környezetben adj hozzá autentikációt (API key vagy JWT), sebességkorlátozást, naplózást és health check végpontot (/health). Használj Docker konténerizációt és Kubernetes-t a skálázáshoz.

[13]
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title='WebShop Chatbot API')

class ChatRequest(BaseModel):
    question: str
    session_id: str | None = None

class ChatResponse(BaseModel):
    answer: str
    sources: list[str]
    model: str
    latency_ms: int

@app.post('/chat', response_model=ChatResponse)
async def chat(req: ChatRequest):
    import time; start = time.time()
    result = rag_query(req.question)
    return ChatResponse(
        answer=result.content,
        sources=[d.metadata['source'] for d in result.docs],
        model='gpt-4o',
        latency_ms=int((time.time() - start) * 1000)
    )
Output:
POST /chat
{'answer': '...', 'sources': ['policy.pdf'], 'model': 'gpt-4o', 'latency_ms': 1234}
Section 14

Scaling: rate limiting, queue

A termelési skálázás három kulcsfontosságú mechanizmust foglal magában: rate limiting (felhasználónkénti kéréskorlátozás a visszaélések megelőzésére), request queue (kérések sorba állítása a túlzott terhelés kezelésére) és load balancing (a forgalom elosztása több szerver példány között).

Miért fontos? Ha a chatbot népszerűvé válik, a kérések száma ugrásszerűen megnőhet. Rate limiting nélkül egyetlen felhasználó is leterhelheti a rendszert, queue nélkül a túl sok párhuzamos kérés timeout-okat okoz, load balancing nélkül pedig egyetlen szerver válik szűk keresztmetszetté.

A folyamat: A kódban a SlowAPI könyvtárral 20 kérés/perc/felhasználó limitet állítunk be. Az asyncio Queue maximalizálja az egyidejűleg feldolgozott kérések számát (100), és az async worker-ek párhuzamosan dolgozzák fel a kéréseket. Ez a kombináció biztosítja a stabil működést még forgalmi csúcsok idején is.

Tipp: A rate limitet az üzleti modellhez igazítsd: ingyenes felhasználóknál szigorúbb, premium ügyfeleknél lazább. Használj priority queue-t, hogy a fontos ügyfelek kérései előbb kerüljenek feldolgozásra.

[14]
from fastapi import FastAPI
from slowapi import Limiter

limiter = Limiter(key_func=get_remote_address)

@app.post('/chat')
@limiter.limit('20/minute')  # Rate limit
def chat(request, req: ChatRequest):
    return process_chat(req)

# Queue for peak handling
import asyncio
queue = asyncio.Queue(maxsize=100)

async def worker():
    while True:
        req = await queue.get()
        result = await process_chat(req)
        queue.task_done()
Output:
Rate limit: 20 req/min per user
Queue: max 100 concurrent
Workers: 5 async
Avg latency: 1.2s at 50 req/min
Section 15

Összefoglalás

Gratulálunk! Végigcsináltad a teljes LLMOps / GenAI Production kurzust, és felépítettél egy éles használatra alkalmas GenAI rendszert. A kurzus során megtanultad az alapvető készségeket, amelyek egy AI engineer mindennapi munkájához szükségesek.

Összegzés: A prompt versioning biztosítja, hogy a módosítások nyomon követhetőek és visszavonhatóak legyenek. Az eval dataset és a RAGAS keretrendszer objektív minőségmérést tesz lehetővé. A guardrails és a hallucináció detektálás védi a rendszert a káros kimenetektől. A fallback stratégia és a monitoring garantálja a megbízható működést. A költségoptimalizálás és a skálázás pedig biztosítja, hogy a rendszer gazdaságosan és stabilan üzemelhessen.

Következő lépések: Próbáld ki ezeket a technikákat valós projekten! Építs saját RAG chatbotot, készíts golden dataset-et, futtass eval pipeline-t, és alkalmazd a guardrails-t. A gyakorlat teszi a mestert.

MegtanultukÖsszegzés
Prompt versioning + evalMinőség mérhető és reprodukálható
RAG + guardrailsBiztonságos és kontrollált
Monitoring + fallbackRobusztus és megbízható
Cost optimizationKöltséghatékony üzemeltetés
Gratulálunk!

Végigcsináltad az összes kurzust! Most már data/AI engineer vagy!

Quiz: Mi a hallucination?

Quiz: Melyik stratégiával csökkenthetjük a LLM költségeket?