MODUL 2 - LEKCIJA 2

Lokalni LLM: Ollama Deep Dive

100% Offline AI asistenti unutar Data Centra kompanije — instalacija, konfiguracija i vlastiti custom modeli

⏱️ Trajanje: 1h 45min (11:15 - 13:00) 📚 Nivo: Srednji 🎯 Lab: Custom Modelfile i REST API Integracija

Upoznavanje sa Ollama

Ollama je open-source alat koji apstrahuje kompleksnost pokretanja LLM modela na lokalnom hardveru. Analogija: kao što Docker apstrahuje kompajliranje i konfiguriranje serverskog softvera, Ollama apstrahuje C++ kompajliranje GGUF biblioteka i CUDA podešavanje za AI modele. Jedna komanda umjesto tjedna konfiguriranja.

Arhitektura Lokalnog LLM-a (Ollama) Vaša Aplikacija Python Script Chatbot UI C# / .NET REST API :11434 Ollama Service REST Endpoint Model Manager llama.cpp Engine Inference Hardver RAM CPU Execution VRAM GPU/Apple

🖥️ Zašto Lokalni Model? (Privatnost Podataka)

Iz Modula 2.1 znamo finansijsku stranu priče. Ali postoji i kritična tehnička strana: šta se dešava s podacima koje šaljete cloud API-jevima?

Lokalni model = nulta razmjena podataka s vanjskim serverima. Sve ostaje unutar vaše mreže.

🗜️ Quantizacija — Kako Fitovati 70B Model na Laptop

📌 Šta je Quantizacija?

U normalnom FP32 (32-bit floating point) preciznosti, svaki parametar neuronske mreže zauzima 4 Bajta. U FP16 (16-bit float) — 2 Bajta. Llama 3 70B model ima 70 milijardi parametara — u FP16 to je: 70 × 10⁹ × 2 B = 140 GB! Nema tipičnog server-a koji može to fitovati u VRAM.

Quantizacija je tehnika koja smanjuju preciznost parametara — umjesto punog decimal broja (1.91647832...) čuva zaokruženu vrijednost (1.92). Ovo smanjuje memoriju ali uvodi mali gubitak kvaliteta.

Nivoi quantizacije:

  • FP16 (16-bit): 2B/parametar. Originalna preciznost. Potrebno ~140GB za 70B model.
  • Q8 (8-bit): 1B/parametar. Zanemariv gubitak kvaliteta. ~70GB za 70B.
  • Q4 (4-bit): 0.5B/parametar. Vidljiv ali prihvatljiv gubitak. ~35GB za 70B.
  • Q3/Q2: <0.4B/parametar. Primjetan gubitak. Korisno za edge uređaje.

Konkretno za Llama 3.1 8B: Kvantiziran na Q4 — samo ~4.5 GB RAM/VRAM. Radi na prosječnom gaming laptopu ili Office PC-u s 16GB RAM-a!

🗂️ GGUF Format — Standardni Container za Quantizirane Modele

GGUF (GPT-Generated Unified Format) je datotečni format (.gguf ekstenzija) koji je razvio llama.cpp projekt. Packuje sve što model treba u jedan fajl: kvantizovane težine, tokenizer rječnik, arhitekturalne metadatke i konfiguraciju.

Ollama automatski preuzima GGUF verzije modela i optimizuje ih za vaš hardver — koristi GPU ako je dostupan, CPU i RAM ako nema GPU-a, a može koristiti i Metal (Apple Silicon GPU) na Mac računarima.

💡 Analogija: Docker za AI Modele

Bez Ollame, pokretanje LLM-a na Windows/Linux serveru zahtijeva: instalacja CUDA drivera, kompajliranje llama.cpp C++ biblioteke, preuzimanje GGUF fajlova, ručno pisanje inferecijskog koda sa ispravnim parametrima. Složenost za IT admina koji nije C++ developer: vanredno visoka.

Sa Ollama: ollama run llama3.1 — jedna komanda preuzima model, optimizuje za vaš hardver, i pokreće interaktivni chat unutar 60 sekundi. Isto kao docker pull nginx!

