Intervjuer: RAG bez vektorske baze, sa samim MySQL-om? Ja: milion vektora, zar to nije lako?
U starom Wangovoj providnoj šolji za čaj plivalo je prepuno goji bobica — bacio sam samo jedan pogled, sigurno stotinu komada.
Pre nego što sam došao sebi, stari Wang je prešao pravo na stvar: "Koju bazu koristiš za RAG pretragu?"
"MySQL."
Stari Wang jedva da nije pljunuo vodu koju je upravo otpio u moje lepo lice: "Samo MySQL? Vektorsku pretragu radiš u MySQL-u?"
"Šta je tebi, brate Wang, zar MySQL ne zaslužuje vektore? Million chunkova ja mu sredim uredno."
Videvši ga kako besno reaguje, nasmejao sam se: "Brate Wang, samo te podbadam, da malo razbijem led — evo, više nisam nervozan. Za vektore koristim ElasticSearch, koji radi i semantiku i skladištenje ključnih reči, hibridna pretraga lako rešena. 😄"

Stari Wang je zaista dobar čovek — nije se naljutio, ostao je ljubazan. Postavio je sledeće pitanje: "Kako procenjuješ preciznost pretrage u tom tvom RAG sistemu? Kako konkretno testiraš?"
(Inner OS: evo intervjua, kad bi svi intervjueri bili kao stari Wang.)

PS: pitanja ispod potiču iz stvarnih intervjua za RAG projekat PaiCongming, kao na slici — prvi krug Alibaba Fliggy.
Sadržaj
01. Kako procenjujete preciznost pretrage? Kako konkretno testirate?
Rekao sam: "Brate Wang, u PaiCongming RAG-u sam uradio jednu rundu evaluacije."
"Za procenu kvaliteta pretrage, industrija uobičajeno koristi tri metrike: preciznost (Precision), odziv (Recall) i MRR (Mean Reciprocal Rank)."
Preciznost gleda koliko je od dokumenata koje je pretraga vratila zaista relevantno. Na primer, pretraga vrati 10 chunkova, od kojih su 7 relevantna za pitanje — preciznost je 70%.
Odziv gleda koliko je od svih relevantnih dokumenata pretraza zaista vratila. Na primer, u bazi znanja ukupno postoji 15 relevantnih chunkova, a pretraga ih vrati 7 — odziv je 46,7%.
MRR gleda plasman prvog tačnog rezultata — što je više na listi, to je veći rezultat. Korisnika najviše zanima "da li je prvi rezultat onaj koji mi treba", i MRR upravo meri to.

Kako konkretno testirate?
"Moj pristup je izgradnja skupa za evaluaciju."
"Prvo se anotira 200 do 500 parova QA, gde svaki sadrži pitanje i pripadajući referentni chunk sa odgovorom. Zatim se ta pitanja batch ubacuju u modul za pretragu, uzmu se rezultati i uporede sa anotiranim, pa se izračunaju te tri metrike."
"Pre puštanja PaiCongming RAG-a u rad odradili smo rundu evaluacije — preciznost je sa prvobitnih 68% podignuta na 89%, i to uglavnom na dva načina: prvi, zamenili smo embedding model boljim; drugi, dodali smo reranker model koji drugi put rangira rezultate pretrage."
Stari Wang je naveo: "Koji reranker model koristiš?"
"Koristim bge-reranker-v2-m3; taj model dobro razume semantiku, a brzina zaključivanja je prihvatljiva, P95 latencija ispod 50ms."

Stari Wang je klimnuo glavom: "Sistem za evaluaciju je dobro složen."
02. Koliki je gornji limit broja fajlova za otpremanje?
Stari Wang nastavlja: "Koliki je gornji limit broja fajlova za otpremanje? Kolika veličina fajla?"
Rekao sam: "Ovde treba reći u dva sloja — ograničenje na nivou biznisa i na nivou sistema."
"Na nivou biznisa ograničavamo da jedno otpremanje ima najviše 20 fajlova, a pojedinačni fajl najviše 50MB. Većina korisnika otprema PDF i Word, a 50MB pokriva 99% dokumenata."

