Sedam principa prave memorije — naslovna

Deo 2 od 3 — „Memorija za AI agente” Arhitektura. Konkretno. Sa formulama i lifecycle-om.

U prethodnom postu razložio sam pitch „RAG = memorija” na tri neugodna problema: chunk ne zna da je chunk; retrieval nema strukturu, samo cosine; vreme ne postoji kao first-class koncept. Ukratko — RAG je pretraga obučena u marketinšku reč „memorija.”

Danas — šta bi trebalo da bude umesto toga.

Odmah disclaimer. Ne tvrdim da sam izmislio nijednu stavku sa ove liste. Atomske činjenice idu unazad do Wittgensteina. Temporal validity je osnovna logika. Knowledge graph-ovi su celo polje sa udžbenicima. Lifecycle za podatke je standard u svakom normalnom informacionom sistemu.

Tvrdim nešto drugačije. Tvrdim da svih sedam osobina mora da radi u jednom sistemu istovremeno, i da bilo koji sistem u kome zapravo radi samo pet od sedam nastavlja da laže korisniku samouverenim licem. Postoji samo jedan način da se to vidi — pokušaj da sklopiš svih sedam u jedan kodbeis i posmatraj šta se dešava.

Probao sam. Radilo je. Nazvao sam ga braincore. Open source, Apache-2.0, jedan Go binary, MCP-stdio. Neću pretvoriti tekst u pitch — ali u svakoj sekciji ispod dodaću jednu liniju o tome kako se to radi u braincore-u, da bude jasno da ne pričamo teoriju.

Idemo.


Princip 1. Atomic Knowledge Units sa lifecycle-om, ne „chunk-ovi u Qdrant-u”

Bol. U RAG-u, bilo koji dolazni tekst — dijalog, design dokument, git commit, transkript sastanka — biva isečen na chunk-ove i poslat u vektor bazu bez pitanja. Odatle, šta god da se dešava — svi chunk-ovi su ekvivalentni, svi podjednako „sveži,” svi podjednako „istiniti.” Šest meseci kasnije, jedna kolekcija drži supu od zastarelih, trenutnih, hipotetičkih i opovrgnutih činjenica. I svaka od njih ima tačno jednu šansu da uđe u retrieval — preko cosine.

Šta bi trebalo da bude u shemi. Bilo koja dolazna informacija ne ulazi u memoriju direktno. Prolazi kroz pipeline:

input
  → initial trust (po izvoru: user=0.9, llm=0.3, web=0.4..0.7)
  → parse (entity / fact / relation / event / rule / hypothesis)
  → atomic knowledge units
  → validate (source / graph / dedup / contradiction / temporal / rule)
  → link (najmanje 1 ivica u graf ILI review item)
  → working memory (TTL + activation)
  → iterative verification loop
  → consolidation
  → long-term memory (samo potvrđeno + povezano)
  → edge strengthening (usage + success + co-occurrence − decay)

Osnovno pravilo: ništa ne ulazi u long-term memory odmah. Svaka atomic knowledge unit ima minimalno:

  • truth_status: hypothesis | candidate | confirmed | contradicted | deprecated
  • lifecycle: staging | working | consolidated | archived
  • source_ref — odakle je došlo
  • confidence — numerička procena sigurnosti
  • valid_from / valid_until — kad je istinito

Uporedi to sa RAG chunk-om koji ima samo text i embedding. To je razlika između fioke za smeće i magacina sa inventarom.

Šta to omogućava. Kad si juče rekao „koristimo Postgres” a danas „prešli smo na ClickHouse, Postgres je sada samo OLTP” — stara činjenica automatski dobija valid_until = today i superseded_by = new_fact_id. Pri retrieve-u, ili se uopšte ne pojavljuje, ili dolazi obeležena „istorijsko, ne trenutno.” Ne zbog pametnog modela. Zbog sheme.

Kako braincore to radi. Pipeline staging → working → consolidated je implementiran bukvalno — tri odvojene SQLite tabele plus posrednu verification loop. Zapis dospeva u consolidated samo ako je truth_status = confirmed, ima bar jednu graf ivicu, nema nerešenih kontradikcija, i confidence ≥ threshold. Inače ostaje u working sa TTL-om, ili se premešta u review queue.


Princip 2. Strict Mode i pravo na abstain

Ovo je možda najvažnija tačka u celoj seriji. I najodsutnija iz komercijalnih memory framework-a.

