Izvesna velika kompanija u oblasti velikih modelova (dve reči) pokreće uklanjanje osetljivih podataka pri odlasku zaposlenih — ključni članovi moraju obavezno da potpišu, a ako žele da odstupe, moraju tri meseca unapred da obaveste kompaniju.
Na jednom sajtu za vesti o velikim kompanijama video sam vest kao u naslovu.
Deluje prilično pretjerano, što pokazuje da se AI razvio do te mere da su plate, sistemi i pravila potpuno drugačiji od onog što važi za tradicionalni internet.
Pored toga, prema povratnim informacijama sa intervjua koje ste delili.
Učestalost AI tema raste, dok se udeo tradicionalnih pitanja o Java back-endu postepeno smanjuje — čini se da se odnos pomera ka 7 naprema 3.
Danas ćemo zajedno proći kroz visoko-frekventna AI Agent pitanja za intervju.

Svi odgovori se zasnivaju na našem PaiCLI-ju — to je AI Coding Agent napisan u Javi, sličan Claude Code-u.
content
01. Šta si radio u Agent projektu?
Lao Wang otvara direktno: "Prvo mi ukratko predstavi — za koje module si bio zadužen u ovom projektu?"
Rekao sam: "PaiCLI je prošao kroz 21 verziju, od prvobitnog ReAct-a do isporučivog proizvoda koji podržava Multi-Agent. Glavno sam radio tri ključna bloka."

Prvi blok je Agent motor.
Implementirao sam glavnu petlju za ReAct režim, uključujući pozivanje LLM-a, izvršavanje alata i upravljanje kontekstom — kompletan tok. Agent u svakoj iteraciji radi proveru budžeta, kompresiju konteksta i raspoređivanje alata — sve to sam dizajnirao i implementirao.
Drugi blok je integracija više LLM modela.
Napisao sam apstraktni klijent kompatibilan sa OpenAI-jem, na bazi OkHttp3 za SSE striming, sa podrškom za seamless prebacivanje između četiri domaća modela — Zhipu, DeepSeek, StepFun i Kimi. Svaki model ima svoje specifičnosti, na primer Zhipu podržava prompt caching, a DeepSeek podržava prozor konteksta od 1M.
Treći blok je tool use i MCP integracija.
Ugrađeno je 11 ključnih alata — čitanje i pisanje datoteka, izvršavanje komandi, pretraga koda, prikupljanje veb-stranica i slično, a uz to podržano je i dinamičko povezivanje spoljnih alata preko MCP Servera.

02. Kako je projektovana izvršna petlja Agenta?
Lao Wang se zainteresovao: "Kako ste konkretno dizajnirali vašu ReAct petlju?"
Rekao sam: "Zapravo je veoma jednostavno — suština je while(true) petlja, a uslov za izlazak određuje sam LLM."

U svakoj iteraciji rade se četiri stvari.
- Prvi korak, provera budžeta — koliko je tokena potrošeno, koliko iteracija je prošlo, i ako se pređe limit, prinudno se izlazi.
- Drugi korak, provera da li je potrebno kompresovati kontekst.
- Treći korak, slanje istorije razgovora i definicija alata zajedno LLM-u.
- Četvrti korak, pregled LLM-ovog odgovora — ako sadrži tool_calls, izvršiti alate, ubaciti rezultate u istoriju razgovora, ući u sledeću iteraciju; ako nema tool_calls, to znači da LLM smatra da je zadatak završen i vraća se konačan odgovor.

Lao Wang je pritisnuo: "Ako izlazak određuje sam LLM, šta ako LLM upadne u beskonačnu petlju i stalno poziva isti alat, bez zaustavljanja?"
Rekao sam: "Postoje rezervne mere. Pratimo dva indikatora: jedan je ukupna potrošnja tokena, sa podrazumevanim limitom od 80% maksimalnog prozora konteksta modela; drugi je broj iteracija petlje, koji ima gornju granicu. Ako bilo koji od ovih indikatora pređe granicu, odmah izlazimo iz petlje i vraćamo poruku korisniku."
03. Da li je poziv alata ugrađen u okvir ili se kontroliše preko Prompta?
"Da li koristite Spring AI? Da li je logika poziva alata urađena od strane okvira ili ste je sami napisali?" Lao Wang nastavlja.
Rekao sam: "Ne koristimo Spring AI, sve je pisano samostalno."
PaiCLI definiše interfejs LlmClient kao apstrakciju za pozivanje LLM-a, a ispod njega postoji osnovna klasa zasnovana na OkHttp3 koja implementira OpenAI kompatibilan protokol za SSE striming.
Tok poziva alata takođe sami raščlanjujemo.

