Anatomija AI sistema koji radi dok spavam

Pre nekih godinu i po dana, ContentStudio je bio cron job i dva Python skripta zalepljena selotejpom. Ako bi OpenAI vratio 500-icu u 3 ujutru, ustao bih u 9, video 47 email upozorenja i ručno restartovao pipeline. Danas taj isti sistem radi po pet, sedam dana bez mog dodira, publikuje na više sajtova, i sam se popravi kad nešto pukne. Evo kako izgleda anatomija tog sistema, iz prve ruke.
Šta znači "radi dok spavaš" u praksi
Autonoman sistem nije onaj koji nema greške. To je onaj koji greške tretira kao normalno stanje. Konkretno, moj kriterijum je: sistem sme da radi minimum 72 sata bez ijednog ljudskog dodira, uz dokazivo isporučen rezultat (objavljeni članci, ažurirani indeksi, poslati izveštaji), i uz jasno stanje u svakom trenutku ako moram da uskočim.
Tri stvari to omogućavaju:
- Multi-agent pipeline koji razdvaja odgovornosti (istraživanje, pisanje, optimizacija, publikacija) tako da otkaz jednog koraka ne ruši ostale.
- Raspoređeni radnici (scheduled workers) koji rade u malim, idempotentnim koracima, ne u jednom velikom job-u.
- Self-healing kroz retry sa backoff-om, checkpoint stanje u bazi, i dead-letter red za ono što ne može automatski.
Ako bilo koja od ove tri stvari fali, sistem će raditi noć ili dve, pa će te probuditi.
Multi-agent pipeline: razdvoj odgovornosti, ne agente
Najveća greška koju vidim kod ljudi koji prave "AI agente" je da naprave jednog velikog agenta sa 40 tool-ova i molitvom da će Claude izabrati pravi redosled. To radi na demou. U produkciji, taj isti agent posle 200 poziva krene da halucinira redosled, ili zaglavi u petlji "istražujem pa razmišljam pa istražujem".
Moj ContentStudio ima jasno razdvojene faze. Svaka faza je zaseban proces sa svojim promptom, svojim output šemom (Zod ili Pydantic), i svojim ulazom iz baze:
| Faza | Šta radi | Trajanje | Šta prosleđuje |
|---|---|---|---|
| Research | Bira temu iz keyword pool-a, radi SERP + interni RAG | 30-90s | Brief JSON |
| Outline | Pravi H1/H2 strukturu, primary + secondary keywords | 10-20s | Outline JSON |
| Draft | Piše sekciju po sekciju, ne ceo članak odjednom | 2-5 min | Markdown |
| Optimize | SEO/AEO pass, interni linkovi iz vector DB | 20-40s | Finalni markdown |
| Publish | Push na CMS API, verifikuje HTTP 200 + URL live | 5-15s | Post URL |
Ključno je da faze komuniciraju preko baze, ne preko memorije. Svaka faza pročita svoj ulaz iz Postgres tabele (briefs, outlines, drafts), radi svoj posao, upiše rezultat sa status = 'ready_for_next', i završi. Sledeći radnik pokupi.
Ovo je dosadno. I zato radi. Ako Draft faza pukne na članku #7, članak #6 je već publikovan, članak #7 ostaje u status = 'draft_failed', i članci #8-15 nastavljaju normalno jer njihovi Brief-ovi i Outline-ovi su spremni.
Raspoređeni radnici i idempotentnost
Ne verujem jednom velikom cron job-u koji radi jednom dnevno u 03:00 i pokušava sve. Umesto toga, imam male EventBridge (na AWS-u) ili node-cron radnike koji rade svaki 5-15 minuta i pitaju bazu: "ima li nešto za mene?"
Pseudo-primer za Draft radnika:
// draft-worker.ts, pokreće se svakih 10 min
async function tick() {
const job = await db.query(`
SELECT * FROM outlines
WHERE status = 'ready_for_draft'
AND locked_until < NOW()
ORDER BY priority DESC, created_at ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
`);
if (!job) return;
await lockJob(job.id, '15 minutes');
try {
const draft = await generateDraft(job);
await saveDraft(job.id, draft); // status -> 'ready_for_optimize'
} catch (err) {
await recordFailure(job.id, err);
// retry_count++, ako > 3 -> dead_letter
}
}
Tri detalja koja ljudi preskoče:
FOR UPDATE SKIP LOCKEDznači da dva radnika mogu da rade paralelno bez konflikta. Postgres im automatski daje različite redove.locked_untilje zaštita ako radnik pukne u sred posla. Posle 15 minuta job se sam otključava i drugi radnik ga preuzima.- Idempotentnost:
saveDraftmora da bude bezbedan za ponovljeni poziv. Ako je isti draft već upisan, ne pravimo duplikat, samo update. Ovo me je spasilo bezbroj puta kad Lambda time-out-uje pošto je već završila posao.
Rezultat: mogu da restartujem ceo sistem u sred noći, i on nastavi tačno tamo gde je stao. Ništa se ne izgubi, ništa se ne duplira.
Self-healing: retry, backoff, dead-letter
LLM API-ji padaju. Rate limiti se pojave. WordPress REST API bude sporo 12 sekundi umesto normalnih 800ms. Sve je ovo normalno. Sistem koji spava ne sme da traži tvoju pažnju za ove stvari.
Moj sloj za retry ima tri nivoa:
- Transient retry unutar samog HTTP klijenta: 3 pokušaja sa exponential backoff (1s, 4s, 12s) za 429, 500, 502, 503, 504, i mrežne greške. Ovo pokrije ~85% svih problema.
- Job-level retry iz baze: ako sam job (Draft za članak X) pukne,
retry_count++, i vraća se u red sanext_retry_at = NOW() + interval '30 minutes'. Do 3 pokušaja. - Dead-letter red: posle 3 neuspešna pokušaja, job ide u
dead_lettertabelu sa punim kontekstom (input, greška, stack). Ujutru dobijem jedan email: "3 job-a u DLQ, evo linkova".
Ono što neću da radim: da retry-jem beskrajno. Video sam sisteme koji su potrošili 400 dolara na OpenAI kredite jer je jedan članak imao malformed prompt i sistem je iterirao 800 puta u 6 sati. Hard cap na retry i hard cap na trošak po job-u (max tokens, max cena u USD) su neispregovorbe.
Observability: šta gledam kad ustanem
Sistem koji radi dok spavam mora da mi kaže jednim pogledom da li je noć bila dobra. Ne 400 log linija. Jedan dashboard.
Ono što stvarno pratim:
- Job throughput: koliko je članaka prošlo svaku fazu za poslednjih 24h. Ako je Research uradio 12 briefova, a Publish samo 4, znam gde je usko grlo.
- P95 latency po fazi: ako Draft normalno traje 3 min, a odjednom je P95 na 9 min, nešto sa Claude/OpenAI API-jem se menja.
- Failure rate po fazi i po tipu greške: 5xx sa CMS-a, JSON parse greške iz LLM outputa, rate limit hitovi.
- DLQ dubina: koliko job-ova čeka moju pažnju.
- Trošak po članku (USD): ako mi ovo skoči sa $0.40 na $1.20 preko noći, znam da neki prompt curi tokene.
Za male sisteme, ovo je jedan Postgres SELECT preko materializovanog view-a, prikazan na Next.js dashboardu. Ne moraš Datadog na dan jedan. Ali moraš imati sve pet metrika, jer bez njih letiš na slepo.
Guardraili: sistem ne sme da uradi glupost sam
Autonomija bez guardraila je tempirana bomba. Ono što sam nametnuo:
- Content gate pre publikacije: automatski provera da li članak ima minimum reči, obavezne H2, primary keyword u prvih 100 reči, nema neuklonjenih placeholder-a tipa
[TODO]iliKao AI model.... Ako pukne, ide uneeds_review, ne u dead-letter, jer je popravljivo. - Budget cap per day: hard limit na $X potrošnje na LLM API po danu. Kad se približi 80%, sistem prelazi na jeftiniji model (Haiku umesto Sonnet za Draft), ili pauzira niže-prioritetne teme.
- Rate limit awareness: klijent za LLM prati sopstveni token budget u sliding window-u i pauzira sam sebe pre nego što udari u 429. Ovo je jeftinije nego reagovati na 429 posle.
- Publish confirmation: posle POST-a na CMS, sistem uradi GET na URL i proveri da članak stvarno postoji i vraća 200. Nije objavljeno dok nije verifikovano.
Bez ovoga, sistem koji "radi dok spavaš" postaje sistem koji objavi 40 članaka sa placeholder tekstom na tvom sajtu dok spavaš. Video sam da se desi.
Šta bih ja uradio da krećeš iz nule
Ako sada praviš prvi autonoman AI sistem, evo redosleda kojim bih išao. Ne preskači korake, čak i kad se čine dosadni.
- Napravi jedan pipeline koji radi sinhrono, do kraja, na jednom ulazu. Bez retry-ja, bez radnika, samo
run(input) -> output. Ovo ti daje istinu o tome šta faze rade i koliko traju. - Prebaci ga na bazu. Umesto da faze prosleđuju objekte, upisuj u tabele sa
statuskolonom. Sad možeš da restartuješ na sredini. - Dodaj jednog radnika po fazi. Cron ili EventBridge, svaki 5-10 min.
FOR UPDATE SKIP LOCKEDje tvoj najbolji prijatelj. - Ubaci retry i DLQ tek sad. Ne ranije. Ako ubaciš retry pre nego što razumeš gde faze pucaju, maskiraš prave bagove.
- Napravi dashboard sa 5 metrika. Throughput, latency, failure rate, DLQ, cost. Bez ovoga, ne znaš da li sistem radi ili ne.
- Postavi budget cap i content gate. Ovo je poslednja stvar pre nego što pustiš sistem da radi preko noći.
- Pusti ga na 48h nadgledanog rada. Gledaj dashboard 3-4 puta dnevno. Popravi šta puca. Onda 72h. Onda nedelju.
Nemoj da praviš "agenta koji sve radi". Napravi 5 dosadnih radnika koji rade po jednu stvar dobro.
Jedna stvar koju ljudi potcene: verzionisanje promptova. Kad sistem radi dok spavaš, i prompt se menja, moraš da znaš koji je prompt napravio koji članak. Ja čuvam prompt_version u svakom draft redu. Ako sledeće nedelje kvalitet padne, znam tačno šta se promenilo.
Šta ovo košta i koliko donosi
Realno, autonoman ContentStudio-tip sistem ima infrastrukturne troškove reda 20-60 USD mesečno (Supabase/RDS, Vercel/Lambda, sve serverless), plus varijabilni LLM trošak koji zavisi od volumena. U mojim projektima, on je pao ispod 0.50 USD po članku otkad sam prešao na hibrid Sonnet za draft, Haiku za optimize.
Poređenja radi, ekosistem od 4 automatizacije koji sam napravio štedi 73+ sati mesečno operativnog rada, sa 192% ROI u prvoj godini. To nije zato što je AI magičan. To je zato što sistem radi dok spavam, i ne traži me za sitnice.
Ako gradiš nešto slično i zapneš na koraku 3 ili 4 (radnici koji se blokiraju, retry koji ne konvergira, ili sistem koji ćuti a ne radi), tu obično mogu da pomognem najbrže. Slobodno se javi preko lazar-milicevic.com/#contact. Interesuje me šta pravite, čak i ako trenutno ne tražite pomoć.
Često postavljana pitanja
Kako da napravim AI sistem koji radi autonomno 72 sata bez ljudske intervencije?
Autonoman AI sistem ne znači sistem bez grešaka, već sistem koji greške tretira kao normalno stanje. Moj kriterijum je da radi minimum 72 sata bez ljudskog dodira, uz dokazivo isporučen rezultat i jasno stanje u svakom trenutku. Tri stvari to omogućavaju: multi-agent pipeline sa razdvojenim odgovornostima, raspoređeni radnici koji rade u malim idempotentnim koracima, i self-healing kroz retry sa backoff-om, checkpoint stanje u bazi i dead-letter red. Ako bilo koja od te tri komponente fali, sistem će te probuditi posle noć ili dve.
Zašto je loše praviti jednog velikog AI agenta sa mnogo tool-ova?
Najveća greška je napraviti jednog agenta sa 40 tool-ova i nadati se da će LLM izabrati pravi redosled. To funkcioniše na demou, ali u produkciji taj agent posle 200 poziva počne da halucinira redosled ili zaglavi u petlji tipa 'istražujem pa razmišljam pa istražujem'. Bolje rešenje je razdvojiti pipeline u jasne faze (Research, Outline, Draft, Optimize, Publish), gde svaka faza ima svoj prompt, svoju output šemu (Zod ili Pydantic) i svoj ulaz iz baze. Faze treba da komuniciraju preko baze, ne preko memorije, što čini sistem otpornim na otkaze.
Kako da omogućim paralelno izvršavanje worker-a bez konflikata u PostgreSQL-u?
Ključ je korišćenje SQL konstrukcije `FOR UPDATE SKIP LOCKED` koja omogućava da dva ili više radnika mogu paralelno da rade bez konflikta jer im Postgres automatski dodeljuje različite redove. Uz to, koristim polje `locked_until` kao zaštitu ako radnik pukne u sred posla, posle 15 minuta job se sam otključava i drugi radnik ga preuzima. Sve operacije upisivanja moraju biti idempotentne, tako da ponovljeni poziv ne pravi duplikat već radi update. Ova kombinacija dozvoljava restart celog sistema u sred noći bez gubitka ili dupliranja podataka.
Kako da sprečim da AI sistem potroši previše novca na retry pokušaje?
Video sam sisteme koji potroše 400 dolara na OpenAI kredite jer je jedan članak imao malformed prompt i sistem je iterirao 800 puta u 6 sati. Zato koristim tri nivoa retry logike: transient retry unutar HTTP klijenta (3 pokušaja sa exponential backoff 1s, 4s, 12s), job-level retry iz baze (do 3 pokušaja sa razmakom od 30 minuta), i dead-letter red za sve što ne uspe posle toga. Hard cap na broj retry-ja i hard cap na trošak po job-u (max tokens, max cena u USD) su neispregovorljivi. Ujutru dobijem jedan email sa linkovima ka job-ovima u DLQ, umesto 400 log linija.
Koje metrike treba pratiti za AI sistem koji radi tokom noći?
Sistem mora da mi jednim pogledom kaže da li je noć bila dobra, ne 400 log linija, nego jedan dashboard. Pratim tri ključne metrike: job throughput po fazi (koliko je zadataka prošlo kroz Research, Draft, Publish za poslednjih 24 sata, što otkriva usko grlo), P95 latency po fazi (ako Draft normalno traje 3 minuta a odjednom P95 skoči na 9, nešto se menja sa LLM API-jem), i failure rate po fazi i tipu greške (5xx sa CMS-a, rate limit, timeout). Ove tri metrike su dovoljne da za 30 sekundi znaš da li sistem radi zdravo ili treba intervencija.
Gradiš nešto teško sa AI-jem ili automatizacijom? Otvoren sam za razgovor.
Javi se