"Na nivou sistema, pravi uski zahvat je u parsiranju dokumenata i vektorizaciji. Jedan PDF od 50MB može imati nekoliko stotina strana; parsiranje u tekst, sečenje na chunk-ove, vektorizacija jednog po jednog — ceo tok može trajati nekoliko minuta. Ako korisnik odjednom otpremi 20 takvih velikih fajlova, pozadinski red zadataka će se nagomilati."
"Zato sam uveo asinhronu obradu. Korisnik odmah dobije potvrdu uspeha, a pozadina ih postepeno probavlja preko Kafke. Na frontend-u stoji traka napretka, a kad obrada završi, korisnik se obavesti."

Stari Wang nastavlja: "A šta ako neko zlonamerno otpremi gomilu smeća?"
"Imamo limitiranje protoka. Po korisniku je ograničenje ukupnog dnevnog otpremanja do 500MB, po IP adresi ograničen broj paralelnih otpremanja, kao i dnevni limit za Embedding. Uz to, tipovi fajlova su stavljeni na whitelist-u — dozvoljeni su samo PDF, Word, TXT i Markdown."

03. Šta ako broj dokumenata dostigne milionski nivo?
Stari Wang se naslonio, izraz mu postade ozbiljan: "Ako broj dokumenata dosegne milionski nivo, kako dizajnirate skladištenje i pretragu? Pritisak je veliki, šta onda?"
"To pitanje treba razložiti po slojevima. Arhitektura PaiCongminga je: MySQL čuva metapodatke dokumenata, ElasticSearch čuva vektore i ključne reči — njih dvoje sarađuju."
Kako dizajnirati sloj za skladištenje?
"Prvo o MySQL-u. MySQL čuva metapodatke dokumenata — naziv fajla, putanju, vreme otpremanja, kategoriju, korisnika kom pripada. Ne čuva vektore — svi vektorski podaci su u ES. Zato ovde u MySQL-u nema velikih polja, pritisak na skladište je mali, a za milionski nivo dokumenata to je svega nekoliko GB podataka, jedna tabela to lako izdrži."

"Ako zaista treba optimizovati, može se razdvojiti po biznisu — na primer pravni dokumenti u posebnoj bazi, tehnički u posebnoj. Ili hladno-vruća separacija: dokumenti kojima se nije pristupalo više od 6 meseci arhiviraju se u hladno skladište. Ali na trenutnom nivou to nije potrebno."
"Pravi deo skladišta koji vuče jeste ES. Milionski nivo dokumenata, pretpostavimo da se prosečan dokument seče na 50 chunk-ova — to je 50 miliona chunk-ova. Svaki chunk čuva jedan 2048-dimenzionalni vektor, pa sami vektorski podaci iznose 50 miliona × 2048 × 4 bajta ≈ 400GB."
"Optimizacija skladišta u ES ima nekoliko pravaca. Prvo, koristiti gusti vektorski indeks. ES nakon verzije 8.x podržava HNSW indeks, pa vektorska pretraga ne mora nasumično da obilazi; sa indeksom, brzina pretrage se poveća i deset puta. Drugo, hladno-vruća podela: ES podržava da se vrući podaci smeste na SSD, a hladni na HDD, čime se istovremeno uvažavaju i performanse pretrage i trošak skladišta."
Kako optimizovati sloj pretrage?
"Za pretragu, ES prirodno podržava vektorsku i ključnu reč pretragu — hibridna pretraga se direktno rešava. Ako je pritisak veliki, postoji nekoliko pravaca optimizacije."
"Prvo, prvo filtriranje, pa vektorska pretraga. Korisnički upiti obično nose metapodatkovne uslove, poput 'pronađi mi dokumente vezane za pravo'. Prvo u ES-u term upitom suzi kandidatski skup, a zatim radi izračunavanje vektorske sličnosti — računarski posao je mnogo manji."
"Drugo, štelovanje HNSW parametara. HNSW indeks u ES ima dva ključna parametra: m (broj suseda po sloju) i ef_search (broj kandidata pri pretrazi). Što je m veće, indeks je tačniji, ali zauzima više memorije; što je ef_search veće, pretraga je tačnija ali sporija. Naša merenja su pokazala da su m=16 i ef_search=100 dobar balans između tačnosti i latencije."
"Treće, keširanje popularnih upita. Mnogi RAG sistemi imaju 80% upita koncentrisanih u 20% popularnih pitanja. Rezultati pretrage za ta pitanja keširaju se u Redis, sa stopom pogođenosti preko 40%, čime se direktno štedi računanje vektora."