U SSE strimu koji vraća LLM, tool_calls stiže u delićima — id, name i arguments jednog poziva alata mogu biti raspoređeni u više SSE događaja.
Te delove skladištimo, a nakon završetka strima ih sastavljamo u potpun ToolCall objekat.
Lao Wang pita: "Zašto ne koristite Spring AI? Ne plašite li se visokih troškova održavanja ako sami pravite točkove?"
Rekao sam: "Uglavnom zato što je PaiCLI alat komandne linije — brzina pokretanja mu je važna, Spring AI je preterano težak i nema potrebe za njim, pogotovo sada kada je AI Coding toliko napredovao da u suštini ne postoji ništa što se ne može implementirati."
04. Kako je dizajniran sistem prompta?
Lao Wang menja temu: "Pričajmo o dizajnu vašeg sistemskog prompta — da li je fiksan ili dinamički sastavljen?"
Rekao sam: "Dinamički sastavljen, i to u slojevima."
Imamo PromptAssembler koji je zadužen za sklapanje sistemskog prompta iz više Markdown datoteka.

Čitav prompt je podeljen u 7 slojeva:
- Prvi sloj je base.md — definiše identitet PaiCLI-ja, na primer "Ti si PaiCLI, inteligentni Agent za programiranje", jezičke zahteve "odgovaraj na kineskom", kao i listu svih dostupnih alata i strategije korišćenja.
- Drugi sloj je karakter — trenutno se koristi calm.md, koji definiše smiren i racionalan stil.
- Treći sloj je instrukcija režima — ReAct režim, Plan režim i Multi-Agent režim svaki ima svoju Markdown datoteku koja govori modelu na koji način trenutno treba da radi.
- Četvrti sloj je strategija odobrenja — kontroliše koji alati zahtevaju potvrdu korisnika pre izvršavanja.
- Peti sloj je dinamički kontekst — obuhvata rezime memorije i izvore spoljnog konteksta.
- Šesti sloj je indeks Skills — ubacuje se opis aktiviranih Skill-ova.
- Sedmi sloj su instrukcije za upravljanje kontekstom i protokoli saradnje.
Lao Wang nastavlja: "Gde se nalaze datoteke sa promptovima? Mogu li korisnici da ih prilagode?"
Rekao sam: "Postoje tri nivoa prioriteta učitavanja. Prvi nivo je ugrađeni direktorijum resources/prompts/ unutar JAR paketa — to su podrazumevane vrednosti. Drugi nivo je korisnički direktorijum ~/.paicli/prompts/, gde korisnik može da zameni podrazumevane promptove. Treći nivo je direktorijum projekta .paicli/prompts/, koji ima najviši prioritet i zgodan je za prilagođavanje na nivou tima. Ovaj dizajn je inspirisan mehanizmom CLAUDE.md u Claude Code-u, koji omogućava različitim projektima da imaju različito ponašanje Agenta."
05. Kompletan proces pozivanja LLM-a
"Od korisničkog unosa do konačnog odgovora — ispričaj mi čitav proces pozivanja LLM-a." Lao Wang ovog puta želi čitav tok.

