</> Local LLM Engineering Crash Course

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

Local LLM Engineering: saját gépen futó AI stack Python Docker

A kurzus célja egy lokális, privacy-first LLM gateway felépítése. Nem csak azt nézzük meg, hogyan indíts el egy modellt a gépeden, hanem azt is, hogyan döntesz modellméret, quantization, latency, RAG, eszközhívás, observability és cloud fallback között.

Projekt: WebShop Pro Local AI Gateway

A WebShop Pro ügyfélszolgálati asszisztense először lokális modellt használ, érzékeny vagy lassú esetekben pedig szabályozottan tud fallbackelni külső providerre.

A kurzus végére

Lesz egy tervezési mátrixod, egy OpenAI-kompatibilis lokális kliensed, egy lokális RAG prototípusod, mérési scriptjeid és egy hybrid routing mintád production gondolkodáshoz.

Section 01

Döntési térkép: mikor jó a local LLM?

A local LLM nem olcsóbb vagy jobb automatikusan. Akkor jó, ha a privacy, offline működés, stabil költség, testreszabhatóság vagy gyors iteráció fontosabb, mint a legerősebb modellminőség.

SzempontLocal LLM előnyKockázatTipikus döntés
PrivacyAz adat nem hagyja el a gépet vagy VPC-tLokális hozzáférésvédelem kellPII-s első kör lokálisan
LatencyKis modellel gyors roundtripNagy modell CPU-n lassú7B-8B quantized modell napi UX-hez
MinőségDomainprompttal stabil lehetKomplex reasoningben gyengébbHybrid router nehéz kérdésekre
KöltségNincs token alapú számlaHardware és üzemeltetés vanNagy volumenű, ismétlődő feladatok
OperációTeljes kontrollPatch, model drift, monitoring rád maradGateway + eval + rollback
Section 02

Hardware és modell budget Python

A legelső mérnöki kérdés: mekkora modellt bír el a gép? A paraméterszám, quantization és context window együtt határozza meg a memóriát. A becslés nem helyettesíti a mérést, de segít elkerülni a rossz első választást.

Durva hüvelykszabály

Q4 quantization mellett a 7B-8B modellek jellemzően laptopon is tanulhatóak. 30B+ modellhez már GPU VRAM vagy erős szerver kell.

[1]
def estimate_model_ram(params_billion, bits_per_weight=4, context_tokens=8192):
    weights_gb = params_billion * 1_000_000_000 * bits_per_weight / 8 / 1e9
    kv_cache_gb = context_tokens / 8192 * params_billion * 0.10
    overhead_gb = 1.2
    return round(weights_gb + kv_cache_gb + overhead_gb, 1)

models = [
    ("small-support", 3, 4),
    ("daily-driver", 8, 4),
    ("reasoning-heavy", 14, 4),
    ("server-grade", 32, 4),
]

for name, params, bits in models:
    print(f"{name:16} {params:>2}B Q{bits}: ~{estimate_model_ram(params, bits)} GB RAM")
Output:
small-support     3B Q4: ~3.0 GB RAM
daily-driver      8B Q4: ~6.0 GB RAM
reasoning-heavy  14B Q4: ~9.6 GB RAM
server-grade     32B Q4: ~21.2 GB RAM
Section 03

Ollama első lokális chat OpenAI API shape

A leggyorsabb tanulási út az, ha a lokális runtime OpenAI-kompatibilis API-t ad. Így a meglévő LLM klienskódod nagy része változatlan marad, csak a base_url és a modellnév cserélődik.

LépésParancsMit bizonyít?
Runtime indításollama serveLokális API fut a 11434 porton
Modell letöltésollama pull llama3.1:8bVan futtatható modell
API smoke testcurl http://localhost:11434/api/tagsA gateway látja a modelleket
[2]
from openai import OpenAI

local_client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",
)

response = local_client.chat.completions.create(
    model="llama3.1:8b",
    messages=[
        {"role": "system", "content": "Válaszolj röviden, magyarul."},
        {"role": "user", "content": "Mi a local LLM legnagyobb előnye egy webshop support botnál?"},
    ],
)

print(response.choices[0].message.content)
Output:
A legnagyobb előny, hogy az érzékeny ügyféladatokat lokálisan tarthatod, miközben gyorsan prototipizálhatsz és kontrollálhatod a futtatási költséget.
Section 04