Bol. Standardna metrika po kojoj se AI sistemi mere — „koliko često daju ispravan odgovor.” Ovo je trula metrika. 95% tačnih odgovora i 5% sigurnih halucinacija je sistem kome ne možeš verovati u produkciji. Jer ne znaš unapred u kojih 5% si trenutno.

Prava metrika glasi:

0% sigurno-pogrešnih akcija pri prihvatljivom abstain rate-u.

Ne „uvek odgovori.” Već „nikad ne preduzimaj pogrešnu akciju bez verifikacije.” A ako verifikacija nedostaje — reci „ne znam” i sam sebi dodeli zadatak da to popraviš.

Šta bi trebalo da bude u shemi. Pre nego što činjenica dospe u prompt kontekst, prolazi kroz vrata:

  • da li postoji source_ref?
  • confidence ≥ threshold?
  • trust_score ≥ threshold (za izvor)?
  • temporal_valid == true (validno u vreme upita)?
  • nema nerešenog contradiction u grafu?
  • nema nerešenog ambiguity?

Ako čak jedan zahtev ne uspe — činjenica ne stiže do konteksta. Ako nijedna činjenica nije prošla za upit — sistem vraća abstain = true sa reason = no_accepted_facts (ili contradiction_unresolved, ili temporal_invalid — uvek eksplicitno).

I — pažnja, ovde se dešava magija — abstain se ne dostavlja korisniku kao ćorsokak. Postaje brain task u backlog-u: „Treba mi dokaz za X da odgovorim sa sigurnošću. Izvor je tu, konkretan konflikt je tu.” Sistem zna šta ne zna, i sam sebi dodeljuje zadatak da to popravi.

Šta to omogućava. AI agent kome možeš verovati. Ne zato što je uvek u pravu — već zato što kad nije siguran, ćuti ili traži razjašnjenje. A kad preduzima akciju — akcija je utemeljena na činjenicama koje su prošle vrata, ne „pa, ChatGPT je mislio da je ovo bolje.”

Pokaži mi jedan RAG stack koji to radi. Sačekaću.

Kako braincore to radi. Paket internal/strictmode je odvojen modul sa eksplicitnim pravilima vrata. Po default-u, svaki upit prolazi kroz strict mode; za UX scenarije gde abstain nije prihvatljiv (brainstorming, na primer), možeš ga isključiti eksplicitnim flag-om --allow-uncertainty. Svi abstain događaji se loguju kao brain tasks sa svojim izvorom i razlogom.


Princip 3. Causal Decision Chains, ne ravne činjenice

Bol. U RAG-u, bilo koja odluka se čuva kao „tekst o odluci.” Pri retrieve-u, dobiješ komad teksta koji opisuje odluku — ali ne odgovara na „zašto?”, „koje smo alternative razmatrali?”, „šta je iz toga ispalo?”

Šest meseci kasnije, pitaš „zašto smo izabrali JWT umesto sesija?” — RAG vraća tri fragmenta deklaracije, i model sam popunjava reasoning. Ponekad ispravno. Ponekad izmišlja iz popularnih pattern-a u svojim trening podacima. Ne znaš koje od to dvoje je ovog puta.

Šta bi trebalo da bude u shemi. Entitet nije „dokument” niti „memory entry.” Entitet se zove decision i ima shemu:

problem      → šta smo rešavali
alternatives → šta smo razmatrali i odbacili (sa razlozima)
decision     → šta smo izabrali
reasoning    → zašto baš to
outcome      → šta je iz toga ispalo (popunjava se kasnije, post-hoc)
superseded_by → link na novu odluku ako je ova revidirana

Ovo nije „daj da nabacimo tekst u embedding.” Ovo je kauzalni lanac koji odgovara na ZAŠTO, ne samo na ŠTA.

Šta to omogućava. Šest meseci kasnije, pitaš „zašto JWT?” — sistem vraća strukturirani odgovor:

  • Problem: skaliranje sesija + audit zahtevi.
  • Alternatives (rejected): stateful sesije sa Redis-om (krši audit), opaque tokeni sa centralizovanim lookup-om (latency).
  • Decision: JWT sa kratkim TTL-om.
  • Reasoning: stateless, audit-neutralan, latency prihvatljiv.
  • Outcome (zabeleženo 4 meseca kasnije): kompleksnost invalidacije veća od očekivane; dodali refresh tokene.
  • Superseded by: none.

RAG vraća tri fragmenta. Decision chain vraća reasoning. To su različiti proizvodi.

Kako braincore to radi. Decisions su odvojen tip entiteta u grafu sa obaveznim poljima problem, alternatives[], decision, reasoning, i opcionim outcome/superseded_by. Čuvaju se ne kao chunk-ovi već kao strukturirani zapisi sa eksplicitnim ivicama u code graph i u druge decisions.