Prvi korak, nakon što korisnički unos stigne, gradi se kontekst. Iz kratkoročne memorije izdvajamo informacije relevantne za trenutno pitanje i ubacujemo ih u dinamički kontekst sistemskog prompta.
memoryManager.addUserMessage(userInput);
String memoryContext = memoryManager.buildContextForQuery(
userInput, contextProfile.memoryContextTokens()
);
updateSystemPromptWithMemory(memoryContext);Drugi korak, korisnička poruka se dodaje u istoriju razgovora. Ako poruka sadrži referencu na sliku (na primer putanju do snimke), slika se konvertuje u ContentPart sa base64 kodiranjem i pakuje se zajedno sa tekstom.
Treći korak, ulazak u ReAct petlju. Prvo se proverava da li je potrebno kompresovati kontekst, a zatim se proverava budžet.
Četvrti korak, izgradnja HTTP zahteva.
Istorija razgovora i definicije alata se serijalizuju u OpenAI format JSON. U nizu messages svaka poruka sadrži role i content, a u nizu tools svaki alat sadrži name, description i JSON Schema za parameters.
Peti korak, slanje zahteva i raščlanjivanje SSE strima.
OkHttp3 uspostavlja dugu vezu i red po red čita događaje koji počinju sa data:. Delta u svakom događaju može da sadrži tri vrste informacija: reasoning_content (proces razmišljanja), content (sadržaj odgovora) i tool_calls (pozivi alata). Ova tri polja se putem StreamRenderer-a prikazuju korisniku u realnom vremenu.
Šesti korak, nakon završetka strima sastavlja se ChatResponse koji sadrži kompletan content, reasoning, listu toolCalls i statistiku tokena.
Sedmi korak, povratak u Agent petlju koja odlučuje da li će izvršiti alate ili vratiti rezultat.

Lao Wang pritiska: "Spomenuo si renderovanje u realnom vremenu — kako se razlikuje proces razmišljanja od sadržaja odgovora?"
Rekao sam: "Preko imena polja u SSE događaju. Duboki režim razmišljanja DeepSeek-a i Zhipu-a vraća polje reasoning_content u delti, dok običan odgovor ide kroz polje content. PaiCLI interno održava dva stanja koja kontrolišu format ispisa u terminalu. Proces razmišljanja se prikazuje u stilu sklopivog panela, tako da se ne meša sa konačnim odgovorom."
(U sebi: Ovo pitanje mi je previše poznato — striming renderovanje sam doterivao tri dana da uhvatim sve granične slučajeve)
06. Kada se alati šalju LLM-u, a kada izvršavaju?
Lao Wang nastavlja da kopa: "Kada se definicije alata šalju modelu? Pri registraciji ili pri svakom zahtevu?"
Rekao sam: "Pri svakom zahtevu."
U ReAct petlji, pre pozivanja LLM-a, uvek se iz ToolRegistry uzima najnovija lista definicija alata:
List<LlmClient.Tool> toolDefinitions = toolRegistry.getToolDefinitions();
LlmClient.ChatResponse response = llmClient.chat(
conversationHistory, toolDefinitions, streamRenderer
);Prednost ovoga je što, ako korisnik usput putem komande /mcp učita novi MCP Server, novoregistrovani alati mogu biti primećeni od strane LLM-a u sledećoj iteraciji.
Registracija alata se dešava tokom faze konstrukcije. Ugrađeni alati se jedan po jedan registruju u konstruktoru — read_file, write_file, execute_command, glob_files, grep_code i slično. Svaki alat se sastoji od četiri dela: imena, opisa, JSON Scheme za parametre i funkcije za izvršavanje.
tools.put("read_file", new Tool(
"read_file",
"Čita sadržaj datoteke (samo unutar korenskog direktorijuma projekta)",
createParameters(
new Param("path", "string", "putanja do datoteke", true),
new Param("offset", "integer", "početni red", false),
new Param("limit", "integer", "maksimalan broj redova za čitanje", false)
),
args -> {
Path safe = pathGuard.resolveSafe(args.get("path"));
return readFileForTool(safe, args);
}
));MCP alati se registruju dinamički.
Nakon što korisnik pokrene MCP Server, metod registerMcpTool() iz ToolRegistry registruje spoljne alate u istu Mapu, pri čemu se imenski prostor izoluje formatom mcp__{server}__{tool}.

Lao Wang pritiska: "A šta je sa izvršavanjem? Ako jedan zahtev vraća više tool_calls, da li se izvršavaju sekvencijalno ili paralelno?"
Rekao sam: "Zavisi od broja. Ako postoji samo jedan tool_call, izvršava se direktno u trenutnoj niti. Ako ih je više, otvara se pool niti za paralelno izvršavanje, sa maksimalno 4 istovremena."