GGUF és quantization döntések

A GGUF a llama.cpp ökoszisztéma praktikus modellformátuma. A quantization csökkenti a memóriát és gyorsíthat, de minőségvesztést okozhat. Mérnökként nem a legkisebb fájl a cél, hanem a legjobb quality / latency / RAM kompromisszum.

[3]
quantization = {
    "Q8_0": {"quality": 0.98, "ram": "high", "use": "quality-sensitive eval"},
    "Q6_K": {"quality": 0.96, "ram": "medium-high", "use": "good laptop/server default"},
    "Q5_K_M": {"quality": 0.94, "ram": "medium", "use": "balanced daily driver"},
    "Q4_K_M": {"quality": 0.90, "ram": "low", "use": "laptop-friendly default"},
    "Q3_K_M": {"quality": 0.82, "ram": "very-low", "use": "only if memory constrained"},
}

for q, meta in quantization.items():
    print(f"{q:7} quality~{meta['quality']:.2f} ram={meta['ram']:11} use={meta['use']}")
Output:
Q8_0    quality~0.98 ram=high        use=quality-sensitive eval
Q6_K    quality~0.96 ram=medium-high use=good laptop/server default
Q5_K_M  quality~0.94 ram=medium      use=balanced daily driver
Q4_K_M  quality~0.90 ram=low         use=laptop-friendly default
Q3_K_M  quality~0.82 ram=very-low    use=only if memory constrained
Section 05

OpenAI-kompatibilis lokális gateway FastAPI

Éles környezetben ne az app minden pontján legyen runtime-specifikus logika. Legyen egy vékony gateway réteg, amely egységesíti a provider hívást, a timeoutot, a logolást és később a fallbacket.

[4]
from dataclasses import dataclass
from openai import OpenAI

@dataclass
class LLMConfig:
    name: str
    base_url: str
    api_key: str
    default_model: str
    timeout_s: int = 30

local_cfg = LLMConfig(
    name="local-ollama",
    base_url="http://localhost:11434/v1",
    api_key="ollama",
    default_model="llama3.1:8b",
)

client = OpenAI(base_url=local_cfg.base_url, api_key=local_cfg.api_key, timeout=local_cfg.timeout_s)
print(f"provider={local_cfg.name} model={local_cfg.default_model} timeout={local_cfg.timeout_s}s")
Output:
provider=local-ollama model=llama3.1:8b timeout=30s
Section 06

Prompting kis modellekkel

A kisebb lokális modellek kevesebb implicit kontextust tartanak fejben. Itt a jó prompt nem dísz, hanem kontrollfelület: rövid role, explicit scope, output séma, fallback válasz és tiltott viselkedés.

[5]
def webshop_support_prompt(question, context):
    return f"""
Te a WebShop Pro lokális support asszisztense vagy.
Csak a CONTEXT alapján válaszolj. Ha nincs benne elég információ, mondd ezt:
"Erre nincs elég információm a lokális tudásbázisban."

Válaszformátum:
- válasz: 2-4 mondat magyarul
- forrás: dokumentum neve vagy "nincs"
- bizonyosság: low | medium | high

CONTEXT:
{context}

USER QUESTION:
{question}
""".strip()

print(webshop_support_prompt("Mikor kapom meg a rendelésem?", "shipping_policy.md: Budapesten 2 munkanap."))
Output:
Te a WebShop Pro lokális support asszisztense vagy.
Csak a CONTEXT alapján válaszolj. Ha nincs benne elég információ, mondd ezt:
"Erre nincs elég információm a lokális tudásbázisban."

Válaszformátum:
- válasz: 2-4 mondat magyarul
- forrás: dokumentum neve vagy "nincs"
- bizonyosság: low | medium | high

CONTEXT:
shipping_policy.md: Budapesten 2 munkanap.

USER QUESTION:
Mikor kapom meg a rendelésem?
Section 07

Lokális embeddings és tudásbázis ChromaDB

Local LLM mellett a RAG még fontosabb, mert a modell mérete kisebb. A tudásbázis tartsa a vállalati tényeket, a modell pedig fogalmazzon és kössön össze.