⚙️

LAB O5: Instalacija i Konfiguracija Ollama

U ovom labu instaliramo Ollama, pokrećemo prvi lokalni LLM u terminalu, i upoznajemo sve važne komande za upravljanje modelima.

1

Instalacija Ollama Engine-a

Windows:

  1. Otvorite browser i idite na ollama.com
  2. Kliknite "Download" → preuzmite Windows installer (OllamaSetup.exe, ~100MB)
  3. Pokrenite installer (administratorski pristup nije obavezan)
  4. Ollama se instalira i automatski starta kao background Windows Service na portu 11434
  5. Provjerite instalaciju u PowerShell-u:
powershell
# Provjera instalacije
ollama --version
# Trebate vidjeti: "ollama version 0.x.x"

# Provjera da li servis radi (Ollama REST API)
curl http://localhost:11434
# Trebate vidjeti: "Ollama is running"

Linux (Ubuntu/Debian — za server deployment):

bash
# Zvanični install script (za lab okruženje)
curl -fsSL https://ollama.com/install.sh | sh

# Za produkciju preporučujemo: manual install + systemd service
# (detalji na: github.com/ollama/ollama/blob/main/docs/linux.md)

# Provjera systemd servisa
sudo systemctl status ollama
# Trebate vidjeti: Active: active (running)
2

Preuzimanje i Pokretanje Prvog Modela

Koristit ćemo Llama 3.1 8B model u 4-bit quantizaciji — odličan balans između veličine (~4.7GB) i inteligencije za lab okruženje:

powershell
# Preuzimanje i pokretanje modela
# Ako model nije preuzet, Ollama automatski skida sa svog Huba (~4.7GB)
# Progress bar se prikazuje tokom downloada
ollama run llama3.1

# Kada se preuzme, pojavit će se prompt za interaktivni chat:
# >>> Napiši bash skriptu koja prati disk usage i šalje email upozorenje kada pređe 90%
# (model će napisati skriptu... 100% lokalno!)

# Izlaz iz chat-a:
# >>> /bye

Ako nemate dovoljno prostora na disku (trebate ~5GB slobodnih): Koristite manji model: ollama run llama3.2:1b (~1.3GB download).

3

Pregled Svih Bitnih Ollama Komandi

Ollama se koristi kao CLI (Command Line Interface) tool. Evo tablice svih komandi:

Komanda Opis Analogija (Docker)
ollama run MODEL Start interaktivni chat sa modelom (download ako nije lokalno) docker run -it IMAGE
ollama pull MODEL Preuzimanje modela bez pokretanja docker pull IMAGE
ollama list Prikaz svih lokalno preuzetih modela docker images
ollama ps Modeli koji su trenutno učitani u RAM/VRAM docker ps
ollama show MODEL Detalji o modelu (veličina, arhitektura, parametri) docker inspect IMAGE
ollama rm MODEL Brisanje modela sa diska docker rmi IMAGE
ollama create NAME -f FILE Kreiranje custom modela iz Modelfile-a docker build -t NAME -f FILE .
ollama serve Eksplicitno pokretanje Ollama REST servera docker run -p 11434:11434 ...
powershell
# Prikaz liste preuzetih modela
ollama list
# NAME                    SIZE    MODIFIED
# llama3.1:latest         4.7 GB  2 minutes ago

# Detalji o modelu
ollama show llama3.1
# Model  llama3.1:latest
# Architecture  llama
# Parameters    8.0B
# Quantization  Q4_0
# Context       131072 tokens

# Provjera RAM usage dok model radi (u novom terminal prozoru)
ollama ps
# NAME            ID              SIZE      PROCESSOR    UNTIL
# llama3.1:latest ...             5.1 GB    100% CPU     4 minutes from now

# Brisanje modela (oslobađanje prostora na disku)
# ollama rm llama3.1
4

Ollama REST API — Spajanje sa Vlastitim Kodom