Paralelno izvršavanje ima dve zaštite od isteka vremena: 60 sekundi po pojedinačnoj komandi i 90 sekundi po celoj grupi alata. Ako neki alat istekne, odgovarajući Future se otkazuje i vraća se status TimedOut, bez uticaja na rezultate drugih alata.
07. Kako se iz rezultata zna koji Tool pozvati?
"Model vraća gomilu JSON-a — kako ga povezuješ sa konkretnom funkcijom alata?" pita Lao Wang.
Rekao sam: "Ključ je u polju name unutar tool_calls."
Svaki tool_call koji LLM vrati ima tri ključna polja: id (jedinstveni identifikator), function.name (ime alata), function.arguments (JSON parametara). name je isto ono ime koje smo koristili pri registraciji alata, na primer read_file, execute_command.

U striming SSE scenariju, ova tri polja ne stižu istovremeno. Informacije o jednom tool_call-u mogu biti raspoređene u više SSE događaja — name i arguments stižu postepeno, u delićima. Zato ih akumuliramo po indexu.
Nakon završetka strima, sastavljamo ih u listu ToolCall. Svaki ToolCall nosi kompletno name i arguments.
Zatim, preko name, u Mapu ToolRegistry tražimo odgovarajuću funkciju za izvršavanje, analiziramo JSON string arguments u Mapu parametara i prosleđujemo je funkciji alata na izvršavanje. Rezultat izvršavanja se, zajedno sa id, obavija u poruku tipa tool i ubacuje u istoriju razgovora, čime LLM zna kom zahtevu odgovara rezultat svakog poziva alata.
for (ToolExecutionResult toolResult : toolResults) {
conversationHistory.add(
LlmClient.Message.tool(toolResult.id(), toolResult.result())
);
}Lao Wang pritiska: "Šta ako model vrati ime alata koji ne postoji? Na primer, halucinira 'delete_database'?"
Rekao sam: "Ako ne pronađe odgovarajući ključ, vraća se poruka o grešci — 'Nepoznat alat: delete_database'. Ova poruka o grešci se ubacuje u istoriju razgovora kao tool poruka. Kada je LLM vidi, obično se sam ispravi i pokušava sa drugim ispravnim alatom. U našem sistemskom promptu base.md takođe su jasno izlistana imena svih dostupnih alata, čime se smanjuje verovatnoća halucinacija."
(U sebi: Hehe, Lao Wang, ovakvi detaljni pritisci me ne mogu zaustaviti)
08. Način kompresije memorije — kako se generiše rezime?
Poslednje pitanje Lao Wang-a: "Ranije si spomenuo kompresiju konteksta — kako se to konkretno radi? Kako se generiše rezime?"
Rekao sam: "Pokreće se pre svakog poziva LLM-a."
Logika provere je jednostavna — prvo se proceni broj tokena u trenutnoj istoriji razgovora, i ako je ispod praga (podrazumevano 90% maksimalnog prozora konteksta modela), ne radi se ništa. Ako se pređe prag, pokreće se kompresija.

