LLMOps / GenAI Production
OpenAI
MLflow
A kurzus a production 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 production-ready 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ő.
Prompt management, evaluation, A/B testing, monitoring, guardrails, deployment, scaling
Production-ready RAG chatbot a WebShop Pro ügyfélszolgálatához
RAG · Guardrails · Hallucination
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ás, a hallucináció ellenőrzés és a token-alapú 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 engineerings, 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 token-költség és a biztonság egyensúlyozása folyamatos feladat.
Termelési 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.
| Fogalom | Leírás |
|---|---|
| Prompt Engineering | System/user prompt tervezés és tesztelés |
| RAG | Retrieval-Augmented Generation |
| Eval Dataset | Tesztadat a minőség mérésére |
| Guardrails | Biztonsági szűrők és korlátok |
| Hallucination | AI által generált hamis információ |
| Latency | Válaszidő monitorozás |
# 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}')LLM : OpenAI GPT-4o Embedding : text-embedding-3-small Vector DB : ChromaDB Framework : LangChain Tracking : MLflow Serving : FastAPI Monitoring : Prometheus + Grafana
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ó.
Tip: 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.
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')Logged 3 prompt versions v1: generic, v2: with context, v3: with guardrails
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.
Tip: 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.
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')Eval dataset: 5 samples across 5 categories Saved to eval/qa_dataset.json
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.
Tip: 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.
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}')Hallucination check: NO Reason: Answer claims 90 days but context says 30 days
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.
Tip: Productionben 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.
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)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
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.
Tip: Á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%".
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()
raiseLatency: 1.23s (p50: 1.1s, p95: 2.5s, p99: 4.1s) Requests: 1500/min Errors: 0.2%
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.
Tip: A guardrails thresholdokat 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.
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 answerGuardrails active: - ToxicLanguage: threshold 0.8 - PIIFilter: EMAIL, PHONE, SSN - NoOffTopic: orders, products, returns, shipping All checks passed!
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.
Tip: 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.
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 satisfactionA/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)
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 modellek láncba vannak szervezve: ha az első (legtöbbet tudó, de legdrágább) modell timeout-ot vagy API hibát ad, automatikusan a következő (gyorsabb, olcsóbb) modell próbálkozik.
Miért szükséges? Az LLM API-k nem 100%-ban megbízhatóak: rate limit, szerver leállás, hálózati problémák bármikor előfordulhatnak. Fallback nélkül a teljes chatbot leáll, ami üzleti szempontból elfogadhatatlan. A fallback stratégia biztosítja, hogy a felhasználók mindig kapjanak valamilyen választ.
A folyamat: A kódban három modell van sorba rendezve: gpt-4o (legjobb minőség, 3s limit), gpt-4o-mini (jó minőség, 2s limit), gpt-3.5-turbo (alapvető, 1s limit). A chat_with_fallback függvény végigmegy a listán, és az első sikeresen válaszoló modellt használja. Ha minden modell elbukik, egy előre definiált hibaüzenetet ad vissza.
Tip: A fallback modellek válaszait külön naplózd (MLflow-ban), és heti szinten elemezd, milyen gyakran aktiválódik a fallback. Ha túl gyakran, az arra utal, hogy a primer modell SLA-ját javítani kell.
models = [
{'name': 'gpt-4o', 'max_latency': 3.0, 'max_cost': 0.03},
{'name': 'gpt-4o-mini', 'max_latency': 2.0, 'max_cost': 0.005},
{'name': 'gpt-3.5-turbo', 'max_latency': 1.0, 'max_cost': 0.001},
]
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'}gpt-4o: timeout after 3.0s gpt-4o-mini: success (1.2s) Using fallback model: gpt-4o-mini
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.
Tip: 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.
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')POST /chat/stream Token-by-token streaming TTFB: 0.3s, Total: 1.5s
Cost optimization
A költségoptimalizálás az LLM üzemeltetés egyik legfontosabb aspektusa: egy production chatbot havi százezres kéréseivel a költségek gyorsan elfuthatnak. A fő stratégiák: semantic caching (hasonló kérdésekre cache-elt válasz), kisebb modell választása (ahol a minőség elfogadható), Batch API használata és prompt optimalizálás (rövidebb prompt = kevesebb token = kevesebb költség).
Miért fontos? A GPT-4o egyetlen lekérdezése ~$0.03, ami 100 000 kérésnél már havi $3000. Ha a lekérdezések 70%-ára elég a GPT-4o-mini ($0.002/kérés), a megtakarítás drámai. A semantic caching tovább csökkentheti a költségeket azáltal, hogy az ismétlődő vagy nagyon hasonló kérdéseket nem küldi el az LLM-nek.
A folyamat: A kódban egy egyszerű cache implementációt mutatunk be, amely a kérdés hash-elt változatával keresi a korábbi válaszokat. A táblázat összefoglalja a négy fő stratégiát és azok várható megtakarítását. A modell routing (melyik kérdés melyik modellhez kerül) intelligens kialakítása a legnagyobb hatású optimalizálás.
Tip: Kövesd naponta a token-fogyasztást és a költséget modellenként. Állíts be alertet, 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égia | Megtakarítás |
|---|---|
| Semantic caching | 60-80% request csökkentés |
| GPT-4o-mini (ha elég) | 90% költség csökkentés |
| Batch API | 50% olcsóbb |
| Prompt rövidítés | 30% token csökkentés |
# Semantic cache implementation
from langchain.cache import InMemoryCache
import hashlib
class SemanticCache:
def __init__(self, threshold=0.95):
self.cache = {}
self.threshold = threshold
def lookup(self, question):
# Check if semantically similar question was asked before
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 = SemanticCache()
print(f'Cache hit rate: 65% (saved ${420}/month)')Cost optimization results: Semantic cache: 65% hit rate, $420/month saved Model routing: gpt-4o-mini for 70% of queries Total savings: $680/month (45% reduction)
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.
Tip: 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.
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
# Eval results
results = evaluate(
dataset=eval_dataset,
metrics=[faithfulness, answer_relevancy, context_precision]
)
print('RAG Evaluation Results:')
for metric, score in results.items():
print(f' {metric}: {score:.3f}')RAG Evaluation Results: faithfulness: 0.912 answer_relevancy: 0.876 context_precision: 0.834 Target: all > 0.85
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 production 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.
Tip: Productionben adj hozzá autentikációt (API key vagy JWT), rate limitinget, loggingot és health check végpontot (/health). Használj Docker konténerizációt és Kubernetes-t a skálázáshoz.
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)
)POST /chat
{'answer': '...', 'sources': ['policy.pdf'], 'model': 'gpt-4o', 'latency_ms': 1234}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.
Tip: 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.
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()Rate limit: 20 req/min per user Queue: max 100 concurrent Workers: 5 async Avg latency: 1.2s at 50 req/min
Összefoglalás
Gratulálunk! Végigcsináltad a teljes LLMOps / GenAI Production kurzust, és felépítettél egy production-ready 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 + eval | Minőség mérhető és reprodukálható |
| RAG + guardrails | Biztonságos és kontrollált |
| Monitoring + fallback | Robusztus és megbízható |
| Cost optimization | Költséghatékony üzemeltetés |
Végigcsináltad az összes kurzust! Most már data/AI engineer vagy!