Ollama ne samo da pruža CLI chat — pokrenuti je kao REST API server na portu 11434. Ovo ga čini integrisanim u vaš Python/C#/.NET/Node.js kod bez ikakvih cloud API ključeva.

Napravite fajl ollama_client.py:

python
"""
ollama_client.py - Komunikacija sa lokalnim Ollama API-jem
Demonstrira OpenAI-kompatibilni API format koji Ollama podržava
"""

import requests
import json

# Ollama lokalni endpoint (ne treba internet niti API ključ!)
OLLAMA_URL = "http://localhost:11434"

def provjeri_ollama_status():
    """Provjera da li Ollama servis radi."""
    try:
        r = requests.get(f"{OLLAMA_URL}/", timeout=5)
        return r.status_code == 200
    except:
        return False

def lista_modela():
    """Vraća listu svih lokalno dostupnih modela."""
    r = requests.get(f"{OLLAMA_URL}/api/tags")
    models = r.json().get("models", [])
    return [(m["name"], m["size"]) for m in models]

def chat_sa_modelom(model: str, system_prompt: str, user_message: str) -> str:
    """
    Šalje Chat Completion zahtjev Ollama API-ju.
    Format je identičan OpenAI API-ju!
    """
    payload = {
        "model": model,
        "stream": False,  # Čekamo kompletan odgovor (za demonstraciju)
        "messages": [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_message}
        ],
        "options": {
            "temperature": 0.2,    # Niski temperature za tehničke odgovore
            "num_ctx": 4096,       # Context window limit (smanjujemo za brzinu)
            "num_predict": 500     # Max output tokena (Ollama terminologija)
        }
    }

    response = requests.post(
        f"{OLLAMA_URL}/api/chat",
        json=payload,
        timeout=120  # LLM inference može trajati duže na CPU-u
    )

    data = response.json()
    return data["message"]["content"]

def streaming_chat(model: str, user_message: str):
    """
    Streaming verzija — prikazuje tokene čim se generišu.
    Bez ovoga, na CPU-u bismo čekali 30-60 sekundi bez ikakvog outputa.
    """
    payload = {
        "model": model,
        "stream": True,  # Streaming MODE aktiviran!
        "messages": [
            {"role": "user", "content": user_message}
        ]
    }

    # requests stream=True drži vezu otvorenom i čita chunks
    with requests.post(f"{OLLAMA_URL}/api/chat", json=payload, stream=True) as r:
        for line in r.iter_lines():
            if line:
                chunk = json.loads(line)
                if not chunk.get("done", False):
                    # Svaki chunk sadrži jedan token (djelić teksta)
                    token = chunk["message"]["content"]
                    print(token, end="", flush=True)  # flush=True za real-time ispis
    print()  # Novi red na kraju


# ================================================================
# DEMO PROGRAM
# ================================================================

if __name__ == "__main__":
    print("🦙 Ollama Python Klijent Demo\n")

    # Provjera statusa
    if not provjeri_ollama_status():
        print("❌ Ollama servis nije pronađen na localhost:11434!")
        print("   Pokrenite Ollama aplikaciju i pokušajte ponovo.")
        exit(1)

    print("✅ Ollama servis radi!\n")

    # Lista modela
    modeli = lista_modela()
    if not modeli:
        print("⚠️  Nema preuzetih modela. Pokrenite: ollama pull llama3.1")
        exit(1)

    print("📋 Lokalno dostupni modeli:")
    for ime, velicina in modeli:
        print(f"   - {ime} ({velicina / (1024**3):.1f} GB)")

    # Koristimo prvi dostupni model
    model = modeli[0][0]
    print(f"\n🤖 Koristim model: {model}\n")

    # Test 1: Obična chat komunikacija
    print("="*60)
    print("TEST 1: Standardni poziv (čeka na kompletan odgovor)")
    print("="*60)

    odgovor = chat_sa_modelom(
        model=model,
        system_prompt="Ti si senior Linux sistem administrator. Odgovaraj kratko, samo konkretni odgovori.",
        user_message="Koja naredba prikazuje live CPU usage po svakoj jezgri?"
    )
    print(f"Odgovor:\n{odgovor}")

    # Test 2: Streaming poziv
    print("\n" + "="*60)
    print("TEST 2: Streaming poziv (tokeni se pojavljuju u real-time)")
    print("="*60)
    print("Odgovor (streaming):")
    streaming_chat(
        model=model,
        user_message=(
            "Objasni u 3 kratke tačke: šta je Docker i kako pomaže "
            "DevOps timu u svakodnevnom radu?"
        )
    )
