Kako programi koriste gotove AI modele

Modul 3 · Lekcija 7 od 7 · Veštačka inteligencija

Velike modele niko ne trenira iznova za svaki program – trening traje danima i košta mnogo. Programi koriste gotove, već naučene modele. U ovoj lekciji naučićeš dva načina: kako da sačuvaš i ponovo koristiš svoj model i kako program „razgovara“ sa jezičkim modelom preko API-ja.

Deo o API-ju opisuje stanje iz novembra 2026. i ažurira se jednom godišnje.

Način 1: sačuvaj svoj model

Mreža iz prethodne lekcije uči nekoliko sekundi. Kod većih modela to traje mnogo duže, pa model posle treninga sačuvamo u fajl i kasnije ga samo učitamo. Za to služi biblioteka joblib, koja se instalira zajedno sa scikit-learn.

# Treniramo mrežu jednom i čuvamo je u fajl – posle je koristimo bez ponovnog učenja
import joblib                                   # dolazi uz scikit-learn
from sklearn.datasets import load_digits
from sklearn.neural_network import MLPClassifier

cifre = load_digits()
mreza = MLPClassifier(hidden_layer_sizes=(64,), max_iter=500, random_state=0)
mreza.fit(cifre.data / 16.0, cifre.target)      # učimo na svim slikama

joblib.dump(mreza, "model_cifre.joblib")        # čuvanje na disk
print("Model je sačuvan u fajl model_cifre.joblib")

Ispis programa:

Model je sačuvan u fajl model_cifre.joblib

Sada drugi program učitava model i odmah ga koristi – bez treninga. Cifru „crtamo“ brojevima od 0 do 16:

# Gotov model: učitavamo sačuvanu mrežu i prepoznajemo cifru koju smo sami „nacrtali“
import joblib

mreza = joblib.load("model_cifre.joblib")       # nema treninga – model je već naučen

# cifra 7 nacrtana brojevima od 0 (belo) do 16 (crno), 8 redova po 8 piksela
sedmica = [
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 4, 16, 16, 16, 16, 12, 0],
    [0, 0, 0, 0, 0, 14, 8, 0],
    [0, 0, 0, 0, 6, 15, 1, 0],
    [0, 0, 0, 0, 14, 8, 0, 0],
    [0, 0, 0, 6, 15, 1, 0, 0],
    [0, 0, 0, 13, 9, 0, 0, 0],
    [0, 0, 0, 15, 4, 0, 0, 0],
]
red = [p / 16.0 for vrsta in sedmica for p in vrsta]   # 64 broja u jednom redu, od 0 do 1

print("Mreža kaže:", mreza.predict([red])[0])
verovatnoce = mreza.predict_proba([red])[0]
najverovatnije = sorted(range(10), key=lambda c: -verovatnoce[c])[:3]
for c in najverovatnije:
    print(f"  cifra {c}: {verovatnoce[c] * 100:.1f} %")

Ispis programa:

Mreža kaže: 7
  cifra 7: 98.8 %
  cifra 2: 1.1 %
  cifra 3: 0.0 %

predict_proba daje verovatnoće za svaku cifru – mreža je 98,8 % „sigurna“ da je to sedmica. Ovako se modeli koriste i u aplikacijama: neko ih istrenira i sačuva, a aplikacija ih samo učitava.

Način 2: API – program pita model preko mreže

API (engl. application programming interface) je „dogovor“ kako jedan program traži nešto od drugog. Kod jezičkih modela to izgleda ovako:

  1. Naš program pošalje zahtev (npr. pitanje) na određenu adresu.
  2. Na toj adresi radi program sa modelom; on izračuna odgovor.
  3. Odgovor se vrati našem programu, obično u formatu JSON (tekst koji liči na Python rečnik).

Model može da radi na serveru kompanije (tada je potreban nalog i API ključ) ili na tvom računaru. Za školu je pogodniji drugi način: besplatan program Ollama pokreće otvorene jezičke modele lokalno, bez naloga i bez slanja podataka na internet.

