Продолжая использовать этот сайт, вы соглашаетесь на использование файлов cookie 🍪
Ок
Блог CosySoft

RAG в продакшене: как дать LLM свежие данные без сложного дообучения

Наш хэд бэкэнд-разработки Женя — тот девелопер, который не просто играет с ИИ, а проверяет их на прочность и думает будет ли от них польза в реальных рабочих процессах. Используя LLM, он давно заметил очевидное: память модели заканчивается датой последнего обучения, а все новое остается за кадром. Retrieval Augmented Generation (RAG) решает эту проблему: вытаскивает свежие документы из баз или интернета, подмешивает их прямо в промпт и избавляет от затратного fine‑tuning модели. В статье Женя делится своими находками — как настроить RAG, ускорить ответы и сэкономить бюджет.
Все примеры кода и базовая схема реализации взяты с Baeldung

Что такое Retrieval Augmented Generation

Retrieval Augmented Generation — это архитектурный прием, который «пришивает» к языковой модели слой поиска и превращает ее ответы в динамический процесс.
Как работает цепочка?
  1. Извлечение. По запросу система ищет релевантные фрагменты в базах, корпоративных хранилищах или в сети.
  2. Обогащение промпта. Найденные куски текста вставляются в одно сообщение с вопросом.
  3. Генерация. LLM формулирует ответ, опираясь на свежий контекст, а не только на свои встроенные представления.
Таким образом, RAG не заменяет модель и не требует переобучения. Он просто соединяет поисковый механизм с генерацией так, чтобы каждый ответ строился на актуальных, проверенных данных.

Преимущества RAG-подхода

  1. Актуальность данных. Модель видит свежие документы сразу после их загрузки. Переобучать LLM не нужно.
  2. Фокус на сути. Документы режем на чанки. В prompt попадают только релевантные куски. Меньше шума — выше точность ответа.
  3. Экономия токенов и бюджета. Чанки короче исходных файлов, значит запрос дешевле. Плюс мы избегаем дорогого дообучения модели.

Где можно применить RAG

Чат‑боты и ассистенты поддержки
Извлекает нужные абзацы из базы знаний и подает их модели. Клиент получает точный ответ без ожидания, оператор — меньше рутины.
Анализ «толстых» документов
Делит файл на чанки, находит релевантные куски, подсовывает только их. Модель не тонет в лишнем контексте и отвечает быстрее.
Поисковые движки с генерацией ответа
Вместо десятка ссылок пользователь сразу видит сжатый ответ, собранный из лучших фрагментов сети.

Начинаем работу: как устроен RAG‑конвейер

Это пример классической реализации пайплайна на базе RAG.

1. Индексация знаний

  1. Собираем источники: документы, PDF, базы.
  2. Режем на чанки — удобные по размеру куски текста.
  3. Строим эмбеддинги: прогоняем каждый чанк через модель embedding → получаем N‑мерный вектор (512, 1024 — зависит от модели).
  4. Сохраняем: кладем вектор и исходный текст в vector store.

2. Обслуживание запроса

  1. Пользователь задает вопрос.
  2. Генерируем эмбеддинг запроса той же моделью.
  3. Ищем ближайшие векторы в vector store → получаем релевантные чанки.
  4. Склеиваем prompt: вопрос + найденный контекст.
  5. LLM формирует ответ и отдает его пользователю.
Такой двухшаговый поток разделяет задачи. Индексация выполняется офлайн, сколько угодно долго. Retrieval и генерация работают онлайн за миллисекунды.
Этот паттерн остается одинаковым, даже если меняется способ поиска (векторный, keyword + вектор) или хранилище (Milvus, pgvector, Elastic).

Качественный retrieval всему голова

Ключевой компонент в RAG — поиск релевантных фрагментов. Без хорошего retrieval генерации просто будет не на что опираться.
Подход
Когда применяем
Как работает
Семантический (векторный)
Когда важен смысл, а формулировки различаются
Документам назначаем векторы‑эмбеддинги. Извлекаем тексты, где идея совпадает, даже если слова другие.
Точный (keyword)
Когда нужны точные совпадения, например, артикул, имя функции, номер договора
Индексируем ключевые слова, получаем минимальный шум и стопроцентное совпадение по форме.
Оба метода можно смешивать: сначала точный фильтр — отсекаем очевидный мусор, потом семантика — добавляем близкие по смыслу документы. Главное передать модели короткий, чистый контекст, пригодный для ответа.

