TL;DR
За 8 дней частичной занятости я собрал RAG-систему на NestJS + PostgreSQL (pgvector), которая обрабатывает ~11 000 чанков документов.
Первая версия отвечала около 4 минут, после оптимизации — 40–60 секунд.
Главный вывод: RAG — это не «векторный поиск + LLM», а в первую очередь подготовка данных, фильтрация контекста и аккуратная работа с промптами.
С чего всё началось
Идея проекта возникла довольно прозаично. Я давно хотел сделать себе простой сайт-визитку, но всё время откладывал. В какой-то момент понял, что в эпоху нейросетей это уже не большая проблема — и за вечер собрал site15.ru.
Дальше возник логичный вопрос: почему бы не добавить на сайт чат, который мог бы отвечать на вопросы на основе моих знаний, опыта и проектов?
Так я и начал разбираться, как вообще делаются RAG-системы.
Проект изначально был для личного использования — без бизнес-целей и «стартап-мышления». Мне хотелось руками пройти путь от «ничего не знаю про RAG» до рабочей системы.
Зачем вообще RAG
Основная задача была учебная: научиться работать с RAG-системами, потому что сейчас это одна из самых востребованных тем — корпоративные базы знаний, ответы в стиле компании, поиск по внутренней документации.
По ходу стало понятно, что RAG — это не какая-то магия, а довольно жёсткий инженерный процесс, где ошибки в данных или промптах мгновенно вылезают наружу.
Как это встроено в site15.ru
RAG-система интегрирована с моим сайтом-визиткой. Site15.ru выступает как демо и интерфейс:
frontend site15.ru → backend site15.ru → отдельный сервер rag-system
Backend передаёт специальный API-ключ, что хотя бы минимально защищает систему от лишних запросов. Это не про серьёзную безопасность — просто базовая гигиена.
Таким образом сайт стал не просто визиткой, а живым примером работы RAG.
Почему стек именно такой
Backend — NestJS
Я постоянно пишу бэкенды на NestJS, поэтому тут даже не было выбора.
Frontend — React Admin
Вообще я работаю с Angular, но полноценного фронтенда тут не было нужно — требовалась только админка для управления документами, эмбеддингами и промптами.
В Angular-экосистеме готового аналога react-admin нет, поэтому решил взять его и заодно получить практический опыт.
PostgreSQL + pgvector
Очень удобно, когда не нужно поднимать отдельное векторное хранилище. Обычные данные и векторы живут в одной базе — меньше инфраструктуры, меньше точек отказа.
Несколько LLM-провайдеров
Изначально заложил поддержку разных провайдеров (OpenAI, Groq, Ollama и т.д.), чтобы можно было переключаться между ними и использовать бесплатные лимиты. Когда лимит одного заканчивается — активным становится следующий.
Архитектура и ключевая идея
В какой-то момент стало очевидно, что главная проблема — не LLM, а объём данных, который ты в неё пихаешь.
Я реализовал иерархическую фильтрацию:
Запрос пользователя
→ нормализация вопроса
→ фильтрация по метаданным (11000 → ~500)
→ фильтрация по секциям (500 → ~200)
→ векторный поиск (200 → 5–10)
→ один оптимизированный запрос в LLM
Идея простая: не отправлять в LLM всё подряд.
Почему RAG оказался сложнее, чем казалось
На старте всё выглядело очень просто:
RAG = векторный поиск + LLM
На практике оказалось, что большая часть времени уходит на:
- сегментацию документов,
- генерацию метаданных,
- согласование промптов между собой.
Первая версия системы делала всё последовательно и отвечала около 4 минут даже на простой вопрос.
Самая большая техническая боль
Самым тяжёлым этапом стало создание метаданных для 11 005 чанков документов.
В облаке это просто не взлетало — слишком долго и дорого. В итоге я запустил всё локально через LM Studio с моделью qwen2.5-7b-instruct и два дня гонял чанки на своей RTX 2060 SUPER.
Это был момент, когда стало особенно понятно, что RAG — это не игрушка.
Оптимизация и ускорение
После того как всё заработало, выяснилось, что система тормозит не из-за LLM, а из-за:
- лишних промежуточных промптов,
- последовательных вызовов, которые можно было запускать параллельно.
В первой версии было 8 промежуточных промптов, сейчас — 4. Часть этапов стала параллельной, появилась асинхронная очередь на RxJS.
Результат: 40–60 секунд вместо 4 минут.
Промпты — это ад
Самое долгое и сложное — формирование промптов. Они легко конфликтуют друг с другом или начинают «утекать»:
Промпт: отвечай только по контексту
LLM: ...и ещё немного от себя
Главный вывод: меньше промптов, но они должны быть согласованы.
Использование ИИ при разработке
Примерно 70% кода писалось с помощью ИИ-ассистентов, но без моей архитектурной логики, правок и отладки этот код просто не работал бы.
Ассистент — это инструмент, а не замена инженера.
Безопасность и деплой
Проект не production-ready, но я добавил:
- проверку разрешённого IP,
- проверку API-ключа.
Развёртывание максимально простое:
- отдельный VPS,
docker-compose для PostgreSQL и Ollama,
- backend через
pm2.
CI/CD пока нет — в планах Docker + Kubernetes.
Текущий статус и планы
Сейчас это экспериментальный проект, не MVP и не продакшен. Скорее заготовка и рабочий пример того, как можно собирать RAG-системы руками.
В планах:
- написать тесты пользовательских сценариев,
- отрефакторить LLM-модуль в стиле NestJS,
- добавить аналитику и статистику,
- автоматизировать деплой,
- возможно сделать публичную SaaS-версию.
Ссылки
Итог
RAG — это не «подключил LLM и поехали». Это про данные, фильтрацию и дисциплину в промптах.
За 8 дней частичной занятости мне удалось собрать рабочую систему, интегрировать её с site15.ru и получить реальное понимание того, как RAG работает на практике.