Princip 4. Stabilan identitet koda kroz AST, ne stringove

Bol. Ovaj princip je specifičan za AI agente koji rade sa kodom — ali pogađa sve njih. Preimenovao si GetUser → FetchUser, premestio iz pkg/auth u pkg/user, promenio signaturu sa pointer receiver-a na value receiver. Sve reference u RAG memoriji koje pokazuju na „GetUser u pkg/auth” sad su mrtve. Jer je RAG vezan za stringove.

I niko ti to ne kaže. Chunk nastavlja da živi u Qdrant-u, njegov cosine na auth-related upite ostaje visok. Agent vuče mrtvu informaciju i radi protiv nje. Čestitke, imaš memory rot maskiran kao memorija.

Šta bi trebalo da bude u shemi. Parsiranje koda kroz go/ast (za Go) i tree-sitter (za PHP, JS, TS, Python, Rust, Java, i dalje). Identitet čvora se gradi ne od stringa i ne od putanje fajla, već od strukturnog hash-a:

node_id = sha256(qualified_name + kind + signature_hash)

Što znači:

  • Preimenovanje funkcije ne lomi reference ka njoj (qualified_name se promenio, ali se link automatski ažurira pri sledećem parse-u, sa back-referencom na stari node_id kao renamed_from).
  • Premeštanje između paketa — ista stvar.
  • Promena signature (pointer → value receiver) — signature_hash se menja, i stare reference automatski se obeležavaju kao stale — mozak zna da sada zahtevaju review.

Šta to omogućava. Kad AI agent treba da edituje FetchUser, sistem podiže tri prethodne odluke o toj funkciji, dve regresije u ovom modulu, i aktivna pravila projekta — pre nego što agent počne da piše kod. Ne zato što se cosine slučajno poklopio. Već zato što je to code graph, i FetchUser ima ivice ka odlukama, regresijama i pravilima po identitetu, ne po tekstualnoj sličnosti.

Ovo nazivam pre-edit warning. I to je kvalitativno drugačija vrsta prevencije grešaka od „hajde da pokrenemo linter posle generacije.”

Kako braincore to radi. Code graph je odvojen sloj iznad AST/tree-sitter, sa background reindex-om na filesystem watch događaje. Identity hash-evi žive u SQLite, ivice takođe tu. Pri pre-edit hook-u, agent dobija kontekst povezanih decisions/rules/regressions automatski.


Princip 5. Internal Git kao memory versioning

Bol. RAG nema koncept vremena izvan created_at. To su metapodaci o zapisu, ne o stanju znanja. Ne možeš da pitaš „pokaži mi šta sam znao o ovom kodu pre mesec dana.” Ne možeš da rollback-uješ stanje memorije pre nego što je agent dovukao smeće. Ne možeš da pređeš na feature granu i imaš paralelno mentalno stanje za nju.

Šta bi trebalo da bude u shemi. Svaka promena u memoriji je commit. Ne metaforički. Bukvalno, kroz go-git, u skriveni .internal-git/ repozitorijum koji živi paralelno sa glavnim repo projekta.

To ti daje:

  • git log preko memorije projekta — šta je dodato, šta se promenilo, kad.
  • git checkout da bi rollback-ovao stanje mozga unazad N dana — za audit, za istraživanje regresija, za testove.
  • Kad pređeš na feature granu u glavnom repo-u, mozak to ogleda, i svaka grana ima svoje mentalno stanje. Eksperiment u feature grani ne zagađuje master memoriju.

Šta to omogućava. Time-travel upiti: „koju sam odluku smatrao trenutnom pre 30 dana?” Audit: „kad je tačno agent počeo da veruje da koristimo ClickHouse?” Branch izolacija: „u feature/oauth imamo drugačiji pristup auth-u, ali to znanje ne bi trebalo da curi u main.”

RAG to ne može. RAG nema koncept „stanje znanja” — samo set vektora koji raste.

Kako braincore to radi. .internal-git/ se kreira pri braincore init. Commit-ovi se prave automatski pri svakoj promeni knowledge units i graf ivica. Branch tracking je sinhronizovan sa glavnim git-om kroz post-checkout hook.


Princip 6. Memory Scoring — jer nije svako znanje jednako

