Узнайте, как исправить семантический кэш, гибридный поиск и защиту PII в RAG-системах. Практические советы и код на Python.
Большинство RAG-демо на GitHub делают одно и то же: эмбедят чанки, ищут по косинусной близости, подставляют top-k в промпт — и готово. Я тоже сначала собрал такой. Но когда я попробовал использовать его на реальных неструктурированных документах, всё развалилось в трёх конкретных местах. Поэтому я переделал его в событийно-ориентированный конвейер вместо линейного скрипта — так появился Project Aether.
Кэширование ответов LLM по точной строке запроса бесполезно: никто не задаёт один и тот же вопрос дважды. Нужен кэш на основе сходства (достаточно ли новый запрос «близок» к кэшированному?), но это открывает более сложную проблему: какой порог считать «достаточно близким», чтобы не возвращать неправильный, но правдоподобный ответ из кэша на немного другой вопрос? В итоге я настраивал порог на небольшом оценочном наборе, а не угадывал порог косинусной близости наугад.
Чистые плотные эмбеддинги плохо работают с точными ключевыми словами, номерами деталей, кодами ошибок. Если кто-то ищет конкретный SKU, поиск только по плотным эмбеддингам возвращает пять семантически похожих, но неправильных товаров. Я исправил это, перейдя на гибридный поиск (плотный + разреженный) вместо только плотного.
Это та проблема, о которой не говорят в туториалах по RAG. Если вы нарезаете и эмбедите реальные тикеты поддержки или контракты, вы навсегда эмбедите и PII, которая в них есть, в векторное хранилище, к которому у вас может не быть полного контроля доступа. Поэтому перед нарезкой на чанки нужен этап маскирования PII, а не после.
Project Aether — это событийно-ориентированный поисковый движок для RAG:
Конвейер загрузки маскирует PII перед нарезкой, обогащает чанки метаданными от LLM, а на стороне запроса выполняет трансформацию запроса и цикл уточнения с оценкой релевантности перед генерацией. Опционально есть этап переранжирования с cross-encoder (BAAI/bge-reranker-v2-m3), который я отключаю по умолчанию из-за требований к памяти.
Живое демо работает на бесплатном тарифе Render, поэтому оно только для запросов (загрузка выполняется как локальная задача и не доступна извне), и первый запрос может быть медленным из-за холодного старта. Не буду притворяться, что это не так — такова цена бесплатного хостинга. Если вы зайдёте и первый ответ займёт время, это контейнер просыпается, а не RAG-конвейер тормозит.
Это сольный проект, без команды, поэтому если что-то выглядит недоработанным, это потому, что я строил его под свои временные рамки, а не из-за нехватки идей.
Репозиторий: https://github.com/gabaoun/Project-Aether
Я лучше получу комментарий вроде «этот подход к поиску неправильный, потому что X», чем звезду без обратной связи, но если вам полезно — звезда поможет другим найти проект. Интересно, кто-нибудь ещё боролся с настройкой порога семантического кэша? Похоже, это самая недооценённая сложная проблема в RAG сейчас.
Начните с малого: выберите одну проблему, исправьте её на своих данных и проверьте, улучшилось ли качество. Не пытайтесь переписать всё сразу.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →