AI Agent intervjujska pitanja druga serija: Sistem memorije, RAG pretraga, inženjering dugog konteksta 13 pitanja
Stari Wang ovaj put je zamenio naočare sa zlatnim okvirom, izgleda potpuno kao CTO nekog internetskog giganta, pogled mu je oštar ali sa osmehom na ustima, izgleda da je danas u dobrom raspoloženju.
Stari Wang je prevrteo moj životopis, "Ti si napisao da tvoj PaiCLI ima trosloku arhitekturu memorije, RAG vektorsku pretragu, adaptivni dugi kontekst, dosta si se hvalio."
(Interno OS: Brate Wang, ne govori da se hvalim, ovo sam ja liniju po liniju kodirao😤)
Rekao sam: "Brate Wang, ova tri bloka su zaista srce PaiCLI-ja. Sistem memorije radio sam u tri izdanja, 3. izdanje je memorija, 4. izdanje je RAG razumevanje koda, 12. izdanje je inženjering dugog konteksta. Nedavno sam uradio dva nadgradnje — dugoročna memorija dobila je izolaciju na nivou projekta, pretraga koda se iz RAG premosćivanja promenila u prioritet precizne pretrage, RAG semantička pokrivanje."
Stari Wang je pokazao interes: "Dobro, onda počnemo od sistema memorije."
content
01, Koji slojevi ima sistem memorije Agent-a
Stari Wang pita: "Prvo kaži celu arhitekturu, kako je složen vaš sistem memorije?"
Rekao sam: "Tri sloja. Kratkoročna memorija, dugoročna memorija, spoljašnja memorija."

Kratkoročna memorija je istorija poruka trenutnog razgovora — korisnički unos, odgovor modela, pozivi alata i rezultati, svaki krug se dodaje. Životni vek je jedna sesija, kada se zatvori terminal nestane.
Dugoročna memorija je trajna preko sesija.
Korisnik kaže "Zapamti da ovaj projekat koristi Java 17", Agent upisuje ovu činjenicu u lokalni JSON fajl. Sledeći put kada se otvori nova sesija, Agent iz fajla pronalazi stavke koje se odnose na trenutni razgovor i ubacuje ih u kontekst. Tako Agent može "zapamtiti" korisničke preference i kontekst projekta i preko sesija.
Spoljašnja memorija je spoljašnja baza znanja koja se pristupa preko pretrage, ne stalno boravi u istoriji razgovora, poziva se po potrebi.
PaiCLI-jeva spoljašnja memorija ima dva puta:
- Jedan je precizna pretraga, koja u realnom vremenu skenira stablo fajlova projekta prema ključnim rečima ili regularnim izrazima;
- Drugi je RAG vektorska semantička pretraga, koja iz predgrađenog Embedding indeksa pronalazi odgovarajuće odlomke koda.
Agent prvo ide na preciznu pretragu, samo kada je upit suviše nejasan, ključne reči se teško određuju, onda ide na RAG.
Stari Wang nastavlja: "Kako se koordiniraju ova tri sloja?"
Rekao sam: "Postoji jedinstveni menadžer koji je zadužen za koordinaciju. Pre svakog zahteva modelu, on radi tri stvari: pronalazi relevantne stavke iz dugoročne memorije, dobija rezultate pretrage iz spoljašnje memorije, a zatim te zajedno sa istorijom razgovora iz kratkoročne memorije slaže u kompletan prompt i šalje modelu. Svaki sloj ima svoju ulogu, menadžer je zadužen za 'koordinaciju'."
02, Da li kratkoročna memorija može da prelije
Stari Wang pita: "Kada se razgovor duže vodi, da li kratkoročna memorija može da prsni kontekstni prozor?"
Rekao sam: "Može."
Model ima ograničenje kontekstnog prozora, GLM-5.1 je 200k tokena, DeepSeek V4 je 1M.
Izgleda mnogo, ali ako se ne upravlja istorijom razgovora, posle nekoliko desetina krugova može se napuniti. Naročito rezultati poziva alata — čitanje velikog fajla može biti nekoliko hiljada tokena, izlaz komandne linije ako se ne skraći je katastrofalno.
PaiCLI-jevo rešenje je u realnom vremenu prati broj tokena koje trenutni razgovor zauzima. Kada zauzeće približi 90% prozora, automatski se pokreće sažimanje.
Stari Wang nastavlja: "Kako tačno radi sažimanje?"

