🔤 Šta Model Zapravo Vidi?
U prethodnoj lekciji (Modul 1.1) učili smo o Transformer arhitekturi i tenzorima. Rekli smo da se tokeni pretvaraju u embedding vektore. Ali kako tačno tekst koji pišete postaje token ID-evi? Ovaj proces je tokenizacija i od nje direktno zavise:
- Koliko ćete platiti za AI API pozive (plaćate po tokenu, ne po znaku)
- Koliko teksta možete poslati odjednom (Context Window limit se mjeri u tokenima)
- Zašto bosanski jezik "košta više" od engleskog pri korištenju komercijalnih modela
📌 Definicija: Token
Token je osnovna jedinica teksta kojom LLM operira. To nije uvijek cijela riječ — može biti dio riječi, cijela riječ, interpunkcija ili čak whitespace (razmak, novi red). Svaki model ima fiksan rječnik (Vocabulary) — listu svih mogućih tokena koje zna. GPT-4 ima rječnik od ~100,000 tokena. Llama 3 ima ~128,000.
Svaki token ima jedinstven Integer ID (redni broj u rječniku). Model ne vidi tekst — vidi niz Integer-a.
Vizualna Demonstracija Tokenizacije
Zamislimo da GPT tokenizira rečenicu na engleskom — česte riječi postaju jedan token:
Engleski (čest, bogat rječnik):
→ 6 tokena za 5 engleskih riječi (~1.2 tokena/riječ)
Bosanski (rjeđi u trening podacima, slova š/č/ć razbijaju BPE):
→ 11 tokena za iste 3 bosanske riječi (~3.7 tokena/riječ)
🔴 Ista poruka, ali skoro 2× više tokena = 2× veći trošak + manje prostora u context window-u!
🧩 Byte-Pair Encoding (BPE) — Algoritam iza Tokenizacije
Gotovo svi moderni LLM-ovi (GPT-4, Claude, Llama 3, Mistral) koriste BPE tokenizaciju. Razumijevanje ovog algoritma objašnjava zašto neki jezici imaju više tokena od drugih.
📌 Šta je BPE (Byte Pair Encoding)?
BPE je kompresijski algoritam koji je originalno izmišljen za kompresiju podataka (1994.), a zatim adaptiran za NLP (2016.). Princip rada:
Korak 1 — Inicijalizacija: Počnemo sa svim pojedinačnim karakterima kao tokenima (a, b, c, ..., š, č, ć, ...). Svaki karakter = 1 token.
Korak 2 — Iterativno spajanje: Pronađi par znakova koji se najčešće pojavljuje zajedno u trening podacima i spoji ih u novi token. Ponavljaj.
Korak 3 — Zaustavljanje: Stani kada dostigneš željenu veličinu rječnika (npr. 100,000 tokena).
💡 Analogija: Pakovanje kofera za put
Zamislite da trebate spakovati kofer i prevoznik vam naplaćuje let po broju ubačenih predmeta (to je API naplata po Tokenu). Standardne česte stvari na engleskom jeziku ("the", "and") su kao majice - model ih smota u jedan komad i ubaci (1 token). Rijetke ili kompleksne riječi na bosanskom jeziku (npr. "preopterećen") model nije stigao naučiti izolovati. Model zato takve riječi rastavlja na manje djeliće iz svog kalupa: "pre" - "opt" - "ere" - "ć" - "en". Umjesto jedne smotane majice, sada u kofer gurate 5 odvojenih predmeta, što zauzima više mjesta u koferu (Context Window limit) i košta više na vagi (Naplata API-ja).
Trening korpus (milijarde Web stranica, knjiga, koda...):
...the, therapy, then, there, these, theory, theme...
...the the the... (najčešći par: t+h)
Iteracija 1: "t" + "h" → "th" (postaje jedan token)
Iteracija 2: "th" + "e" → "the" (postaje jedan token)
Iteracija 3: "the" + " " → "the " (postaje jedan token)
...
Nakon 100,000 iteracija → rječnik od 100,000 tokena
Rezultat za engleski: "the" je 1 token (viđeno milionima puta u treningu)
Rezultat za "preopterećen": nema u rječniku kao cijela riječ →
razbija se na: "pre" + "opt" + "er" + "e" + "ć" + "en" = 6 tokena
(jer "ć" je rijetko u trening podacima i nije formirano kao čest par)
🔑 Praktični zaključak za IT Inženjere i Arhitekte
💰 Troškovi API-ja: Modele u cloudu (OpenAI, Anthropic, Google) plaćate po procesiranom tokenu, a ne po broju znakova ili rijedi. GPT-4o trenutno košta $5.00 za 1 Milion Input tokena i $15.00 za 1 Milion Output tokena (april 2025).
📏 Context Window limit: Veličina "radne memorije" modela mjeri se u tokenima. Tekst koji šaljete (prompt) + historija razgovora + odgovor modela — sve mora stati u ovaj limit.
🌐 Dizajn System Promptova: Interne instrukcije AI-ju (system prompt) koje definišete pri izgradnji AI sistema uvijek pišite na engleskom — trošak je 2-4x manji, a model bolje razumije engleski. Output neka bude na bosanskom samo ako korisnik to traži.
🧠 Context Window — Radna Memorija Modela
Context Window (Kontekstni prozor ili Kontekstni limit) je ukupan broj tokena koji model može "vidjeti" i "misliti o" istovremeno u jednom pozivu. Uključuje:
VISUALIZACIJA CONTEXT WINDOW (npr. 128,000 tokena):
┌──────────────────────────────────────────────────────────────────────┐
│ [SYSTEM PROMPT: 500 tok] [USER: poruka 1: 200 tok] [ASSISTANT: odg 1: 300 tok] │
│ [USER: poruka 2: 150 tok] [ASSISTANT: odg 2: 250 tok] ... [DOKUMENT: 8000 tok] │
│ ↑ sve ovo su INPUT tokeni koje plaćate │
│ [NOVI OUTPUT: max_tokens podešeni od vas: npr 1000 tok] │
└──────────────────────────────────────────────────────────────────────┘
Ukupno: moraju stati u 128,000 tokena limit
Poređenje Context Window Kapaciteta kod Popularnih Modela (2025)
| Model | Context Window | Otprilike u A4 Stranicama | Input Cijena ($/1M tok.) |
|---|---|---|---|
| GPT-4o (OpenAI) | 128,000 tokena | ~ 300 stranica teksta | $5.00 |
| Claude 3.5 Sonnet (Anthropic) | 200,000 tokena | ~ 500 stranica / cca 6h koda | $3.00 |
| Google Gemini 1.5 Pro | 2,000,000 tokena | Masivni repozitoriji, 1h videa | $3.50 |
| Llama 3.1 70B (Meta, Open-Source) | 128,000 tokena | ~ 300 stranica | Besplatno (lokalno) |
| Mistral Large 2 (Open-Source) | 128,000 tokena | ~ 300 stranica | Besplatno (lokalno) |
💡 Analogija: Context Window kao Radna Ploča (Desk)
Zamislite da imate fizički radni sto (desk) ograničene veličine za rješavanje zadatka. Sve što stavite na njega — uputstva za rad (System Prompt), pristigli dokumenti, i historija razgovora sa klijentom — mora tu stati istovremeno da biste mogli raditi.
Kada se stol u potpunosti popuni starim papirima i listovima, novi papiri će jednostavno pasti na pod. Vi ih više ne vidite! Mreža ne može pročitati ništa što je "palo sa stola" — odnosno prešlo kapacitet zadatog Context Window-a. LLM nema dugoročno skriveno sjećanje kao mi; svaki novi API poziv model započinje potpuno iznova usred apnezije, samo s onih papirima koji su trenutno na stolu (u token listi).
Sliding Window Strategija — Upravljanje Dugim Razgovorima
Kada razvijate AI chatbot koji treba pamtiti dugačke razgovore (npr. korisnička podrška koja se odvija danima), historija razgovora će preći limit context window-a.
Strategija kojom vaš backend kod briše najstarije poruke i čuva najnovije naziva se Sliding Window:
Historija razgovora (svaka poruka ima broj tokena):
[SYSTEM]: "Ti si IT asistent..." (300 tok) ← NIKAD ne brišemo!
[User 28 dana}: Poruka 1: 200 tok ← 🗑️ BRIŠI (najstarija)
[AI]: Odg 1: 300 tok ← 🗑️ BRIŠI
[User]: Poruka 2: 150 tok ← 🗑️ BRIŠI
[AI]: Odg 2: 400 tok ← 🗑️ BRIŠI
... (50 poruka starica)
[User]: Poruka 51: 200 tok ← ✅ Čuvamo (noviji razgovor)
[AI]: Odg 51: 350 tok ← ✅ Čuvamo
[User]: NOVO pitanje: 180 tok ← ✅ Ovo je zadnje pitanje!
Strategija: Kada historija pređe ~80% context limita,
brišemo najstarije PAROVE poruka (user+assistant)
dok ne ostanemo ispod limita. System prompt se NIKAD ne briše.
⚠️ Šta znači brisanje historije za korisnika?
Ako korisnik kaže "Shodno onome što smo pričali juče...", a te poruke su obrisane iz historije — AI neće "pamtiti" taj razgovor. Ovo nije greška AI-ja, to je matematička granica context window-a.
Rješenje (napredni dizajn): RAG (Retrieval Augmented Generation) — arhitektura gdje se relevantni dijelovi starijih razgovora pretražuju i ubacuju u prompt po potrebi. Ovo ćemo učiti u Modulu 6.
✅ Checkpoint — Provjera Razumijevanja
-
Pitanje: Šta je razlog što engleska rečenica "I am going home" treba oko 4
tokena, a ista na bosanskom "Ja idem kući" može uzeti 7-8 tokena?
Odgovor: BPE tokenizer je treniran najviše na engleskom tekstu. On prepoznaje cijele engleske riječi kao jedan jedini token. Zbog slova poput 'ć' i rjeđe upotrebe jezika na internetu, bosanske se riječi lome na slogove. -
Pitanje: Dobili ste izvještaj na našem jeziku dug 100 stranica (~30.000 riječi)
u PDF formatu, i želite da API izvuče sažetak. Koji API model trebate odabrati iz tabele i
zašto?
Odgovor: 30.000 riječi na našem jeziku prelazi 100.000 tokena (zbog omjera loma). GPT-4o (128k limit) može ovo primiti na "svoj radni stol", mada je blizu granice. Raditi to sa starijim modelima od samo 8k tokena je potpuno nemoguće bez cijepanja PDF-a na više zasebnih komada. -
Pitanje: Da li je Sliding Window rješenje ako korisnik AI agentu kaže "Provjeri
onaj mail od prije pola godine" (a mi pričamo mjesecima svaki dan)?
Odgovor: Nije. Taj mail je davno "pao sa radnog stola" zbog Sliding Window pritiska. Model ga ne može vidjeti. Razumijevanje stare historije bi ovdje zahtijevalo RAG tehniku pronalaženja i dovođenja na stol, što učimo iz Modula 6.
LAB O2: Tokenizacija, Kalkulacija i Troškovi (TikToken)
Izgradićemo Python alat koji: (1) analizira tokenizaciju teksta, (2) uspoređuje bosanski i engleski po broju tokena, i (3) izračunava finansijski impakt na realnim scenarijima korištenja OpenAI API-ja.
Instalacija TikToken biblioteke
Nastavljamo u istom venv okruženju iz Lekcije 1.1. Aktivirajte ga ako nije aktivan:
# Aktivacija venv (ako nije aktivno)
cd C:\Users\$env:USERNAME\Desktop\AI_Kurs
.\venv\Scripts\Activate.ps1
# tiktoken je OpenAI-jeva open-source biblioteka za tokenizaciju
# Isti tokenizer koji koriste GPT-3, GPT-4, o1, o3 modeli
pip install tiktoken
# Provjera instalacije
python -c "import tiktoken; print('tiktoken OK, verzija:', tiktoken.__version__)"
Kreiranje analizatora u VS Code
Otvorite VS Code: File → Open Folder → Izaberite AI_Kurs folder.
Napravite novi fajl: File → New File → Sačuvajte kao analyzer.py.
Unesite sljedeći kod liniju po liniju, čitajući komentare:
"""
analyzer.py - Alat za analizu tokenizacije i troškova LLM API-ja
Autor: AI Training Kurs, Modul 1.2
"""
# Importamo tiktoken biblioteku (OpenAI tokenizer)
import tiktoken
# ================================================================
# Korak 1: Inicijalizacija tokenizera
# ================================================================
# Svaki model ima vlastiti tokenizer (encoding).
# "cl100k_base" je encoding koji koriste: gpt-4, gpt-4o, gpt-3.5-turbo
# "o200k_base" koriste noviji o1, o3, gpt-4o-mini modeli
# Koristimo encoding_for_model() da automatski odaberemo pravi encoding:
encoding = tiktoken.encoding_for_model("gpt-4o")
print(f"Tokenizer učitan: {encoding.name}")
print(f"Veličina rječnika: {encoding.n_vocab:,} tokena")
# Trebate vidjeti: 200,019 tokena u rječniku gpt-4o tokenizera
print("\n" + "="*60)
# ================================================================
# Korak 2: Naši test stringovi (isti sadržaj, dva jezika)
# ================================================================
text_english = (
"The database migration caused significant downtime on the main "
"production cluster due to locking issues in the transaction log."
)
text_bosnian = (
"Migracija baze podataka uzrokovala je značajan prekid rada na "
"glavnom produkcijskom klasteru zbog problema sa zaključavanjem "
"u dnevniku transakcija."
)
# ================================================================
# Korak 3: Tokenizacija
# ================================================================
# encode() metoda prima string i vraća Python listu Integer-a (token ID-eva)
# Svaki integer je indeks tokena u rječniku modela
tokens_eng = encoding.encode(text_english)
tokens_bos = encoding.encode(text_bosnian)
# decode_single_token_bytes() vraća bytes reprezentaciju svakog tokena
# Ovo nam omogućava da vidimo točno kako se svaki ID mapira na tekst
print("="*60)
print("📊 ANALIZA ENGLESKOG TEKSTA")
print("="*60)
print(f"Originalni tekst ({len(text_english)} znakova):")
print(f" '{text_english}'")
print(f"\nBroj tokena: {len(tokens_eng)}")
print(f"Token ID niz: {tokens_eng}")
print(f"\nDetaljna tokenizacija (token → tekst koji reprezentira):")
for token_id in tokens_eng:
# decode() pretvara token ID natrag u string za čitanje
token_text = encoding.decode([token_id])
print(f" [{token_id:6d}] → '{token_text}'")
print("\n" + "="*60)
print("📊 ANALIZA BOSANSKOG TEKSTA")
print("="*60)
print(f"Originalni tekst ({len(text_bosnian)} znakova):")
print(f" '{text_bosnian}'")
print(f"\nBroj tokena: {len(tokens_bos)}")
print(f"Token ID niz: {tokens_bos}")
print(f"\nDetaljna tokenizacija:")
for token_id in tokens_bos:
token_text = encoding.decode([token_id])
print(f" [{token_id:6d}] → '{token_text}'")
# ================================================================
# Korak 4: Izračunavanje finansijskog impakta
# ================================================================
# Scenario: Imamo sistem koji procesira 1,000,000 ovakvih poruka
# GPT-4o cijena: Input = $5.00 / 1M tokena, Output = $15.00 / 1M tokena
# Pretpostavimo da je output otprilike jednak inputu po dužini
INPUT_PRICE_PER_MILLION = 5.00 # USD za 1 Milion input tokena
OUTPUT_PRICE_PER_MILLION = 15.00 # USD za 1 Milion output tokena
PORUKA_COUNT = 1_000_000 # Obrađujemo 1 milion poruka
print("\n" + "="*60)
print("💰 FINANSIJSKA KALKULACIJA — 1,000,000 poruka")
print("="*60)
def calculate_cost(token_count, n_messages):
"""Izračunava ukupni trošak za n_messages identičnih poruka."""
total_input_tokens = token_count * n_messages
total_output_tokens = token_count * n_messages # Pretpostavljamo isti output
input_cost = (total_input_tokens / 1_000_000) * INPUT_PRICE_PER_MILLION
output_cost = (total_output_tokens / 1_000_000) * OUTPUT_PRICE_PER_MILLION
return input_cost + output_cost, total_input_tokens, total_output_tokens
cost_eng, in_tokens_eng, out_tokens_eng = calculate_cost(len(tokens_eng), PORUKA_COUNT)
cost_bos, in_tokens_bos, out_tokens_bos = calculate_cost(len(tokens_bos), PORUKA_COUNT)
print(f"\n🇺🇸 ENGLESKI:")
print(f" Tokeni po poruci: {len(tokens_eng)}")
print(f" Ukupni input tokeni: {in_tokens_eng:,}")
print(f" Ukupni output tokeni: {out_tokens_eng:,}")
print(f" 💵 UKUPNI TROŠAK: ${cost_eng:,.2f}")
print(f"\n🇧🇦 BOSANSKI:")
print(f" Tokeni po poruci: {len(tokens_bos)}")
print(f" Ukupni input tokeni: {in_tokens_bos:,}")
print(f" Ukupni output tokeni: {out_tokens_bos:,}")
print(f" 💵 UKUPNI TROŠAK: ${cost_bos:,.2f}")
print(f"\n📊 ZAKLJUČAK:")
ratio = len(tokens_bos) / len(tokens_eng)
extra_cost = cost_bos - cost_eng
print(f" Bosanski tekst ima {ratio:.2f}x VIŠE tokena od ekvivalenta na engleskom")
print(f" Na 1 milion poruka, bosanski košta EXTRA: ${extra_cost:,.2f}")
print(f"\n💡 Inženjerska preporuka: Pišite system prompts i API instrukcije na ENGLESKOM!")
print(f" Output tražite na bosanskom samo za krajnjeg korisnika.")
Pokretanje i analiza rezultata
# Uvjerite se da ste u AI_Kurs folderu sa aktivnim venv-om
python analyzer.py
- Engleski tekst: Vidjet ćete da se česte engleske riječi poput "the", "on", "main", "due" svaka mapira u jedan jedini token.
- Bosanski tekst: Vidjet ćete da se rijeci "uzrokovala", "zaključavanjem", "produkcijskom" razbijaju na 3-5 tokena jer BPE algoritam nije vidio dovoljno bosanskih primjera u trening podacima da ih zapakovao u jedan token.
- Finansijski impakt: Na velikim sistemima (npr. automatizovana obrada 10.000 korisničkih zahtjeva dnevno), razlika između "pisemo System Prompt na bosanskom vs. engleskom" može biti stotine dolara mjesečno ili hiljade godišnje.
-
Arhitektonski zaključak: Svaki AI sistem u produkciji koji obrađuje
bosanski/srpski/hrvatski sadržaj treba imati strategiju za optimizaciju tokena. Tipično:
System Prompt na engleskom (robusnost + efikasnost), User prompt na maternjem (UX),
Output na maternjem (čitljivost) uz
max_tokenslimit za kontrolu troška.
Bonus: Interaktivni tokenizer u terminalu
Napravite novi fajl interactive_tokenizer.py za eksperimentisanje:
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
print("🔤 Interaktivni Tokenizer")
print("Napišite tekst (ili 'quit' za izlaz):\n")
while True:
text = input(">>> ")
if text.lower() in ['quit', 'exit', 'q']:
break
tokens = enc.encode(text)
print(f" Broj znakova: {len(text)}")
print(f" Broj tokena: {len(tokens)}")
print(f" Tokenizovano:")
for tid in tokens:
print(f" '{enc.decode([tid])}' (ID: {tid})")
print(f" Omjer tok/slovo: {len(tokens)/len(text):.2f}")
print()
python interactive_tokenizer.py
# Probajte unijeti: "Hello" vs "Zdravo" vs "Šeširdžija"
# Vidite razliku u broju tokena za iste koncepte na različitim jezicima!
✅ Zaključak
Sada razumijemo cijeli put teksta: String → BPE tokenizacija → Token ID-evi (Integer lista) → Embedding vektori → Transformer obrada → Logits distribucija → Sljedeći token.
Naučili smo da tokenizacija direktno utiče na troškove API poziva i na kapacitet context window-a, te zašto se za sistemske prompts u poslovnim AI aplikacijama preporučuje engleski jezik.
Slijedi pauza za ručak (60 minuta). Nakon toga, nastavl jamo sa Lekcijom 1.3 — kako direktno komunicirati sa LLM API-jevima, koje hiperparametre možemo kontrolisati i kako izbjeći halucinacije u produkcijskim sistemima.