Learning
Všechny články
AI12. října 2026 4 min

Tichý den a rozbitý zdroj vypadají pro agenta stejně

Plánovaný agent selhává potichu, pokud prázdný výstup nerozliší od chyby

Prázdný výstup agenta nic neznamená, dokud nevíš, proč je prázdný

Agent, který každé ráno projde Slack a GitHub a pošle krátký přehled, vypadá jako prompt na cronu. Ve skutečnosti je to malý distribuovaný systém. Má vstupy, které můžou vypadnout, výstup, který může a nemusí dorazit, a stav mezi běhy. A protože u něj nikdo nesedí, každá chyba se projeví stejně: přehled je kratší, než by měl být, a nikdo si toho nevšimne.


Záložka místo časového okna

Nejpřirozenější zadání zní „přečti posledních 24 hodin". Jenže cron neběží přesně. Když se běh o hodinu zpozdí, hodina zpráv propadne mezi dvě okna. Když proběhne dřív, část zpráv dostaneš dvakrát.

Řešení je stejné jako u každého konzumenta fronty: agent si pro každý zdroj ukládá záložku, tedy časovou značku nejnovější položky, kterou opravdu přečetl. Další běh začíná přesně tam. Okno se pak samo přizpůsobí tomu, kdy běh skutečně proběhl, ne kdy proběhnout měl.

Záložka má i druhý efekt. Když MCP server spadne nebo vyprší token, agent prostě nevidí žádné nástroje a poctivě nahlásí „nic nového". Z jeho pohledu je to pravda. S oknem by ta zpráva byla navždy ztracená. Se záložkou platí jednoduché pravidlo: neúspěšné čtení není klidný den. Záložka daného zdroje se neposune, přehled se napíše z ostatních zdrojů a výslovně v něm stojí, co přečíst nešlo.


Odesláno je až to, co cíl potvrdil

Na výstupní straně hrozí dvě opačné chyby. Agent zapíše, že přehled odeslal, i když nedorazil. Záložky se posunou a položky z toho přehledu už nikdy nikdo neuvidí. Nebo si agent odesláním není jistý, pošle ho znovu a čtenáři dostanou duplikát.

Proti oběma pomáhá pevné pořadí kroků. Před odesláním zkontrolovat, jestli dnešní vydání v kanálu už není. Za odeslané považovat jen odpověď s "ok": true a časovou značkou zprávy. Teprve potom posunout záložky a zapsat položky do ledgeru. A když výsledek není jasný, zapsat běh jako „možná odesláno" a nic dalšího neměnit.

Je to stejná disciplína jako u transakce: stav se mění až po potvrzeném vedlejším efektu, nikdy před ním. Totéž platí pro obsah. Mezi čtením a odesláním se svět posune, takže agent těsně před odesláním znovu ověří stav každé položky. Co se vyřešilo, vypadne. Co se nedá potvrdit, taky vypadne. Formulace typu „asi pořád čeká" se nepoužívá: stav se buď tvrdí, nebo se položka vynechá.


Kdo co vlastní, rozhoduje o tom, co přežije další běh

Každý běh startuje bez paměti, takže zpětná vazba musí žít v úložišti. Článek ho dělí na dvě části s různým vlastníkem. Preference (kanály, repozitáře, výjimky, délka) patří čtenáři a agent je smí jen číst. Načítá je při každém běhu. Když je načíst nejde, má skončit, ne jet podle výchozích hodnot. Stav (záložky, ledger s ID a posledním známým stavem položek, záznam o běhu) patří agentovi a smí ho přepisovat.

To rozdělení není jen pořádek. Agent čte cizí zprávy a issue, a ty můžou obsahovat instrukce. Pokud by preference směl přepsat, jediná podvržená zpráva mu může trvale změnit zadání. Proto read-only token pro GitHub, allowlist sítě a bot pozvaný jen tam, kam má psát.

Poslední past je limit útraty. Běh, který na něj narazí, se zastaví, a když je limit nastavený moc nízko, výsledek vypadá přesně jako přehled z klidného dne. Doporučení je začít na trojnásobku až pětinásobku běžného běhu a utahovat podle reálných čísel.

Co si z toho odnést

U plánovaného agenta nehledej chyby v promptu, ale v místech, kde se ticho dá zaměnit za úspěch: výpadek zdroje, nejisté odeslání, vyčerpaný rozpočet. Každé z nich potřebuje vlastní explicitní stav, jinak se schová do „dnes nic nového". Záložka místo okna a zápis až po potvrzení jsou staré vzory z front a transakcí. U agentů platí stejně, jen je bez nich nikdo nevynutí.

Zdroje

Poslech místo čtení — 2 zdroje k načtení.