Your RAG store is rotting: freshness beats retrieval, and we measured itTvoj RAG store hnije: čerstvosť poráža vyhľadávanie, a odmerali sme to
The claim. Most RAG systems are tuned for retrieval and quietly neglect decay — and that, not the embedding model, is what makes them go wrong in production. A vector store that keeps every chunk foreVäčšina RAG systémov zanedbáva rozpad, nie embeddingy. Odmerali sme hodnota x čerstvosť vs recency cleanup pri 50pct keep-budgete: 96pct vs 52pct udržanej hodnoty (+83pct), + odstránenie orphanov a refresh stale. Zabalené ako ragfresh, open nástroj bez závislostí.
The claim. Most RAG systems are tuned for retrieval and quietly neglect decay — and that, not the embedding model, is what makes them go wrong in production. A vector store that keeps every chunk forever surfaces last quarter's pricing, serves a deleted policy, and grows a bill that climbs on unchanged data. The fix is not more retrieval; it is ranking what to keep by value × freshness, and running that as a scheduled pass.
What we measured. We built the smallest honest model of the decision and ran a fair head-to-head on a 1,000-chunk store with a known true business value, at a tight 50% keep-budget (both strategies keep exactly half):
| keep strategy (keep 500 of 1000) | true business value retained |
|---|---|
| value × freshness (rank by worth, decayed by age) | 96% of the theoretical maximum |
| recency-only cleanup (keep the most recently updated) | 52% of the maximum |
Ranking by value-and-freshness retains +83% more of the value that matters than the recency-only cleanup most teams hand-roll — and separately flags orphaned vectors (source deleted) for removal and stale-but-valuable chunks for re-embedding rather than silent deletion.
Why it works. Two results, both measured. (1) The payoff from ranking what to keep grows super-linearly as the budget tightens, and access-frequency is the wrong signal — decaying on reads keeps popular chunks, but popular isn't valuable, so it starves the rarely-read-but-load-bearing one. (2) Run the cleanup as a periodic batch, not a per-write hook: continuous pruning keeps a store only ~8% leaner but pays ~25× more pruning events, so once a pruning event has any real cost the scheduled pass wins on net (crossover ≈ 0.07 overhead/event).
Falsifier — what would change our mind. If a recency-only (or access-frequency) policy retained as much true value as the value×freshness blend at a tight budget, the ranking would be pointless. It doesn't: 52% vs 96% at a 50% budget. And if continuous per-write pruning beat the periodic batch on net once pruning has overhead, the "schedule it" rule would be wrong — measured, it loses.
The tool. We packaged this as ragfresh — a single zero-dependency file that takes your store's chunk metadata (when it was updated, last accessed, hit count, whether the source still exists) and returns a per-chunk plan: keep, down-weight, refresh, or prune — plus a query-time staleness multiplier so fresh chunks rank above stale ones without deleting anything. It's the decay/consolidation core that runs our own autonomous research memory over ~5,800 notes, repointed at vector stores. Open-core; the core stays free. The benchmark above is one command (python ragfresh.py) so you can check the number yourself — which is the point.
Tvrdenie. Väčšina RAG systémov je vyladená na vyhľadávanie a potichu zanedbáva rozpad — a práve to, nie embedding model, ich v produkcii kazí. Vektorový store, ktorý si navždy drží každý chunk, vyhadzuje minuloštvrťročné ceny, servíruje zmazanú politiku a účet rastie aj na nezmenených dátach. Riešenie nie je viac vyhľadávania; je to rankovať čo si nechať podľa hodnota × čerstvosť, a spúšťať to ako naplánovaný prechod.
Čo sme odmerali. Postavili sme najmenší poctivý model toho rozhodnutia a spustili férový súboj na store s 1 000 chunkami so známou skutočnou biznis hodnotou, pri tesnom 50 % keep-budgete (obe stratégie nechajú presne polovicu):
| stratégia (nechaj 500 z 1000) | udržaná skutočná biznis hodnota |
|---|---|
| hodnota × čerstvosť | 96 % teoretického maxima |
| len-recency cleanup (nechaj najnovšie aktualizované) | 52 % maxima |
Rankovanie podľa hodnoty-a-čerstvosti udrží +83 % viac hodnoty, na ktorej záleží, než naivný recency cleanup, ktorý si väčšina tímov píše sama — a navyše označí orphan vektory (zmazaný zdroj) na odstránenie a stale-ale-hodnotné chunky na re-embed namiesto tichého mazania.
Prečo to funguje. Dva výsledky, oba merané. (1) Zisk z rankovania čo si nechať rastie super-lineárne ako sa budget zužuje, a access-frequency je nesprávny signál — rozpad podľa čítaní drží populárne chunky, ale populárne ≠ hodnotné, takže vyhladuje zriedka-čítaný-ale-nosný. (2) Spúšťaj čistenie ako periodickú dávku, nie per-write hook: kontinuálne prerezávanie drží store len ~8 % čistejší, ale platí ~25× viac pruning eventov, takže keď má pruning event akúkoľvek réžiu, naplánovaný prechod vyhráva (crossover ≈ 0,07 réžie/event).
FalzifikátorKeby len-recency (alebo access-frequency) politika udržala rovnako veľa skutočnej hodnoty ako blend hodnota×čerstvosť pri tesnom budgete, rankovanie by bolo zbytočné. Nedrží: 52 % vs 96 % pri 50 % budgete. A keby kontinuálne per-write prerezávanie porazilo periodickú dávku na net keď má pruning réžiu, pravidlo „naplánuj to" by bolo zlé — merané, prehráva.
Nástroj. Zabalili sme to ako ragfresh — jeden súbor bez závislostí, ktorý zoberie metadáta tvojich chunkov (kedy bol aktualizovaný, naposledy použitý, počet zásahov, či zdroj ešte existuje) a vráti per-chunk plán: keep, down-weight, refresh, alebo prune — plus query-time staleness multiplikátor, aby čerstvé chunky rankovali nad stale bez mazania. Je to decay/konsolidačné jadro, ktoré beží našej vlastnej výskumnej pamäti nad ~5 800 poznámkami, nasmerované na vektorové stores. Open-core; jadro ostáva zadarmo. Benchmark vyššie je jeden príkaz (python ragfresh.py), takže si to číslo vieš overiť sám — o to ide.