powershell
# Aktivacija venv i pokretanje
.\venv\Scripts\Activate.ps1
pip install requests  # Ako nije instalirano
python ollama_client.py
  • Na CPU-u (bez GPU-a), model generiše 3-8 tokena u sekundi. Bez streaming moda, morali biste čekati 30-70 sekundi u tišini. Streaming prikazuje odgovor odmah.
  • Veći model (Llama 3.1 70B na CPU) može biti drastično sporiji — 0.5-1 token/sekundi. Za produkcijsku upotrebu s više korisnika — obavezno GPU!
  • Primjetan ste da format API poziva (model, messages, temperature) je identičan OpenAI formatu koji smo koristili u Lekciji 1.3. Ovo je namjerno — Ollama je OpenAI-kompatibilan, omogućujući lak switch između cloud i lokalne varijante.
📝

LAB O6: Kreiranje Vlastitog "Modelfile"-a — Company AI Agent

Kao što Dockerfile apstrahuje softver i konfiguraciju u reproducibilni build, Modelfile apstrahuje LLM konfiguraciju u reproducibilni AI "agent". Možete definisati: koji base model koristiti, koje parametre zaključati, i koji system prompt ugraditi — i sačuvati kao novu verziju modela u Ollama registru.

Modelfile: Apstrakcija LLM Agenta FROM llama3.1 PARAMETER temp 0.1 SYSTEM "...prompt..." ollama create Lokalni Model "it-agent" ⚙️ REST API App Aplikacija samo komunicira s modelom, sva logika je enkapsulirana u 'it-agent'!
1

Kreiranje Modelfile-a

U VS Code-u, otvorite AI_Kurs folder i napravite fajl tačno pod imenom Modelfile (bez ekstenzije!). Unesite sljedeće:

dockerfile
# Modelfile — Definicija Custom Company LLM Agenta
# Sintaksa je identična Dockerfile formatu radi familijarnosti

# FROM: Koji bazni model koristimo kao osnovu
# Svi ostali slojevi "nadgrađuju" ovaj model
FROM llama3.1

# PARAMETER: Zaključavamo hiperparametre modela
# Ovo sprječava korisnike da mijenjaju ponašanje putem API poziva
PARAMETER temperature 0.1     # Strogo deterministički odgovori (IT kontekst)
PARAMETER top_p 0.9           # Nucleus sampling za raznovrsnost rječnika
PARAMETER num_ctx 8192         # Context window (8k tokena = dovoljno za tehniku)
PARAMETER num_predict 600      # Maksimum output tokena (troškovni limit)
PARAMETER repeat_penalty 1.1  # Blaga penalizacija za ponavljanje fraza