Stari Wang je naveo: "Za vektor od 2048 dimenzija, da li je latencija pretrage prihvatljiva?"
"2048 dimenzija zaista je malo sporije od 1024, ali razlika nije tolika kako se misli. Složenost pretrage HNSW indeksa je O(log N) i nije mnogo povezana sa dimenzionalnošću. Naša opterećenja su pokazala da 50 miliona vektora dimenzije 2048 imaju P99 latenciju ispod 100ms, što je sasvim prihvatljivo."
Stari Wang klimnu glavom: "ES za vektore + MySQL za metapodatke — ta arhitektura je ispravna."
04. Kolika je veličina sečenja pri otpremanju dokumenta?
Stari Wang nastavlja: "Kolika je veličina sečenja pri otpremanju dokumenta? Zašto baš tako? Zašto ne 1MB ili 10MB?"
Rekao sam: "Veličina chunk-a koju smo postavili je 512 tokena, a preklapanje 64 tokena."
Zašto 512?
"Prvo, preciznost pretrage. Model text-embedding-v4 koji koristimo mada maksimalno podržava 8192 tokena ulaza i daje 2048-dimenzionalni vektor, na testiranju se pokazalo da što je chunk duži, to semantika razvodnjenija, a razlikovnost embedding-a opada. 512 tokena je optimalna vrednost koju smo našli nakon više krugova štelovanja, sa balansom između preciznosti i količine informacija."
"Drugo, semantička celovitost. Premali chunk (npr. 100 tokena) lako preseče jednu celu rečenicu, pa sadržaj koji pretraga vrati nema kontekst i model ga ne razume. Preveliki chunk (npr. 2000 tokena) obuhvata previše tema, pa preciznost pretrage pada — u jednom chunk-u se priča o tri teme, pa zbog koje je zapravo vraćen?"
"Treće, budžet tokena. Prozor konteksta velikog modela je ograničen. Ako je svaki chunk prevelik, broj chunk-ova koji stane u njega je manji. Chunk od 512 tokena, sa 5 rezultata pretrage i šablonom prompta, ukupno uzme manje od 4000 tokena, ostavljajući dovoljno prostora za generisanje."

Stari Wang je naveo: "Zašto ne 1MB ili 10MB?"
"Zato što bi jedinica chunk-a trebalo da bude token, a ne bajt. Tekst od 1MB je oko pola miliona reči, to više nije chunk, to je cela knjiga. 10MB je još apsurdnije."
"Suština je da svrha sečenja jeste razbijanje dugog dokumenta na 'semantičke jedinice', gde svaka nosi relativno samostalnu temu. Ta granulacija nije vezana za veličinu skladišta, već za semantiku. Sečenje po bajtovima je isto toliko nepouzdano kao i sečenje po tački — samo sečenje po semantici ima smisla."
"Kasnije smo uradili još jednu optimizaciju — rekurzivno sečenje. Prvo seče po pasusima; ako pasus prelazi 512 tokena, seče po rečenicama. Tako se nastoji da svaki chunk bude ceo pasus ili cele rečenice, bez presecanja rečenice na pola."
Stari Wang je zadovoljno klimnuo glavom.
05. Kako se radi deploy na više mašina?
Stari Wang menja ton: "Da li ste razmišljali o deploy-mentu na više mašina? Šta bi trebalo doraditi?"
Rekao sam: "Razmišljali smo, ali PaiCongming RAG je još uvek u deploy-mentu na jednoj mašini, jer obim biznisa još nije dostigao nivo koji zahteva više mašina. Ali pri dizajnu arhitekture već je predviđena proširivost."
"Ako želimo deploy na više mašina, glavna su tri mesta."
"Prvo, skladište fajlova. Već koristimo MinIO za objektno skladištenje, koje u multi-mašinskom okruženju prirodno podržava deljeni pristup — ovde nema potrebe za izmenom."
"Drugo, red zadataka. Parsiranje dokumenata i vektorizacija su asinhroni zadaci, već koristimo Kafka, pa više mašina može da konzumira istu temu — prirodno podržava više mašina. Ali treba obratiti pažnju na strategiju dodele particija, kako se zadaci ne bi duplo konzumirali."
"Treće, upravljanje sesijama. Sesija se mora prebaciti iz lokalnog skladišta u Redis, kako bi se omogućilo deljenje sesija."