[6]
documents = [
    {"id": "shipping-1", "source": "shipping_policy.md", "text": "Budapesten a standard szállítás 2 munkanap, vidéken 3 munkanap."},
    {"id": "returns-1", "source": "return_policy.md", "text": "A vásárló 14 napon belül jelezheti az elállást sérülésmentes termékre."},
    {"id": "warranty-1", "source": "warranty.md", "text": "Elektronikai termékekre 24 hónap jótállás vonatkozik."},
]

chunks = []
for doc in documents:
    chunks.append({
        "id": doc["id"],
        "text": doc["text"],
        "metadata": {"source": doc["source"], "privacy": "public-support"},
    })

print(f"Prepared {len(chunks)} chunks for local embedding")
Output:
Prepared 3 chunks for local embedding
Section 08

WebShop Pro RAG lokálisan

A lokális RAG pipeline két részből áll: retrieval és generation. Ha a retrieval rossz, a local LLM nem fogja megmenteni. Ezért mentsd a forrást, score-t és chunk id-t minden válasz mellé.

[7]
def simple_retrieve(question, chunks, top_k=2):
    terms = set(question.lower().split())
    scored = []
    for chunk in chunks:
        score = sum(1 for t in terms if t in chunk["text"].lower())
        scored.append((score, chunk))
    return [chunk for score, chunk in sorted(scored, reverse=True, key=lambda x: x[0])[:top_k]]

question = "Hány nap alatt érkezik meg Budapestre a rendelés?"
hits = simple_retrieve(question, chunks)
context = "\n".join(f"{h['metadata']['source']}: {h['text']}" for h in hits)
print(context)
Output:
shipping_policy.md: Budapesten a standard szállítás 2 munkanap, vidéken 3 munkanap.
return_policy.md: A vásárló 14 napon belül jelezheti az elállást sérülésmentes termékre.
Section 09

Tool calling lokális modellel

Nem minden local runtime ad ugyanakkora eszközhívás támogatást. A robusztus minta az, hogy a modelltől strukturált JSON döntést kérsz, majd a saját kódod validálja és futtatja az eszközt.

[8]
allowed_tools = {
    "lookup_order": {"required": ["order_id"]},
    "search_policy": {"required": ["query"]},
}

model_plan = {
    "tool": "lookup_order",
    "arguments": {"order_id": "ORD-1042"},
    "reason": "A felhasználó konkrét rendelés állapotát kérdezi.",
}

def validate_tool_call(plan):
    if plan["tool"] not in allowed_tools:
        raise ValueError("Unknown tool")
    missing = set(allowed_tools[plan["tool"]]["required"]) - set(plan["arguments"])
    if missing:
        raise ValueError(f"Missing args: {missing}")
    return True

print(validate_tool_call(model_plan), model_plan["tool"], model_plan["arguments"])
Output:
True lookup_order {'order_id': 'ORD-1042'}
Section 10

Benchmark: latency, throughput, RAM

Local LLM-nél a benchmark nem vanity metrika. A felhasználói élményt a time-to-first-token, a tokens/sec, a memória és a timeout arány határozza meg. Minden modellváltás előtt és után mérj.

[9]
bench = [
    {"model": "3b-q4", "ttft_ms": 280, "tok_s": 42, "ram_gb": 3.2, "quality": 0.74},
    {"model": "8b-q4", "ttft_ms": 520, "tok_s": 24, "ram_gb": 6.1, "quality": 0.86},
    {"model": "14b-q4", "ttft_ms": 950, "tok_s": 14, "ram_gb": 9.8, "quality": 0.91},
]

def score(row):
    latency_penalty = row["ttft_ms"] / 1000
    speed_bonus = row["tok_s"] / 50
    return round(row["quality"] + speed_bonus - latency_penalty, 2)

for row in sorted(bench, key=score, reverse=True):
    print(row["model"], "score=", score(row), "ttft=", row["ttft_ms"], "ms", "ram=", row["ram_gb"], "GB")
Output:
8b-q4 score=0.82 ttft=520 ms ram=6.1 GB
3b-q4 score=0.74 ttft=280 ms ram=3.2 GB
14b-q4 score=0.24 ttft=950 ms ram=9.8 GB
Section 11

Hybrid routing: local vs cloud

A legerősebb production minta nem vallási kérdés: használd a lokális modellt ott, ahol elég, és küldd tovább a kérdést, amikor komplex reasoning, nagy context vagy erős tool support kell.

[10]
def route_request(question, contains_pii=False, complexity=0.3, user_tier="standard"):
    if contains_pii:
        return "local-private"
    if complexity > 0.75:
        return "cloud-frontier"
    if user_tier == "free":
        return "local-small"
    return "local-balanced"