Rekao sam: "Prvi set je sažimanje kratkoročne memorije unutar sistema memorije, koristi Map-Reduce sažetak: stare poruke prvo generišu sažetak po odeljcima, zatim se spajaju više sažetka, na kraju se sažetak vraća u kratkoročnu memoriju."
"Drugi set je sažimanje conversationHistory, sažima se stvarna lista poruka koje Agent šalje LLM-u. To nije Map-Reduce, već pre poziva LLM proverava broj tokena, kada se dostigne prag, stare poruke iza system i poslednja 3 korisnikova kruga se predaju LLM-u da sažme u jedan sažetak, zatim se rekonstruiše lista poruka."
originalna istorija:
[system, user1, assistant1(tool_call), tool1, ..., user20, assistant20]
posle sažimanja:
[system,
user("[sažeta istorija razgovora]\n" + sažetak),
assistant("Dobro, razumem prethodni kontekst, nastavite."),
poslednje poruke od početka 3. korisnička kruga]Ključno je tačka podeline mora pasti na granicu user message, ne sme se prekinuti parovi assistant tool_call i tool result. Inače će OpenAI-kompatibilan API primetiti da tool_call_id ne može naći odgovarajuću tool poruku, u najboljem slučaju model će biti zbunjen, u najgorem će odmah vratiti 400.

(Interno OS: Na ovu sam muku naleteo, prva verzija je sažimala svu istoriju, model je odgovarao nepovezano, popravljao sam čitavu veče pre nego što sam otkrio problem🥲)
03, Kada se dugoročna memorija čuva, kada se uzima
Stari Wang kaže: "Pričaj o dugoročnoj memoriji, kada se čuva, kada se uzima?"
Rekao sam: "Prvo čuvanje. Dva puta pokreću."
Prvi je korisnik eksplicitno čuva, npr. unos /save ovaj projekat koristi Java 17.
Drugi je Agent aktivno čuva, korisnik kaže "zapamti da ubuduće koristi Maven a ne Gradle", Agent proceni da je to stabilna činjenica, poziva save_memory alat i automatski čuva.

Princip dizajna je čuvati samo stabilne činjenice, ne privremene informacije.
"Korisnik preferira kineske odgovore" može se sačuvati, "trenutno menjam Main.java liniju 42" ne treba čuvati, ovo drugo je stvar kratkoročne memorije, sledeća sesija ne treba da to zna.
Stari Wang nastavlja: "Napravio si scope mehanizam? Pričaj."
Rekao sam: "Da, ovo je nedavna važna nadogradnja. Pre je sva dugoročna memorija bila bez razlike između projekata. Pojavio se problem: u projektu A sam sačuvao 'koristi Java 17', prebacio sam se na projekat B, odnosno Python projekat, Agent je takođe ubacio ovu memoriju, ometajući procenu modela."
Zato smo uveli mehanizam opsega, svaka memorija je podeljena u dva scope-a.
- Nivo project je podrazumevani, vezan za konkretnu putanju projekta, vidljiv samo u sesijama tog projekta.
- Nivo global je preferencija preko projekata, sve sesije ga vide, npr. "korisnik preferira kineske odgovore", "komentari koda na engleskom".
Korisnik čuva project-nivo memoriju preko /save sadržaj činjenice, /save --global sadržaj preferencije čuva global-nivo. Prilikom čuvanja se automatski upisuje apsolutna putanja trenutnog projekta u metapodatke, putanja je normalizovana da bi se sprečilo da se relativna i apsolutna putanja odnose na isti direktorijum a tretiraju kao dva različita projekta.