06. Kako se radi horizontalno skaliranje?
Stari Wang odmah pita: "Kako postižete horizontalno skaliranje?"
Rekao sam: "Jezgro horizontalnog skaliranja je stateless. Dokle god je servis bez stanja, može se dodati bilo koliko mašina, ispred njih stoji load balancer i gotovo."
"U RAG sistemu postoje tri tipa servisa: servis za otpremanje dokumenata, servis za pretragu i servis za generisanje."
"Servis za pretragu je prirodno bez stanja — primi upit, pretraži bazu, vrati rezultat. Bilo koja mašina to može da odradi, ne zavisi od lokalnog stanja. Ni servis za generisanje nema stanja — primi prompt, pozove API velikog modela, vrati rezultat."
"Servis za otpremanje dokumenata je malo kompleksniji, jer uključuje upis fajla na disk i asinhroni zadatak. Ali pošto fajlove čuvamo u MinIO-u, a zadaci idu kroz Kafka-u, i on je bez stanja."
"Dakle, fokus prepravke za horizontalno skaliranje jeste eksternalizacija stanja — fajlovi u MinIO-u, zadaci u Kafka-i, sesije u Redisu, podaci u MySQL-u. Sam servis ne čuva nikakvo stanje, pa se u svakom trenutku može skalirati gore ili dolje."
07. Koji su interfejsi bez stanja?
Stari Wang nastavlja: "Koji su interfejsi bez stanja?"

"Interfejs za pretragu je bez stanja. Uneseš upit, dobiješ rezultat pretrage, ne zavisi ni od kakvog lokalnog stanja."
"Interfejs za generisanje je bez stanja. Uneseš prompt + kontekst, pozove se LLM API, vrati se rezultat generisanja."
"Interfejs za pretragu liste dokumenata je bez stanja. Čita iz MySQL-a, vraća podatke."
"Interfejs za proveru zdravlja je bez stanja. Vrati OK i gotovo."
"Oni sa stanjem su uglavnom dva: interfejs za otpremanje fajlova (ako se fajlovi čuvaju lokalno) i WebSocket veza (jer je WebSocket dugotrajna veza, čije je stanje vezano za konkretnu instancu servera)."
08. Kako se radi RAG pretraga nad videom i zvukom?
Stari Wang iznenada menja pravac: "Kako se radi pretraga nad videom i zvukom? Pretvaranje govora u tekst je skupo, kako to rešiti?"
Rekao sam: "Suština RAG-a za video i zvuk je da ih se prvo pretvori u tekst ili neku drugu vektorizovanu reprezentaciju, pa da krene kroz tok tradicionalnog RAG-a."

Jezgro proces je sledeći: audio se preko ASR (automatsko prepoznavanje govora) pretvara u transkript, transkript se seče na isečke po vremenskoj oznaci, i svaki isečak se vektorizuje Embedding-om i skladišti u vektorskoj bazi.
Kada korisnik postavi pitanje, vrši se semantička pretraga, pronalaze se najrelevantniji isečci teksta, a zatim se na osnovu tih isečaka generiše odgovor i istovremeno vraćaju odgovarajuće vremenske oznake.