Bol. U RAG-u, svi chunk-ovi su jednaki. Top-k po cosine ne razlikuje „ovo je potvrđeno deset puta u prošlom korišćenju” od „ovo je napisano juče i nikad više nije korišćeno.” Ne razlikuje „ovo je kritično za arhitekturu” od „ovo je slučajna beleška u uglu.” Ne razlikuje „ovo je u aktivnoj upotrebi” od „ovo skuplja prašinu od prošle godine.”

Šta bi trebalo da bude u shemi. Svaka knowledge unit ima kompozitni MemoryScore, izračunat kao otežana suma:

MemoryScore =
  + 0.22 * ImportanceScore     (eksplicitna važnost ili izvedena iz povezanosti)
  + 0.22 * TrustScore          (pouzdanost izvora + istorija potvrda)
  + 0.20 * TaskRelevanceScore  (relevantnost za trenutni kontekst rada)
  + 0.12 * UsageScore          (koliko često se koristi)
  + 0.10 * RecencyScore        (svežina)
  + 0.10 * StabilityScore      (koliko često se menja — stabilno je pouzdanije)
  + 0.08 * NoveltyScore        (novost kao mali boost)
  − 0.18 * RiskScore           (potencijalna šteta od korišćenja)
  − 0.18 * NoiseScore          (šum, duplikati, niska koherentnost)

I pri retrieve-u, ono što radi više nije cosine similarity, već:

RetrievalScore =
  + 0.35 * semantic_similarity
  + 0.20 * memory_score
  + 0.15 * graph_relevance
  + 0.15 * temporal_validity
  + 0.10 * trust_score
  − 0.15 * ambiguity_penalty

Ovi težinski koeficijenti nisu apsolutna istina — empirijski su podešeni i pomeraju se sa profilom korišćenja. Poenta nije u brojevima, već u arhitektonskom pomeranju: retrieval prestaje da bude „tekstualna sličnost” i postaje „sličnost × važnost × poverenje × svežina.”

Lifecycle prelazi automatski:

  • memory_score ≥ 0.80 i trust ≥ 0.75consolidated (znanje postaje „firmware”)
  • memory_score ≥ 0.55 → ostaje u working
  • memory_score ≥ 0.30staging
  • memory_score < 0.30archive candidate

Šta to omogućava. Aktivnu memoriju. Ne skladište. Aktivno okruženje u kome se važno jača kroz korišćenje, a šum sam opada — kao u biološkom mozgu, gde retko korišćene sinapse slabe a često korišćene jačaju.

RAG = hard disk koji se nikad ne defragmentira. Brain = mozak u kome đubre samo se sleže i automatski arhivira.

Kako braincore to radi. Scoring se ponovo računa background job-om svakih N sati. Lifecycle prelazi su atomski i logovani (vidi Princip 5). Svi težinski koeficijenti su izloženi u config-u — podesi ih po projektu.


Princip 7. Negative Memory i Rule Engine

Bol. Evo šta svaki LLM agent radi danas: ponavlja greške. Juče je polomio migraciju — danas će polomiti sličnu. RAG neće pomoći, jer polomljena migracija ne ulazi u RAG. Ono što ulazi u RAG je „kako pisati migracije” iz zvanične dokumentacije. Činjenica da si ti lično već stao na ove grabulje — nigde nije zabeležena.

Šta bi trebalo da bude u shemi. Odvojena klasa — negative memory: šta se polomilo, zašto se polomilo, kako je popravljeno, koji commit/test to potvrđuje. First-class entitet, ne marginalno polje.

I pri planiranju, svaki patch prolazi kroz Rule Engine pre generacije koda:

patch
  → architectural rules
  → code rules
  → security rules
  → performance rules
  → anti-patterns (uključujući „ovaj baš sam pre lomio")
  → repair plan ILI abstain

Ako je prekršeno pravilo sa severity critical ili highkod se ne piše. Kreira se repair plan. Ako je popravka nemoguća — abstain (vidi Princip 2). Bez „nadajmo se da ovo prođe” generacije.

I, kritično, safe execution pipeline zatvara petlju:

checkpoint
  → apply patch
  → rules validate
  → build
  → tests
  → success → commit
  → fail → rollback → zapis u negative memory

Svaka izvršena akcija je ili potvrđena testovima, ili rollback-ovana, ili zapisana kao negative evidence za buduće odluke.

Šta to omogućava. Agenta koji ne može da ponovi tvoju prošlogodišnju grešku. Ne zato što ima odličan model — već zato što rule engine fizički odbija da pusti bilo kakav patch koji krši pravilo izvedeno iz te greške.

RAG pomaže agentu da nešto nađe. Dobra memorija sprečava agenta da nešto polomi.

To su različiti proizvodi. I žao mi je onih koji ih nastavljaju da mešaju.

Kako braincore to radi. Negative memory je odvojen tip entiteta sa obaveznim linkom na failing test ili git commit. Rule engine je pre-execution gate, severity-aware, sa override mogućim samo kroz eksplicitnu korisnikovu potvrdu.


Bonus princip. Entity Disambiguation

Formalno specijalan slučaj Principa 1 (atomske jedinice), ali se lomi odvojeno dovoljno često da zaslužuje svoj poziv-aut.

U RAG-u, ne postoji koncept entiteta. Postoji samo tekst. Ako tvoj projekat ima dve User klase — jednu u pkg/auth, drugu u pkg/billing — za RAG to su dva komada teksta sa sličnim embedding-ima. Pri retrieve-u, mešaju se, i model samouvereno objašnjava auth logiku u kontekstu billing-a.

Ovo nije teorija. Ovo se dešava upravo sad u svakom code RAG agentu.

Popravka — EntityFingerprint:

fingerprint(symbol) = hash(
  project_id +
  file_path +
  symbol_name +
  symbol_type +
  signature +
  language
)

Dva User entiteta u različitim fajlovima = dva fingerprint-a = dva različita entiteta koji se nikad automatski ne spajaju. Kad stigne novi kandidat, izračunava se SameEntityScore:

SameEntityScore =
  + 0.30 * name_similarity
  + 0.20 * alias_match
  + 0.20 * context_similarity
  + 0.15 * graph_neighborhood_similarity
  + 0.10 * temporal_consistency
  + 0.05 * source_consistency

I:

  • ≥ 0.92auto_merge
  • ≥ 0.82same_as link (mekan link, ne merge)
  • ≥ 0.65ambiguous — kreira se ambiguity record, koji zahteva ljudski review
  • inače — novi entitet

Osnovno pravilo: nikad ne spajaj entitete pri niskom confidence-u. Bolje kreirati ambiguity zapis i pitati čoveka, nego ih tiho zalepiti i lagati zauvek posle.


Zašto sve ovo zajedno

Namerno ne uobličavam ovo kao „nigde ovo nije urađeno, prvi sam.” Svaki od sedam principa već postoji. Atomske činjenice sa lifecycle-om — u sistemima knowledge management. Strict mode + abstain — u expert sistemima prošlog veka. Kauzalni lanci — u alatima decision support. AST identitet — u IDE-ima. Internal git — u alatima poput Pijul-a i u Datalog database eksperimentima. Memory scoring — u istraživačkim radovima o episodic memory. Negative memory — u RL i reliability engineering-u.

Jedinstvenost nije u idejama. To je u sklapanju.

Ako imaš atomske jedinice ali nemaš strict mode — imaš strukturiranu bazu halucinacija. Ako imaš strict mode ali nemaš kauzalne lance — odbijaš bez razumevanja zašto. Ako imaš kauzalne lance ali nemaš AST identitet — tvoje odluke pokazuju u prazno posle dva refaktorisanja. Ako imaš sve gore navedeno ali nemaš memory scoring — imaš savršeno strukturiran dump u kome važno tone u šumu.

Svaka osobina izolovano je poboljšanje. Svih sedam zajedno je drugačija kategorija proizvoda.

Ovo je, uzgred, odgovor na pitanje koje najčešće dobijam: „zašto pisati nešto novo ako već imam Mem0/Letta/Zep?” Odgovor — pogledaj njihove sheme i proveri koliko od sedam principa je implementirano ne kao marketinški claim, već kao enforced gate u kodu. Za većinu, iskren broj je dva ili tri. Za neke — četiri. Nisu loši proizvodi. Oni su delimična rešenja, koja je iskrenije zvati „structured retrieval” nego „memorija.”


U Delu 3

Sedam principa je inženjering. Šta bi trebalo da bude u arhitekturi. Ali iza inženjeringa stoji dublje pitanje: zašto bi AI agent trebalo da zna šta ne zna? Zašto uopšte abstain, ako može jednostavno da odgovori?

Deo 3 je o pravu AI agenta da ćuti. O self-tasking-u. O tome zašto je kognitivni runtime važniji od veličine modela. I o tome zašto prava metrika za produkcijski AI nije accuracy, već zero confidently-wrong actions at an acceptable abstain rate.

To je najkraći i najfilozofskiji deo serije. Izlazi sledeće nedelje.


Deo 2 od 3. Ako si propustio Deo 1 — ovde (o tome zašto je RAG pretraga a ne memorija). Ako je odjeknulo — repost bi pomogao.