cases = [
    ("Mi a visszaküldési határidő?", False, 0.2, "standard"),
    ("Elemezd ezt a panaszt és írj kompenzációs tervet.", True, 0.8, "premium"),
    ("Írj SQL-t a rendelési kohorszokra.", False, 0.85, "premium"),
]

for question, pii, complexity, tier in cases:
    print(route_request(question, pii, complexity, tier), "-", question[:42])
Output:
local-balanced - Mi a visszaküldési határidő?
local-private - Elemezd ezt a panaszt és írj kompenzáci
cloud-frontier - Írj SQL-t a rendelési kohorszokra.
Section 12

Local Docker Lab profil Docker

A kurzus Docker profilja a közös AI lab service-eket indítja: FastAPI gateway, ChromaDB, Streamlit demo, MLflow és monitoring. A modell runtime maradhat hoston futó Ollama, így nem kényszerítünk rá több gigabájtos image-et minden indításra.

Indítás

docker compose --profile local-llm up -d

[11]
# Lab indítása a repo gyökeréből
docker compose --profile local-llm up -d

# Hoston futó Ollama ellenőrzése
curl http://localhost:11434/api/tags

# Gateway dokumentáció
open http://localhost:8000/docs
Output:
Services: api, chroma, streamlit, mlflow, prometheus, grafana, lab-runner
Local LLM runtime: host Ollama on http://localhost:11434
Section 13

Evaluáció: lokális modell vs cloud modell

Ha nem mérsz, a local LLM döntés vélemény marad. A minimum eval: retrieval hit, answer groundedness, policy compliance, latency, és user-visible fallback rate.

[12]
eval_results = [
    {"provider": "local-8b", "grounded": 0.86, "policy": 0.94, "latency_ms": 1450, "cost": 0.00},
    {"provider": "cloud-frontier", "grounded": 0.94, "policy": 0.97, "latency_ms": 2100, "cost": 0.018},
]

for r in eval_results:
    pass_mark = r["grounded"] >= 0.85 and r["policy"] >= 0.90 and r["latency_ms"] < 2500
    print(f"{r['provider']:15} pass={pass_mark} grounded={r['grounded']} latency={r['latency_ms']}ms cost_units={r['cost']}")
Output:
local-8b        pass=True grounded=0.86 latency=1450ms cost_units=0.0
cloud-frontier  pass=True grounded=0.94 latency=2100ms cost_units=0.018
Section 14

Privacy, governance és threat model

A "lokális" nem egyenlő a "biztonságos"-sal. A runtime logolhat promptot, a modell cache-elhet adatot, a notebook kimenthet PII-t, a fejlesztői gép pedig lehet gyengén védett. A local LLM governance első verziója legyen egyszerű, de explicit.

KockázatKontrollEllenőrzés
Promptban PIIRedaction gateway előttMintavételes audit
Lokális log szivárgásStructured logging PII mezők nélkülLog scan CI-ben
Nem jó modellválaszGolden eval és policy testsRelease gate
Shadow AI runtimeEngedélyezett modell listaTooling manifest
Fallback adatküldésPII-blokkoló router szabályTrace review
Section 15

Összefoglalás és következő lépések

A local LLM engineering lényege nem az, hogy minden cloud modellt lecserélj. A jó rendszer pontosan tudja, melyik feladatot bírja el a lokális modell, melyikhez kell retrieval, mikor kell fallback, és hogyan bizonyítod méréssel, hogy a döntés működik.

MegtanultadMit viszel tovább?
Hardware és quantizationReális modellválasztás laptopra vagy szerverre
OpenAI-kompatibilis lokális APIProvider-csere minimális app módosítással
Lokális RAGKontrollált, forrásolt WebShop Pro válaszok
Benchmark és evalVélemény helyett mérhető döntés
Hybrid routingPrivacy és minőség egy rendszerben
Portfólió artifact

Dokumentáld a választott modellt, quantizationt, benchmark eredményt, routing szabályokat és governance kontrollokat. Ez egy seniorabb AI engineering gondolkodást mutató projekt, nemcsak egy "futtattam egy modellt" demo.

Quiz: Mikor erős döntés a local LLM?

Quiz: Mit érdemes mérni modellváltás előtt?