Разметка текста — как нарезать чанки

Качественный retrieval начинается с правильного деления исходного материала. Вот какие способы существуют.
Метод
Преимущества
Минусы
Когда брать
Семантическая ручная — делим по смысловым блокам (разделы, абзацы)
Высокая точность, чистый контекст
Дорого, медленно, подходит только для статичного контента
Узкие базы знаний, редко меняющиеся документы
По токенам / символам
Легко автоматизировать
Разрывает смысл, повышает шум
Быстрая индексация больших потоков данных
С наложением (overlap)
Сохраняет часть контекста между чанками
Чуть дороже по токенам, контекст все‑таки рвется
Улучшение токенной схемы без сложных моделей
Автоматическая семантика — специализированные модели сегментации
Баланс скорости и качества, работает в онлайне
Требует обученной модели, результат сильно зависит от домена
Динамические системы с пользовательскими загрузками
Коротко
  • Для статичных, важных документов лучше ручная семантика.
  • Для потоковых загрузок — автоматическая разметка: сначала грубый срез по токенам + overlap, со временем добавляем ML‑сегментацию.
  • Размер чанка подбираем под модель и бюджет: чем меньше токенов — тем дешевле запрос, но выше риск потери контекста.

Сложности при внедрении RAG

  • Динамическая разметка. Автоматические алгоритмы часто рвут смысл. Минимальный рабочий вариант — грубый сплит по токенам с overlap; затем подключаем ML‑сегментацию для тонкой правки свежего контента.
  • Длина чанков. Короткие теряют контекст, длинные несут шум и удорожают запрос. Стартуем с 200‑500 токенов и overlap 10‑20 %, проверяем на реальных запросах и подгоняем порог опытным путем.
  • Релевантность выдачи. KNN‑поиск может пропустить важный фрагмент или вернуть мусор.
  • Накладные расходы. Векторная БД ест память и добавляет задержку. Храним горячие векторы в RAM, холодные — на SSD, используем HNSW‑индексы и кеширование, чтобы цепочка «поиск + LLM» укладывалась в SLA.
Как обработать PDF?
  1. Извлекаем текст (PDF‑miner, Tesseract для сканов).
  2. Чистим, режем на чанки, строим эмбеддинги.
  3. Кладем в vector store вместе с метаданными (имя файла, страница).
Что делать с изображениями?
  1. Прогоняем картинку через CLIP или похожую модель → получаем визуальный эмбеддинг.
  2. (Опционально) генерируем текст‑описание через Vision‑LLM, чтобы LLM мог использовать контент как подсказку.
  3. Сохраняем эмбеддинг + текстовое описание в базе.

Векторные БД — что важно знать

Выбор движка

Открытого кода хватает: Faiss, Milvus, Weaviate, Chroma, Pinecone. Есть и модули для привычных хранилищ — Redis, Postgres, MongoDB. Все поддерживают базовый функционал KNN‑поиска, отличаются скоростью, объемом памяти, удобством администрирования.

Структура записи

  1. embedding — N‑мерный вектор.
  2. content — исходный текст (или ссылка на него).
  3. metadata — любые атрибуты: id, тип документа, язык. По ним удобно фильтровать результаты до ранжирования.

Запросы

  • similarity threshold — порог близости (0‑1). Фильтрует шум.
  • top k — сколько ближайших векторов вернуть. Чем выше k, тем больше шанс покрыть все релевантные чанки.

Индексация

Граф HNSW — дефолт для миллиона‑плюс векторов. IVF + PQ или DiskANN — если важна экономия памяти. Индекс подбирают экспериментально: измеряют latency и recall на боевых запросах.
Коротко
  • Храним «горячие» индексы в RAM, «холодные» — на SSD.
  • Держим отдельное поле для даты — позволяет резать выдачу по свежести.
  • Стартовые значения: threshold 0.3‑0.4, k = 5‑10. Дальше тюним под метрики Precision и Recall.

Индексация документов в Spring AI