Izbor ASR modela ide u nekoliko glavnih pravaca. Iz open-source sveta tu su Whisper (OpenAI-jev open-source, vrlo dobar, podržava više jezika), FunASR (Alibabin open-source za kineski ASR) i SenseVoice (Alibabin najnoviji višemodalni model glasa).
Komercijalni API može da koristi prepoznavanje govora iz Aliyun-a, Tencent Cloud ASR ili Volcano Engine ASR. Whisper je najbolji izbor po odnosu cene i kvaliteta — nije skup za sopstveni deploy, a kvalitet je blizu komercijalnog API-ja.
Ovo rešenje odgovara scenarijima sa čistim zvukom — pretraga podcasta, analiza razgovora u korisničkoj podršci, pitanja i odgovori nad snimkom sastanka. Za video, ako informacija slike nije potrebna, može se primeniti isto rešenje — izvuci audio iz videa i odradi ASR.
Ako je u videu informacija slike bitna — npr. pisanje na tabli u edukativnom videu, prikaz proizvoda u produktnom videu, ili događaji u snimcima nadzora — onda čist ASR nije dovoljan, pa treba iskoristiti i informaciju slike.
Jezgro proces je sledeći: video se ekstraktuje po određenoj frekvenciji (npr. jedan kadar u sekundi ili po jedan ključni kadar), svaki kadar se multimodalnim Embedding modelom pretvara u vektor i skladišti u bazi. Kad korisnik pita, isti multimodalni Embedding model vektorizuje pitanje (multimodalni modeli istovremeno obrađuju i tekst i sliku), radi se semantička pretraga koja pronalazi najrelevantnije kadrove, a zatim se na osnovu njihovih vremenskih oznaka locira deo videa.

Izbor multimodalnog Embedding modela uglavnom je CLIP familija. OpenAI-jev CLIP je pionir, a za kineske scenarije može se koristiti Chinese-CLIP ili multimodalna verzija BGE-M3.
Dobro je to što koristi informaciju slike, ali loše što je računarski skup, jer broj kadrova obično biva veliki. Jedansatni video sa jednim kadrom u sekundi ima 3600 kadrova, pa Embedding i skladištenje svakog od njih prilično troši resurse.
Ima li multimodalno rešenje?
Najnoviji trend jeste da se veliki vizuelni model direktno iskoristi za razumevanje video sadržaja i generisanje strukturiranog opisa. Na primer, modelima poput Qwen-VL, InternVL, GPT-4V se progura video isečak, pa model generiše detaljan tekstualni opis (uključujući sadržaj slike, pokrete ljudi, promene scene), koji se onda seče po vremenskim oznakama i vektorizuje za pretragu.

Prednost ovog rešenja jeste veoma visok kvalitet opisa, jer veliki vizuelni model razume semantičke odnose unutar slike, a ne radi samo običan Embedding slike. Mana je visoka cena — za svaki isečak videa poziva se veliki model što usporava obradu i troši mnogo tokena.
09. Zašto WebSocket
Stari Wang postavlja poslednje pitanje: "Zašto WebSocket? Kako se deploy-uje WebSocket na više servera?"
"SSE je jednosmeran — server gura podatke ka klijentu, a klijent samo pasivno prima. Većini AI proizvoda SSE je dovoljan, jer je scenario 'ja pitam, ti odgovaraš' — server povremeno izbaci token, klijent to renderuje i gotovo."
"Ali RAG scenario ima jednu ključnu potrebu — klijent mora aktivno da prekine generisanje. Korisnik postavi pitanje, veliki model još uvek izbacuje tokene, a korisnik vidi da pravac nije dobar i želi da klikne 'Zaustavi generisanje'. SSE ne može elegantno da prekine — klijent jedino može da zatvori celu vezu i ponovo je uspostavi. WebSocket je dvosmerni kanal, pa klijent u svakom trenutku može poslati stop poruku serveru; kad je server primi, odmah zaustavlja generisanje, veza i dalje postoji i sledeći krug razgovora se direktno ponovo koristi."

