Устаревший индекс знаний
RAG деградирует не с грохотом, а тишиной: переиндексация встала неделю назад, а система исправно отвечает — только по устаревшим данным. Ни ошибок, ни пятисоток. Ловим два независимых сигнала свежести: когда в последний раз собирали индекс и насколько стар самый новый документ в нём.
1. Свежесть по времени последней переиндексации
Заголовок раздела «1. Свежесть по времени последней переиндексации»Каждый успешный прогон переиндексации пишет timestamp. Раз в час cloud-функция сверяет его с SLA:
import os, time, requests
STAMP = "/var/lib/rag/last-reindex.ts"SLA_HOURS = 24 # переиндексация должна проходить раз в сутки
def handler(event, context): if not os.path.exists(STAMP): notify("🕰️ Индекс не собирался", "Нет отметки о переиндексации.", 8) return {"statusCode": 200}
age_h = (time.time() - float(open(STAMP).read())) / 3600 if age_h > SLA_HOURS: notify("🕰️ Индекс устарел", f"Последняя переиндексация: {age_h:.1f} ч назад " f"(SLA {SLA_HOURS} ч).\n" "RAG отвечает по старым данным — проверьте cron/джобу.", priority=8) return {"statusCode": 200}
def notify(title, message, priority): requests.post(f"{os.environ['NOTIFLY_URL']}/message", params={"token": os.environ["NOTIFLY_TOKEN"]}, json={"title": title, "message": message, "priority": priority}, timeout=5)А джоба переиндексации в конце успешного прогона просто делает:
open("/var/lib/rag/last-reindex.ts", "w").write(str(time.time()))2. Свежесть по самому новому документу в индексе
Заголовок раздела «2. Свежесть по самому новому документу в индексе»Индекс мог собираться исправно — но из мёртвого источника (краулер сломался, папка не наполняется). Смотрим на самый свежий документ в коллекции:
FRESHNESS_HOURS = 48 # свежайший документ не должен быть старше 2 суток
def check_newest_doc(): # берём максимальный updated_at из метаданных чанков newest = vector_db_max_metadata("updated_at") # ваш клиент → epoch seconds if newest is None: notify("🕰️ В индексе нет документов", "Коллекция пуста.", 9) return age_h = (time.time() - newest) / 3600 if age_h > FRESHNESS_HOURS: notify("🕰️ Источники устарели", f"Свежайший документ в индексе: {age_h:.1f} ч назад " f"(SLA {FRESHNESS_HOURS} ч).\n" "Индекс собирается, но источник перестал обновляться.", priority=7)Два сигнала ловят разные поломки: первый — «джоба не запускается», второй — «джоба запускается, но данные не приходят».
3. Heartbeat как самый дешёвый вариант
Заголовок раздела «3. Heartbeat как самый дешёвый вариант»Если не хочется отдельной cloud-функции — хватит heartbeat
с intervalSec чуть больше периода вашего cron. Пингуйте его в конце
успешной переиндексации; пропуск сам породит push «индекс не обновился»:
python -m rag.reindex && curl -fsS "$REINDEX_PING_URL" -o /dev/nullHeartbeat закрывает сигнал №1 бесплатно; сигнал №2 всё же требует своей проверки метаданных.
Что положить в текст алёрта
Заголовок раздела «Что положить в текст алёрта»- возраст последней переиндексации и SLA;
- возраст самого свежего документа;
- имя коллекции;
- ожидаемый период cron — чтобы сразу понять, «пропущен один прогон» или «встало совсем».
Связанные рецепты
Заголовок раздела «Связанные рецепты»- Перестройка индекса завершена — успешный прогон, который пишет отметку.
- Vector DB / RAG-инфраструктура — heartbeat от пайплайна индексации.
- Сбои ингеста документов — почему свежие документы не доезжают.