Это пример кода, реализации на базе Spring AI.
  1. Метаданные. Из исходного объекта берем нужные поля и кладем в Map.
  2. Документ. Создаем обертку, в которой текст и метаданные идут вместе.
  3. Чанки. TokenTextSplitter режет текст на блоки равной длины. Overlap отсутствует, поэтому часть контекста может пропасть. При желании пишем свой сплиттер.
  4. VectorStore. Метод add сам вызывает embedding‑модель, формирует векторы и сохраняет их вместе с текстом.
В итоге, пять строк кода и документ попадает в векторную БД. Spring AI берет на себя работу с эмбеддингами и хранением, остается лишь выбрать подходящий VectorStore и, при необходимости, доработать логику разбиения.

Поиск документов

VectorStore скрывает всю тяжелую работу. Мы передаем ему текст запроса, а он сам превращает строку в эмбеддинг, ищет ближайшие векторы в базе, возвращает найденные чанки.
Ключевые параметры:
  1. query — сам запрос.
  2. similarityThreshold — минимальная схожесть. Помогает отсеять шум.
  3. topK — сколько результатов нужно.
Возврат приходит уже списком Document. Достаем метаданные и контент — получаем строгий WikiDocument для дальнейшей обработки.
Минимум кода, никакой ручной работы с эмбеддинг‑моделью и индексом — Spring AI берет это на себя.

QuestionAnswerAdvisor: как связать поиск и LLM одной строкой

QuestionAnswerAdvisor — обертка, которая берет на себя весь RAG‑конвейер. В конструктор передаем:
  1. VectorStore — доступ к векторной БД.
  2. SearchRequest.defaults() — дефолтные параметры (threshold, top‑k). При желании подставляем свои.
Дальше в контроллере общаемся только с LLM‑клиентом:
@GetMapping("/search")
public String getWikiAnswer(@RequestParam("question") String question) {
    return chatClient.prompt()     // создаем prompt‑цепочку
        .user(question)         // текст запроса
        .advisors(questionAnswerAdvisor) // подключаем RAG‑адвайзер
        .call()             // вызываем модель
        .content();           // забираем ответ
}
Что происходит под капотом:
  1. LLM‑клиент передает вопрос адвайзеру.
  2. Advisor делает embedding запроса, ищет релевантные чанки в VectorStore, формирует новый prompt (вопрос + контекст).
  3. Модель получает уже обогащенный prompt и генерирует ответ.
В итоге два бина и несколько строк в контроллере закрывают полный цикл «вопрос → поиск → генерация» без ручных вызовов embedding‑модели или индекса.

RAG и fine‑tuning: когда что выгоднее

Актуальность данных

RAG всегда читает свежие документы: добавили файл — индексация, и он уже в ответах. Fine‑tuning фиксирует знания на момент обучения, каждое обновление базы требует нового цикла дообучения.

Стоимость и время

RAG не переобучает модель, значит экономит GPU‑часы и деньги. Fine‑tuning — это платное обучение плюс пауза на эксперименты и валидацию.
Коротко
  • Берем RAG, если нужно работать с динамичными или закрытыми данными и быстро выводить их в прод.
  • Выбираем fine‑tuning, когда важно изменить «стиль мышления» модели: научить ее отвечать по фирменному шаблону, писать код в своем стиле или корректно обрабатывать доменную терминологию.
Комбинация тоже возможна: дообученная модель + RAG для свежести.

Итоги

Retrieval Augmented Generation дает языковым моделям доступ к актуальным данным без затратного переобучения. Индексация новых документов занимает минуты, поэтому информация в ответах всегда свежая. Экономический эффект очевиден: расходы на GPU‑часы и инженерное время ниже, чем при регулярном fine‑tuning, а данные можно обновлять в режиме near‑real‑time.
Гибкость архитектуры позволяет подключать любые источники — корпоративную базу знаний, CRM, веб‑поиск — ровно тогда, когда это нужно бизнесу. Основные риски связаны с качеством поиска и задержкой отклика. Их можно контролировать метриками Precision/Recall, периодическим аудитом релевантности и оптимизацией индексов: «горячие» векторы держим в RAM, холодные переносим на SSD.
Наибольшую отдачу RAG приносит в сервисах поддержки, поисковых интерфейсах с готовым ответом, аналитических панелях и автоматической генерации отчетов. При этом важно понимать, что RAG не заменяет fine‑tuning, но, когда важна актуальность и точность данных, RAG обеспечивает быстрый и масштабируемый результат.