Stari Wang opet pita: "Kako se filtrira pri uzimanju?"
Rekao sam: "Pri svakom početku razgovora, prilikom pretrage dugoročne memorije dodatno se filtrira vidljivost projekta. Global-nivo memorije je vidljiv za sve projekte, project-nivo memorija je vidljiv samo za sesije gde putanja projekta u metapodacima odgovara trenutnom projektu. Nakon filtriranja vidljivosti, ulazi se u podudaranje ključnih reči i ocenjivanje po redu, uzima se top-k stavki i ubacuje u system prompt."
Pretraga koristi najprostije podudaranje ključnih reči, nije vektorska pretraga.
Zato što dugoročna memorija obično ima samo nekoliko desetina stavki, podudaranje ključnih reči je dovoljno i bez zavisnosti. Ako količina memorije dođe do nekoliko hiljada stavki, trebalo bi zameniti vektorskom pretragom.
Takođe smo dodali tri komande za upravljanje: /memory list prikazuje sve memorije, /memory search pretražuje prema vidljivosti trenutnog projekta, /memory delete briše pojedinačne stavke. Korisnik može videti šta je Agent zapamtio, da ima sigurnost.
04, Šta je RAG
Stari Wang menja temu: "Pričaj o RAG-u, prvo kaži svoje razumevanje."
Rekao sam: "RAG je Retrieval Augmented Generation. Osnovna ideja je vrlo jednostavna, pre nego što model odgovori, prvo se iz spoljašnje baze znanja pronalazi relevantan sadržaj, rezultati pretrage se ubacuju u prompt i zajedno šalju modelu."
Zašto Agent treba RAG?
Agent kaže "refakturuj login modul", ne zna gde je LoginService, koje metode ima, ko ga poziva.
Sav kod se stavi u kontekst? Projekat od 100 hiljada linija koda bi odmah prsnuo kontekst modela.
RAG rešenje je da pretraži samo relevantne delove koda. Korisnik pita "gde je login logika", RAG iz vektorske baze pronalazi relevantne metode LoginService i AuthController, samo nekoliko stotina linija koda se hrani modelu, precizno i ušteda tokena.
Stari Wang pita: "Kako izgleda ceo proces RAG-a u PaiCLI-ju?"
Rekao sam: "Dva koraka, prvo se gradi indeks zatim se pretražuje."
Pri građenju indeksa, izvorne fajlove koda se izvlače iz koda, dele se po sintaksi strukturi, zatim se svaki blok koda pomoću Embedding modela pretvara u vektor i čuva u SQLite bazu podataka. Korisnik pokreće /index komandom ovaj proces.
Pri pretrazi, upit korisnika se takođe pretvara u vektor, sa vektorima svih blokova koda u bazi računa se kosinusna sličnost, uzima se top-k blokova sa najvećom sličnošću i ubacuje u prompt.

Međutim postoji jedna važna promena.
PaiCLI najnovija verzija je RAG sa "glavne pretrage" spustila na "semantičku pomoć".

Stari Wang je zainteresovan: "Zašto je spušten?"
Rekao sam: "Zato što smo dodali dva alata precizne pretrage, jedan pretražuje kód u realnom vremenu prema ključnim rečima ili regularnim izrazima, drugi se podudara prema nazivu fajla glob pattern-om. Ova dva alata imaju nultu predobradu, nulto hladno pokretanje, za precizno pozicioniranje simbola su brza i tačna. RAG ima trošak hladnog pokretanja, prvo treba izgraditi indeks, ima Embedding kašnjenje, takođe gubitak preciznosti vektora. Tražite naziv klase UserService, precizna pretraga za jednu sekund daje rezultat, RAG mora prvo pretvoriti upit u vektor pa računa sličnost."
(Interno OS: rečeno, topovski pucaju na komarce, posao preciznog podudaranja prepustite preciznim alatima😏)
Trenutna strategija je: precizni simboli, nazivi fajlova, pozicioniranje stringova prvo ide na preciznu pretragu, samo kada je upit nejasan, ključne reči se teško određuju, ili mešovita pretraga koda i dokumenata ide na RAG. Ovaj prioritet je napisan u system prompt-u Agent-a, model će sam proceniti koji alat da koristi.

05, Kako se kod deli na blokove
Stari Wang pita: "Nedavno si rekao 'deli se po sintaksi strukturi', kako se to tačno radi?"
Rekao sam: "Deljenje na blokove je ključni deo RAG-a. Ako je blok pregrub, u fajlu ima 10 metoda ali samo jedna je relevantna, prilikom pretrage donosi mnogo nebitnog sadržaja. Ako je blok prefin, kod bez konteksta nema smisla."
PaiCLI ne reže po fiksnom broju linija, već koristi JavaParser za AST parsiranje, deli se po sintaksi strukturi.
Trenutna implementacija ima tri tipa chunkova:

- Nivo fajla: Za ne-Java fajlove ili kada Java parsiranje ne uspe; veliki fajlovi se dele po linijama na više fajl chunk-ova ne većih od oko 2000 karaktera.
- Nivo klase: Nakon što JavaParser parsira Java fajl, za svaku klasu ili interfejs se generiše class chunk. Trenutni class chunk uglavnom čuva početnih nekoliko linija deklaracije klase, služi za ulaz u naziv klase i strukturu, ne ubacuje celu klasu i sve metode.
- Nivo metoda: Za svaku metodu se generiše method chunk, sadržaj je kompletn izvorni kod metode, u nazivu nosi
NazivKlase.PotpisMetode, ovo je najvrednija granularnost pri odgovaranju "kako je logika implementirana".
Stari Wang nastavlja: "Zašto se ne reže po fiksnom broju linija?"
Rekao sam: "Rezanje po broju linija ima fatalni problem, može prepoliti metodu na sredini. Gornji deo je u bloku A, donji deo u bloku B. Kada se pronađe A, model vidi pola metode, ne zna šta metoda radi. AST parsiranje garantuje da je Java metod chunk kompletna sintaksična jedinica, izvorni kod se izvlači od početne do krajnje linije čvora deklaracije metode, pokušava se da se ne prereže metoda na sredini; za ne-Java velike fajlove se vraća na deljenje po linijama.

Stari Wang opet pita: "Šta sa Python kodom?"
Rekao sam: "PaiCLI trenutno ima AST deljenje samo za Java, ostali jezici se vraćaju na deljenje na nivou fajla. Ako treba uraditi opštu višejezičku podršku, može se koristiti tree-sitter, podržava sintaksi parsiranje desetina jezika."
06, Šta je Embedding
Stari Wang pita: "Objasni mi Embedding korak vektorizacije."
Rekao sam: "Embedding je mapiranje teksta u visedimenzionalni vektorski prostor. Dva odlomka sa sličnom semantikom, nakon mapiranja će imati vektore koji su bliži."

Na primer.
Korisnik traži "kod za obradu korisničkog logina", podudaranje ključnih reči može pronaći samo fajlove koji sadrže reči "korisnik", "login". Ali ako u kodu piše authenticate() i SessionManager, ništa se ne podudara. Embedding razume semantiku, "korisnički login" i authenticate + session su u vektorskom prostoru blizu, pretraga će pogoditi.
PaiCLI koristi Embedding model nomic-embed-text, lokalno radi na Ollama, besplatan ali zahteva instaliran Ollama na mašini. Generiše se niz od 768 float-ova, čuva se u SQLite bazi podataka.

07, Koji algoritam se koristi za vektorsku pretragu
Stari Wang pita: "Vektori su sačuvani, koji algoritam se koristi pri pretrazi?"
Rekao sam: "Kosinusna sličnost. Formula je cos(A, B) = (A · B) / (|A| × |B|), to je tačkasti proizvod dva vektora podeljen proizvodom njihovih dužina, opseg vrednosti je -1 do 1, što je bliže 1, to je sličnije."
Stari Wang nastavlja: "Zašto se bira kosinus a ne Euklidska udaljenost?"
Rekao sam: "Dva razloga. Prvi, kosinus gleda samo pravac ne i veličinu, nije podložan dužini vektora. Embedding dva odeljka koda mogu zbog različite dužine teksta imati vrlo različite dužine, kosinus nije ometan. Drugi, u visokodimenzionalnom prostoru Euklidska udaljenost ima problem 'katastrofe dimenzionalnosti', udaljenosti svih tačaka teže da budu iste, razlikovanje opada, kosinus je stabilniji."
PaiCLI nije uveo specijalnu vektorsku bazu podataka, samo čuva vektore u SQLite, pri pretrazi Java kod jedan po jedan računa kosinusnu sličnost, sortira i uzima top-k.
Brzopotezna pretraga ima kompleksnost O(n), za srednje i male projekte sa nekoliko hiljada blokova koda je potpuno dovoljna. Ako baza koda ima nekoliko miliona blokova, treba koristiti ANN algoritam približnog najbližeg suseda za ubrzanje — HNSW, IVF ove, ili direktno Milvus, Qdrant slične vektorske baze.