# SYSTEM: Sistemski prompt. Ovo je "duša" i "karakter" vašeg agenta.
# Ugradite ograničenja ponašanja, identitet, i specifičan kontekst
SYSTEM """
Ti si 'NETKO' — Interni IT Asistent kompanije Edukacija d.o.o.
Tvoj puni naziv je Network and Technical Knowledge Operator.

=== TVOJA ULOGA ===
Pomažeš IT timu i zaposlenicima sa tehničkim pitanjima iz oblasti:
- Linux i Windows Server administracija
- Docker i Kubernetes container orchestracija
- PowerShell i Bash skriptovanje
- Mrežna infrastruktura (switching, routing, firewall)
- Microsoft Azure i AWS cloud servisi
- SQL i NoSQL baze podataka
- Python i C# backend razvoj

=== TVOJA OGRANIČENJA ===
- Nikada ne odgovaraj na pitanja van IT infrastrukturnog domena
- Nikada ne diskutuj o politici, sportu, zabavi, kulinarsVu
- Ako korisnik pita nešto van okvira, odgovori ISKLJUČIVO:
  "Kao NETKO asistent, ta tema prevazilazi moj domenski opseg.
   Molim vas kontaktirajte odgovarajući odjel."

=== STIL KOMUNIKACIJE ===
- Odgovaraj na bosanskom jeziku
- Budi koncizan — ne pišite eseje gdje odmara komanda
- Uvijek navedi izvršne komande/kodove za konkretna rješenja
- Navedi potencijalne rizike gdje su relevantni
"""
2

Build i Deploy Custom Modela

U terminalu, pozicionite se u folder gdje je Modelfile i pokrenite:

powershell
# Kreiranje custom modela
# -f Modelfile = koristimo Modelfile iz trenutnog direktorija
ollama create netko-ai -f Modelfile

# Trebate vidjeti:
# transferring model data
# creating new layer sha256:...
# creating new layer sha256:...
# writing manifest
# success

# Provjera da li je model kreiran
ollama list
# NAME                    SIZE    MODIFIED
# llama3.1:latest         4.7 GB  5 minutes ago
# netko-ai:latest         4.7 GB  Just now   ← VAŠ CUSTOM MODEL!
3

Testiranje Agenta

powershell
ollama run netko-ai

# TEST 1: U domenu (trebalo bi odgovoriti profesionalno)
>>> Moj Docker kontejner ne može pristupiti bazi podataka. Dobivam "connection refused" grešku.
# Očekivani odgovor: detaljna dijagnoza mrežnih problema u Dockeru

# TEST 2: Van domene (treba odgovoriti sa "domenski opseg" porukom)
>>> Koji je recept za dobar burek?
# Očekivani odgovor: "Kao NETKO asistent, ta tema prevazilazi moj domenski opseg..."

# TEST 3: Granica domene (treba odbiti)
>>> Ko je pobijedio na zadnjim izborima?
# Očekivani odgovor: referisanje na ograničenje

# Izlaz
>>> /bye
  • Primjetan ste da model odriče odgovore izvan IT domene zahvaljujući System Promptu. Ovo je osnova izrade poslovnih AI agenata — usmjeravanje generičk og modela u specijalizovani asistent.
  • Temperature 0.1 čini odgovore konzistentnim — isti upit gotovo uvijek daje isti odgovor. Ovo je ključno za podršku korisnicima: pouzdanost je važnija od kreativnosti.
  • Deployment u firmi: Jednom kada je netko-ai model kreiran, može se ollama push na privatni Ollama registry (self-hosted) i ollama pull netko-ai na svim kompanijskim računarima/serverima. Distribucija custom modela po mreži bez cloud-a!

✅ Checkpoint — Provjera Razumijevanja

  • Quantizacija smanjuje preciznost parametara da bi model fitovao u manje RAM/VRAM.
  • GGUF format = standardni kontejner za kvantizovane LLM modele (analogija: Docker Image).
  • Ollama apstrahuje kompleksnost — jedna komanda za download, konfigurisanje i pokretanje modela.
  • Ollama REST API (port 11434) je OpenAI-kompatibilan — isti SDK, drugi URL.
  • Modelfile je "DNA" custom agenta: base model + temperature + system prompt = specijalizirani AI.
  • Streaming mode je obavezan za dobro UX pri sporoj CPU inferenciji.

✅ Zaključak

Ovaj model sada stanuje u vašem sistemu i podešen je za specifičan poslovni kontekst. Da bi model uopšte uspio procesirati zahtjeve, iza kulisa troši gigabajte sistemske (RAM) ili grafičke (VRAM) memorije. Ali koliko tačno i zašto? Upravo to ulazimo u sljedećoj lekciji — matematiku GPU/VRAM potreba!