"Uz to, tok obrade RAG-a je priliicno dugačak — pretraga dokumenata → rerank rezultata → sklapanje prompta → generisanje velikog modela — cela lancanica može potrajati nekoliko sekundi. Sa WebSocket-om se u svakoj fazi može gurati napredak frontend-u (npr. 'Pretražujem...', 'Generišem...'), a klijent u svakoj fazi može poslati poruku koja otkazuje zadatak, što daje mnogo fleksibilnije iskustvo interakcije od SSE."
Stari Wang je naveo: "Kako se WebSocket deploy-uje na više servera?"
"WebSocket je dugotrajna veza — korisnik A je povezan na server 1, pa svaka naredna poruka mora ići serveru 1, a ne serveru 2 — jer server 2 nema tu vezu."
"Postoje dva rešenja."
"Prvo je lepljiva sesija (Sticky Session). Podesi se na load balanceru (npr. Nginx) tako da zahtevi istog korisnika uvek idu na istu mašinu. Konfiguracija je jednostavna — Nginx-u se doda jedan red ip_hash. Mana je što padom jedne mašine sve veze na njoj pucaju."
"Drugo je emitovanje poruka. Između više servera pomoću Redis Pub/Sub ili reda poruka radi se sinhronizacija. Server 1 primi poruku koju treba dostaviti korisniku A, pa je prvo objavi na Redis kanal; sve mašine prate taj kanal, a mašina koja drži vezu korisnika A vrši dostavu. Ovo rešenje je elegantnije — padom servera korisnik se ponovo poveže na neku drugu mašinu."
"PaiCongming RAG trenutno koristi prvo, jer je jednostavno i dovoljno. Ako kasnije budemo radili visoku dostupnost, preći ćemo na drugo."
Rezime
Mnogi prijatelji, kad završe RAG projekat, u biografiji napišu samo "sagradio sam RAG sistem za pitanja i odgovore na bazi LLM-a" i to je to. Intervjuer pročita i pomisli: pa ko to ne zna da napiše.
Biografija mora da ima razlikovnost — intervjuer nakon čitanja mora poželeti da pita za detalje. Evo referentnog šablona:
Naziv projekta: PaiCongming RAG inteligentni sistem za pitanja i odgovore
Kratak opis: Enterprise RAG sistem zasnovan na Spring Boot + MySQL + Redis, podržava otpremanje dokumenata u više formata, pametno sečenje, vektorsku pretragu i streaming odgovore velikog modela; već je u stvarnom radu u tehničkoj zajednici.
Tehnološki stek: Spring Boot, MySQL, Redis, Kafka, ElasticSearch, MinIO, text-embedding-v4 (Embedding, 2048 dimenzija), bge-reranker-v2-m3 (reranker), WebSocket
Ključne odgovornosti:
- Dizajn i implementacija engine-a za sečenje dokumenata, sa strategijom rekurzivnog sečenja na 512 tokena, kombinovanom sa percepcijom pasusa i detekcijom granica rečenica — preciznost pretrage podignuta sa 68% na 89%
- Na osnovu ES HNSW vektorskog indeksa + arhitekture hibridne pretrage, podržava semantičku pretragu nad milionima chunk-ova, sa P99 latencijom 2048-dimenzionalnog vektora kontrolisanom ispod 100ms
- Uveden reranker model bge-reranker-v2-m3 za drugi rang rezultata pretrage, stopa pogođenosti Top-5 podignuta za 23%, MRR sa 0.61 na 0.78
- Dizajn streaming arhitekture za guranje zasnovane na WebSocket-u + Redis Pub/Sub, podržava sinhronizaciju poruka u realnom vremenu i visoku dostupnost veze pri deploy-mentu na više servera
- Izgradnja asinhrone linije obrade dokumenata (Kafka + MinIO), potpuna asinhronizacija celog toka otpremanja, parsiranja i vektorizacije, sa dnevnim kapacitetom obrade preko 5000 dokumenata

Zaključak
Pišući ovo, želim da kažem nekoliko iskrenih reči onima koji se spremaju za AI intervju.
Nemojte namerno juriti Agent, nemojte stalno misliti da je RAG već zastareo — zapravo, ako se duboko zarovi, RAG dodiruje mnoge osnovne principe.

U eri AI-a ljudi su nestrpljivi, a tehnologija se brzo menja.
Kao OpenClaw, koji će uskoro biti zamenjen Agentom iz Hermès-a.
Ali osnovni principi su svima isti.
Nemojte stalno biti u trci za novim, već zaista smireno zahvatite u osnovne principe.
Samo tako možete zaista da ovladate ovom AI erom.