08, Šta je graf odnosa koda
Stari Wang pita: "U životopisu si još napisao i graf odnosa koda, kako se to odnosi na RAG?"
Rekao sam: "Ovo dva su komplementarna. RAG odgovara na "koji deo koda se odnosi na login", to je semantička pretraga. Graf odgovara na "ko poziva LoginService", "Kontroler UserController koje klase zavisi", to je strukturni upit."
PaiCLI koristi JavaParser za AST analizu, izdvaja pet strukturnih odnosa između elemenata koda: nasleđivanje, implementacija interfejsa, uvoz, poziv metoda, sadrži.
Ovi odnosi se čuvaju u SQLite, korisnik unosi /graph NazivKlase može videti kompletnu lanac relacija.

09, Da li je RAG još uvek neophodan nakon što su izašli modeli dugog konteksta
Stari Wang iznenada baca "glavnu bombu": "Sada DeepSeek V4 već ima 1M prozor, da li RAG još uvek ima razlog da postoji?"
(Interno OS: klasiko visoko frekventno intervju pitanje, mirno🤣)
Rekao sam: "Ima, ali se uloga promenila."
Prva je preciznost pažnje. Model pažnja na informacije u sredini dugog teksta opada, ovo je problem Lost in the Middle. RAG unapred izdvaja najrelevantniji sadržaj i stavlja ga na istaknutu poziciju, tačnost je veća.
Druga je previše velika baza koda. Spremnik od 50 hiljada linija koda, 1M prozor ne može stati.
Stari Wang pita: "Kako to PaiCLI rešava?"
Trenutna osnovna pravila su:
| Parametar | Pravilo |
|---|---|
| Linija za sažimanje | maxContextWindow * 90% |
| Budžet kratkoročne memorije | maxContextWindow * 45% |
| Gornja granica ubacivanja dugoročne memorije | min(5000, max(500, window / 200)) |
| Indeks MCP resursa | window ≥ 32k se uključuje |
search_code više ne reže topK na 5/10/20 automatski prema prozoru. Podrazumevana vrednost alata je top_k=5, može se eksplicitno proslediti parametar, maksimalno 30.
Agent treba prvo koristiti grep_code / glob_files / read_file za precizno pozicioniranje; samo kada korisnikov opis je vrlo nejasan, ključne reči se teško određuju, obična pretraga više krugova ne daje rezultat, poziva search_code za semantičku pomoć.
Najnovija verzija ima i dopunu — RAG više nije jedini put za pretragu koda. Agent dobija upit, prvo koristi alate precizne pretrage za podudaranje, samo kada ne može da reši nejasan upit ide na RAG. Zato čak i ako nije unapred izgrađen indeks, Agent i dalje može razumeti bazu koda kroz preciznu pretragu, RAG je postao dodatna vrednost a ne neophodan preduslov.

10, Šta je Prompt Caching
Stari Wang pita pitanje vezano za troškove: "Da li ste radili na Prompt Caching-u?"
Rekao sam: "Da, i Agent scenario prirodno odgovara caching-u."
Prompt Caching je optimizacija na strani servera dobavljača modela — ako se prefiksi prompta uzastopnih zahteva poklapaju, server može ponovno iskoristiti keširani prefiks, preskoči deo dupliranog računanja. Različiti dobavljači imaju različita pravila naplate, PaiCLI ne pretpostavlja popust na naplatu, samo je zadužen za prepoznavanje i prikaz tokena keširanja u odgovoru.
Agent-ov obrazac zahteva savršeno odgovara ovom mehanizmu.

