Перейти к содержимому

Устаревший индекс знаний

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)

Два сигнала ловят разные поломки: первый — «джоба не запускается», второй — «джоба запускается, но данные не приходят».

Если не хочется отдельной cloud-функции — хватит heartbeat с intervalSec чуть больше периода вашего cron. Пингуйте его в конце успешной переиндексации; пропуск сам породит push «индекс не обновился»:

Окно терминала
python -m rag.reindex && curl -fsS "$REINDEX_PING_URL" -o /dev/null

Heartbeat закрывает сигнал №1 бесплатно; сигнал №2 всё же требует своей проверки метаданных.

  • возраст последней переиндексации и SLA;
  • возраст самого свежего документа;
  • имя коллекции;
  • ожидаемый период cron — чтобы сразу понять, «пропущен один прогон» или «встало совсем».