Za nastavnike i starije učenike: Ollama i modeli zauzimaju nekoliko gigabajta i traže jači računar (preporučeno 8 GB RAM-a ili više). Instalaciju neka uradi nastavnik ili roditelj; mali model se preuzima komandom ollama pull llama3.2. Ako to nije moguće, lekciju možeš da pratiš i samo čitanjem – program radi i bez Ollame, samo ispiše poruku da Ollama nije pokrenut.
# Kako program koristi jezički model preko API-ja
# Primer radi sa programom Ollama, koji pokreće jezički model NA TVOM RAČUNARU (bez naloga).
# Pre pokretanja: instaliraj Ollama (ollama.com) i u terminalu pokreni:  ollama pull llama3.2
import json
import urllib.request

ADRESA = "http://localhost:11434/api/generate"   # Ollama sluša na tvom računaru (localhost)


def pitaj(pitanje, model="llama3.2"):
    """Pošalji pitanje modelu i vrati tekst odgovora."""
    zahtev = {"model": model, "prompt": pitanje, "stream": False}
    podaci = json.dumps(zahtev).encode("utf-8")
    req = urllib.request.Request(ADRESA, data=podaci, headers={"Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=120) as odgovor:
        rezultat = json.loads(odgovor.read().decode("utf-8"))
    return rezultat["response"]                  # tekst odgovora je u polju "response"


try:
    print(pitaj("Objasni u dve rečenice šta je neuronska mreža, za učenika 8. razreda."))
except OSError:
    print("Ollama nije pokrenut – proveri da li je instaliran i da li radi.")
  • json.dumps pretvara Python rečnik u JSON tekst; json.loads radi obrnuto.
  • "stream": False traži ceo odgovor odjednom (inače stiže reč po reč).
  • localhost znači „ovaj računar“ – zahtev ne izlazi na internet.
  • Odgovor modela je drugačiji pri svakom pokretanju – setimo se lekcije Kako rade četbotovi.

API ključ: lozinka koja se ne deli

Servisi na internetu traže API ključ – dugačku tajnu šifru po kojoj znaju ko šalje zahtev (i kome da naplate). Pravila:

  • ključ nikada ne piši direktno u kod koji deliš, šalješ ili postavljaš na internet (npr. na GitHub);
  • čuvaj ga u promenljivoj okruženja ili posebnom fajlu koji ne deliš;
  • ako ključ „procuri“ – odmah ga obriši u podešavanjima servisa i napravi novi.
# ključ se čita iz promenljive okruženja, a ne piše se u kod
import os

kljuc = os.environ.get("AI_API_KLJUC")
if kljuc is None:
    print("Postavi promenljivu okruženja AI_API_KLJUC.")

Za učenike mlađe od 18 godina nalozi na komercijalnim AI servisima često zahtevaju saglasnost roditelja ili nisu dozvoljeni – zato u ovom kursu koristimo sopstvene i lokalne modele.

Za čas (nastavnicima): trajanje 45 minuta; pribor: računari; za drugi deo jedan računar sa Ollamom (nastavnikov).
Prvi deo (čuvanje i učitavanje modela) rade svi učenici. Drugi deo nastavnik pokazuje na projektoru: učenici predlažu pitanja, a zatim zajedno proveravaju tačnost odgovora.

Česte zablude

  • „Program „sadrži“ AI čim koristi API“ – program samo šalje pitanje modelu koji radi negde drugde i prikazuje odgovor.
  • „API ključ je kao korisničko ime – može da se pokaže“ – ključ je tajna, kao lozinka; ko ga ima, može da koristi tvoj nalog.

Zadaci za vežbu

Pokušaj prvo sam, pa tek onda otvori rešenje.

  1. „Nacrtaj“ cifru 1 brojevima od 0 do 16 i proveri šta kaže sačuvani model. Probaj tanku i debelu liniju.
  2. Napravi mali „četbot“ u terminalu: program u petlji čita pitanje (input) i šalje ga lokalnom modelu, dok korisnik ne upiše „kraj“.
  3. Zašto API ključ ne sme da se upiše u kod koji postavljaš na GitHub?
Rešenje 1: jedinica
# Zadatak: nacrtaj cifru 1 i proveri šta kaže sačuvani model
import joblib

mreza = joblib.load("model_cifre.joblib")

tanka = [                                   # jedinica nacrtana tankom linijom
    [0, 0, 0, 0, 12, 0, 0, 0],
    [0, 0, 0, 10, 16, 0, 0, 0],
    [0, 0, 8, 6, 16, 0, 0, 0],
    [0, 0, 0, 0, 16, 0, 0, 0],
    [0, 0, 0, 0, 16, 0, 0, 0],
    [0, 0, 0, 0, 16, 0, 0, 0],
    [0, 0, 0, 0, 16, 0, 0, 0],
    [0, 0, 0, 8, 16, 8, 0, 0],
]
debela = [                                  # ista jedinica, debljom linijom – kao u podacima za učenje
    [0, 0, 0, 12, 13, 0, 0, 0],
    [0, 0, 6, 16, 16, 0, 0, 0],
    [0, 0, 10, 14, 16, 0, 0, 0],
    [0, 0, 0, 8, 16, 0, 0, 0],
    [0, 0, 0, 8, 16, 0, 0, 0],
    [0, 0, 0, 8, 16, 0, 0, 0],
    [0, 0, 0, 8, 16, 0, 0, 0],
    [0, 0, 0, 10, 16, 6, 0, 0],
]
for ime, slika in [("tanka", tanka), ("debela", debela)]:
    red = [p / 16.0 for vrsta in slika for p in vrsta]
    print(f"{ime} jedinica -> mreža kaže: {mreza.predict([red])[0]}")

Ispis programa:

tanka jedinica -> mreža kaže: 3
debela jedinica -> mreža kaže: 1

Tanku jedinicu mreža proglasi za trojku! U skupu podataka za učenje jedinice su pisane debelom linijom, pa model „ne prepoznaje“ drugačiji rukopis. Ovo je isti problem kao kod Teachable Machine: model zna samo ono što je video u podacima.

Rešenje 2: četbot u terminalu
# Zadatak: mali „četbot“ u terminalu – pitanja se šalju lokalnom modelu dok ne upišeš „kraj“
import json
import urllib.request


def pitaj(pitanje, model="llama3.2"):
    zahtev = json.dumps({"model": model, "prompt": pitanje, "stream": False}).encode("utf-8")
    req = urllib.request.Request("http://localhost:11434/api/generate", data=zahtev,
                                 headers={"Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=120) as odgovor:
        return json.loads(odgovor.read().decode("utf-8"))["response"]


while True:
    pitanje = input("Ti: ")
    if pitanje.strip().lower() == "kraj":
        break
    try:
        print("Model:", pitaj(pitanje))
    except OSError:
        print("Ollama nije pokrenut.")
        break

Ako Ollama nije pokrenut, program ispisuje poruku i završava – ne „puca“, jer grešku hvata try … except OSError.

Rešenje 3: objašnjenje

Zato što ga tada može pročitati bilo ko i koristiti tvoj nalog – na tvoj račun. Ključ se čuva u promenljivoj okruženja ili u fajlu koji se ne deli, a procureli ključ se odmah poništava.

Šta dalje

Završio si modul Programiranje veštačke inteligencije u Pythonu. U sledećem modulu veštačka inteligencija izlazi iz računara: AI i Internet stvari – ESP32 i micro:bit prikupljaju podatke, a modeli donose odluke. Do tada pogledaj kurs Arduino i ESP32.

Proveri znanje

Otvori kviz

Kviz: gotovi modeli i API

1. Čemu služi joblib.dump?




2. Šta je API?




3. Gde treba čuvati API ključ?




4. Zašto je mreža tanku jedinicu proglasila za trojku?