system prompt se svaki krug isti, savršen je keširani prefiks. Istorija razgovora se dopisuje, novi zahtev je jednak starom plus nova poruka, veći deo prefiksa se ponavlja.
PaiCLI pri sastavljanju prompt-a sledi princip "što je stabilniji sadržaj, to je više napred": system prompt, postava ličnosti, uputstva za režim, ovi stabilni sadržaji idu napred, kontekst projekta, indeks veština, memorija i drugi dinamični sadržaji idu pozadi. Lakše se omogućuje da prefiks keš dobavljača pogodi.
DeepSeek koristi automatic prefix cache; GLM, Kimi, Step takođe su deklarisali odgovarajući prompt cache mode u LlmClient. PaiCLI iz polja cached_tokens, prompt_cache_hit_tokens, input_cache_hit_tokens analizira količinu keširanja i prikazuje je u statusnoj traci.
11, Koje strategije postoj za sažimanje konteksta
Stari Wang pita: "Pored Map-Reduce sažetka koji vi koristite, da li postoje i druge strategije sažimanja?"
Rekao sam: "Tri glavne."
Prva je metoda odsecanja, najjednostavnija i najgrublja, direktno se odbacuje najstariji razgovor.
Druga je metoda sažetka, ovo što PaiCLI koristi. Model generiše sažetak ranijeg razgovora, sažetak zamenjuje original. Čuva se semantika, ali sam sažetak troši jedan poziv modelu.
Treća je selektivno zadržavanje. Zadržava se samo system prompt + poslednjih N krugova + svi rezultati poziva alata, "nebitni ćask" se odbacuje. Potrebno je proceniti šta je "nebitni ćask", implementacija je komplikovanija.
Stari Wang opet pita: "Kako se bira trenutak sažimanja?"
U PaiCLI-ju treba razlikovati dva tipa sažimanja, ne mešati zajedno.
Prvo je sažimanje kratkoročne memorije unutar sistema memorije. Tačka okidača je posle upisa u kratkoročnu memoriju: kada se sačuvaju korisnička poruka, odgovor pomoćnika, rezultat alata, odmah se poziva compressIfNeeded().
Uslovi su da zauzeće tokena kratkoročne memorije dostigne prag, trenutni kod podrazumeva 90%. Budžet kratkoročne memorije je 45% prozora modela, otprilike gledano: DeepSeek 1M prozor pod kratakoročnu memoriju otprilike 450k * 90% = 405k tokena će se sažimati; GLM 200k je otprilike 81k tokena.
Drugo, to je sažimanje conversationHistory.
Ovo je stvarna lista poruka koju Agent šalje LLM-u, sprečava prskanje kontekstnog prozora. Njegov trenutak okidača je pre svakog poziva LLM-a, ne posle završetka zadatka, ne tek kada se greška pa sažima.
ReAct glavna petlja, Plan svaki zadatak izvršna petlja, Multi-Agent SubAgent petlja, sve proveravaju jednom pre pokretanja sledećeg LLM zahteva. Ako se proceni da trenutni conversationHistory dostiže maxContextWindow * 90%, pokreće se sažimanje.
Zato računato po modelu, prag sažimanja conversationHistory je otprilike:
- DeepSeek V4:
1,000,000 * 90% = 900,000 tokena - GLM-5.1:
200,000 * 90% = 180,000 tokena - Step / Kimi:
256,000 * 90% = 230,400 tokena
Način sažimanja se reže po granici user message, zadržava poslednja 3 korisnička kruga, starije poruke se predaju LLM-u da sažmu u jedan sažetak, zatim se rekonstruiše:
system
[sažeta istorija razgovora]
assistant: Dobro, razumem prethodni kontekst, nastavite.
poslednje poruke od početka 3. korisnička krugaOvo se radi da se izbegne prekidanje para assistant tool_call i tool result. Inače lako može doći do situacije da je prethodni assistant rekao da će pozvati alat, ali je rezultat alata odsečen.
U jednoj rečenici: PaiCLI-jevo sažimanje ne čeka da model javi prekoračenje, već proverava svaki krug pre LLM zahteva. Trenutna implementacija koristi 90% prozora kao jedinstavnu liniju okidača.
12, Zašto format poruka istorije razgovora mora strogo da sledi protokol
Stari Wang pita pitanje koje izgleda jednostavno ali ima mnogo zamki: "Kakva su pravila za format poruka?"
Rekao sam: "API za razgovor modela ima stroga pravila za format poruka. Četiri uloge, system je sistemska uputstva, user je korisnički unos, assistant je odgovor modela, može sadržati poziv alata, tool je rezultat vraćen alata, mora sadržati tool_call_id i odgovarajući poziv alata."
Stari Wang pita: "Šta ako se ne sledi?"
Rekao sam: "Odmah greška ili model je zbunjen. tool poruka nema odgovarajući tool_call_id? API vraća 400. Red assistant i user je poremećen? Model ne može da razlikuje ko šta je rekao. Rezultat alata se stavi u user poruku?"
Rekao sam: "Kod sažimanja postoji jedna laka zamka. Ako sažetana poruka sadrži poziv alata i odgovarajući rezultat alata, sažetana assistant poruka ne može zadržati polje tool_calls. Zato što je odgovarajuća tool poruka već "pojeo" sažetak, ali se tool_calls i dalje nalazi u assistant poruci, API će primetiti da postoji tool_call_id koji nema odgovarajući tool rezultat, odmah javi grešku."