Kompresija nije potpuna, već se deli po "krugovima".
Zadržavaju se poslednja 3 kruga korisničkog razgovora netaknuta, a stariji razgovori se izdvajaju za generisanje rezimea. Tačka preseka mora da padne na granicu korisničke poruke — ne sme se razdvojiti par tool_call i tool_result, jer u suprotnom LLM ne bi mogao da razume.
Nakon što se izdvoje poruke za kompresiju, poziva se LLM za generisanje rezimea.
Prompt za rezime je pažljivo dizajniran i zahteva zadržavanje četiri vrste ključnih informacija: ključni zahtevi korisnika, operacije koje je Agent završio, postignuti dogovori i nerešeni problemi.
private static final String SUMMARY_PROMPT = """
Sažmi sledeću istoriju razgovora u jasan rezime, zadržavajući:
1. Ključni zahtevi i ciljevi koje je korisnik postavio
2. Ključne operacije koje je Agent završio (koji alati su pozvani, šta su vratili kao ključne rezultate)
3. Dogovori ili zaključci koji su postignuti
4. Problemi ili zadaci koji još uvek nisu rešeni
Nemoj prepričavati svaki originalni red, nemoj nabrojati sve pozive alata, nemoj zadržati nevažeće ćaskanje.
Ispiši 1-3 pasusa na kineskom, bez listi, bez ikakvih prefiksa ili metaopisa.
""";Nakon generisanja rezimea, istorija razgovora se obnavlja.
Struktura je: sistemski prompt → jedna user poruka koja sadrži rezime kompresije → jedna assistant poruka sa sadržajem "U redu, upoznat sam sa prethodnim kontekstom, nastavimo." → poslednja 3 kruga originalnog razgovora.
Poruka assistant-a je dogovor na nivou protokola. OpenAI kompatibilan protokol zahteva da se user i assistant poruke smenjuju i da ne mogu postojati dve uzastopne user poruke. Dodavanjem ove assistant poruke "potvrda prijema" osigurava se ispravnost sekvence poruka.
Lao Wang pritiska: "Da li unos za rezime ima ograničenje dužine? Šta ako razgovor koji treba kompresovati ima desetinama hiljada znakova?"
Rekao sam: "Da, ograničen je na 60 hiljada znakova. Sve preko se odseca — samo prvih 60 hiljada znakova se šalje na generisanje rezimea. To sprečava da zahtev za rezime sam pređe prozor konteksta LLM-a. U praksi, uz kombinaciju 3 kruga zadržavanja i praga od 90%, sadržaj koji treba kompresovati obično ima između 20-30 hiljada znakova — retko dostiže ovaj limit."
Lao Wang pritiska: "Koliko tokena se smanji nakon kompresije?"
Rekao sam: "Obično se smanji na 20%-30% originalne veličine. Na primer, pre kompresije 80 hiljada tokena, posle oko 20-30 hiljada. Sam rezime obično ima samo nekoliko stotina do hiljadu i nešto tokena, a uz zadržana poslednja 3 kruga originalnog razgovora, ukupan broj znatno pada. U logove se štampa poređenje broja tokena i poruka pre i posle kompresije, radi lakšeg praćenja efekta."
Kako ovo opisati u biografiji?
AI asistent za programiranje | Razvoj Agenta | PaiCLI 2026-03 ~ danas
Kratak opis projekta: AI Coding Agent alat komandne linije zasnovan na Javi, po uzoru na Claude Code, podržava tri režima izvršavanja — ReAct, Plan-and-Execute i Multi-Agent — i integriše domaće velike modele kao što su Zhipu, DeepSeek, StepFun i Kimi.
Tehnički stek: Java 17, OkHttp3, Jackson, JLine3, MCP Protocol
Ključne odgovornosti:
- Dizajn i implementacija ReAct glavne petlje motora, zasnovane na while(true) arhitekturi sa samostalnim donošenjem odluka LLM-a, integracija upravljanja budžetom (token/iteracija dvo-dimenzionalno), implementacija automatske kompresije konteksta.
- Na bazi OkHttp3 + SSE implementiran sloj za integraciju više modela kompatibilan sa OpenAI-jem, uz podršku za akumulativno raščlanjivanje delova ToolCall-a.
- Ugrađeno 11 ključnih alata + MCP dinamičko proširenje, podrška za paralelno izvršavanje više alata (maksimum 4 istovremeno), zaštita od isteka vremena i uređeno vraćanje rezultata.
- Implementacija arhitekture sklapanja sistemskog prompta u 7 slojeva, uz podršku za trostruko pokrivanje: ugrađeno u JAR → korisnički nivo → nivo projekta, što omogućava prebacivanje režima i dinamičko ubacivanje konteksta.
- Dizajn mehanizma kompresije konteksta — podela po korisničkim krugovima, LLM generisanje rezimea, zadržavanje poslednja 3 kruga originalnog razgovora, uz stopu kompresije tokena od 70%-80%, čime se rešava problem prelivanja konteksta u dugim razgovorima.