13, Kako optimizirati loše rezultate RAG pretrage
Stari Wang poslednje pitanje: "Ako rezultati RAG pretrage nisu tačni, kako optimizuješ?"

Rekao sam: "Četiri smera."
Prvi je optimizacija strategije deljenja.
Promena sa fiksnog broja linija na semantičko deljenje, reže se po granicama metoda, klasa, pasusa, osigurava se da svaki blok ima kompletnu semantiku. PaiCLI AST parsiranje upravo radi semantičko deljenje. Takođe se može dodati konteks roditeljskog nivoa u svaki blok, npr. naziv pripadajuće klase i import informacije, pomaže modelu da razume poziciju odlomka koda u projektu.
Drugi je korišćenje specijalizovanog Embedding modela.
Treći je hibridna pretraga. Najnovija verzija PaiCLI-ja je upravo primena ove ideje, alat precizne pretrage je zadužen za pozicioniranje ključnih reči, RAG je zadužen za semantičku pokrivenost. Iako nije tradicionalno jedinstveno fuzionisano rangiranje, u scenariju višekružnog poziva Agent alata efekat je sličan — prvo se precizno traži, ako se ne pronađe, semantička pokrivenost.
Četvrti je prepisivanje upita. Upiti korisnika su četo vrlo usmeni, "login taj kod" se prepisuje u "kod za implementaciju autentikacije korisnika i upravljanja sesijom", Embedding semantičko podudaranje će biti mnogo tačnije. Ovo prepisivanje se može obaviti jednim laganim pozivom modela.
Stari Wang zatvara bilježnicu, zadovoljan izgledom: "Može, memorija i RAG si zaista radio, nisu na papiru."
ending
Naziv projekta: PaiCLI — Java Agent CLI (uporediv sa Claude Code-om)
Opis projekta: Terminalski AI Agent implementiran od nule, ugrađena trosloučna arhitektura memorije (kratkoročna/dugoročna/RAG spoljašnja), izolacija memorije na nivou projekta, stratifikovana strategija pretrage koda prioritet precizne pretrage + RAG semantička pokrivenost, inženjering adaptivnog dugog konteksta koji podržava modele od 200k-1M prozora.
Tehnološki stack: Java 17, JavaParser AST, Ollama nomic-embed-text Embedding, SQLite, Map-Reduce, NIO FileVisitor
Ključne odgovornosti:
- Dizajniranje trosloučne arhitekture memorije, kratkoročna memorija upravlja istorijom razgovora, dugoročna memorija trajno čuva činjenice preko sesija u JSON fajlove (podržava dvostruku izolaciju opsega project/global)
- Implementacija stratifikovane strategije pretrage koda prioritet precizne pretrage + RAG semantička pokrivenost, precizna pretraga u realnom vremenu skenira stablo fajlova projekta prema ključnim rečima/regularnim izrazima za pozicioniranje simbola, podudaranje naziva fajlova prema glob uzorku, RAG koristi Embedding vektorsku semantičku pretragu za nejasne upite
- Na osnovu JavaParser implementirano AST nivo deljenje koda, deli se po tri granularnosti metod/klasa/fajl, osigurava se da je svaki chunk semantički potpun
- Implementirana dva kontekstna sažimanja: Map-Reduce sažetak za kratkoročnu memoriju; pre svakog LLM poziva sažima se stvarna istorija poruka, zadržava se poslednja 3 kruga po granici user, izbjegava se prekidanje protokola tool_call / tool_result
