Главное: RAG — это не просто «поиск + LLM». В локальном эксперименте основная дополнительная нагрузка появилась не в vector DB, а в embedding запроса, росте размера prompt и его обработке моделью. Top-k, chunk size и retrieval mode оказались параметрами проектирования и контроля, а не техническими настройками «по умолчанию». Главный вывод: стратегию retrieval нужно выбирать под тип вопроса, структуру данных, latency budget и требований к качеству.
Введение
Когда говорят про RAG, его часто описывают как простой способ улучшить LLM-систему: добавить поиск по внешним данным, найти релевантный контекст, передать его модели и получить более точный ответ.
На уровне идеи и теории это действительно выглядит логично.
Но в реальной системе RAG — это не только способ обогатить ответ, а отдельный операционный слой, который влияет на задержку, размер prompt, количество input tokens, стоимость запроса, качество ответа, SLA и требования к наблюдаемости системы.
Я хотел посмотреть на это не в формате общих рассуждений, а на небольшом локальном стенде: где именно появляется дополнительная нагрузка, какие параметры сильнее всего влияют на задержки (latency), почему больше контекста не всегда означает лучшее качество и почему стратегия поиска (retrieval) должна зависеть от типа вопроса и структуры данных.
Это не бенчмарк моделей и не сравнение векторных БД, а практический эксперимент в рамках определенного дизайна для понимания механизмов и архитектурных компромиссов при внедрении RAG.
В статье специально оставляю часть метрик и терминов на английском языке т.к. они являются общепринятыми обозначениями, которые удобнее воспринимать именно в таком виде. Часть англоязычных терминов которым не дана расшифровка — или интуитивно понятна, или ее можно легко найти в поисковике и почитать подробнее (в контексте больших языковых моделей — LLM).
Стенд и ограничения
Эксперименты проводились локально:
-
LLM: mistral:7b
-
embedding модель: qwen3-embedding:0.6b
-
векторное хранилище: Chroma
-
runtime: Ollama + local Chroma
-
GPU: RTX 3090 Ti 24 GB
-
без параллельной нагрузки
-
без reranking
-
без tools / agents
-
без продуктовой оркестрации
Корпус документов (corpus) был небольшим: текстовые файлы про retrieval, embeddings, latency, выдержки из публичной документации Chroma, Ollama, API справочник, диагностику и метрики.
Важное ограничение: часть знаний в корпусе пересекалась с тем, что модель могла знать сама. Поэтому часть экспериментов показывает не истинную ценность продуктового / корпоративного (production / enterprise) RAG, а поведение RAG в ситуации, где знания корпуса и базовой модели частично пересекаются.
После первого прогона я уточнил набор вопросов и отдельно проверил сценарии, которые лучше соответствовали содержанию корпуса и это оказалось важным: выводы по latency и overhead сохранились, а оценка качества заметно зависела от соответствия вопросов корпусу.
Я смотрел не только на итоговое время ответа, но и на следующие метрики:
В части задержки (latency):
-
TTFT
-
E2E latency
-
prompt eval duration
-
decode time
В части поиска (retrieval):
-
query embedding time
-
retrieval time
-
retrieved chars
-
assembled prompt size
-
input tokens actual
В части качества:
-
answer correctness
-
groundedness
-
completeness
-
context noise
-
лучший метод поиска (retrieval mode) по классу вопроса
Главная задача была не просто понять: RAG быстрее или медленнее, а разобраться, что именно при использовании RAG делает систему тяжелее.
Простая базовая проверка RAG: где появляется дополнительная нагрузка
Первый шаг был простой: сравнить сценарии запросов с RAG и без него.
Ожидание: RAG добавит дополнительную нагрузку — но важно было понять, где именно она появится.
Результат оказался полезным: сам поиск через Chroma был быстрым, в этом контуре векторное хранилище не было главным узким местом.
Основная нагрузка появилась в другом месте:
-
построение embedding для запроса
-
увеличение assembled prompt
-
рост input tokens actual
-
дальнейшая обработка prompt на стороне LLM
Иными словами, RAG может быть дорогим не потому что поиск медленный, а потому что найденный контекст увеличивает входной prompt, который потом должна обработать модель.


Здесь важен не сам факт, что RAG стал медленнее. Важнее другое: скорость vector DB сама по себе еще не означает, что весь RAG pipeline будет дешевым. Даже быстрый поиск может привести к росту TTFT, prompt eval duration и общей стоимости запроса.
Retrieval vs no-RAG: когда RAG оправдан
Следующий вопрос был практический: если RAG добавляет нагрузку, то когда он действительно окупается?
Я сравнивал ответы no-RAG и RAG на разных типах вопросов и оценивал, стал ли ответ полезнее.
Первый прогон дал неоднозначную картину: где-то RAG помогал, где-то был нейтрален, а где-то даже ухудшал практическую полезность ответа.
Позже стало понятно, что часть вопросов была не идеально согласована с содержанием корпуса. После повторной проверки на вопросах, которые лучше соответствовали документам, картина стала лучше: RAG чаще давал более обоснованные и корректные ответы, а no-RAG чаще ошибался на терминах и деталях, специфичных для корпуса.
Но вывод по задержке и нагрузке (overhead) не изменился.
Для меня здесь главное разделение такое:
-
выводы по latency и overhead оказались устойчивыми;
-
выводы по качеству сильно зависят от качества корпуса, релевантности документов и соответствия вопросов корпусу.
То есть тезис не в том, что «RAG плохой» или «RAG всегда полезен».
Более точный вывод:
Retrieval нужно оценивать как компромисс между практической полезностью и дополнительной нагрузкой на систему:
-
Если найденный контекст действительно исправляет ошибку модели, добавляет нужные факты или помогает уточнить ответ на основе внешней базы знаний (groundedness) — дополнительная стоимость может быть оправдана.
-
Если retrieval приносит контекст, который модель и так знает, или вытаскивает нерелевантный шум, система становится тяжелее без сопоставимой пользы.
top-k: не «чем больше, тем лучше»
Дальше я проверял влияние top-k.
Здесь есть распространенная интуитивная ловушка: взять больше chunks на всякий случай, чтобы модель получила больше контекста.
Но top-k напрямую влияет на:
-
retrieved payload
-
assembled prompt size
-
input tokens actual
-
TTFT
-
prompt eval duration
-
context noise
В моем сценарии проверки рост top-k почти линейно увеличивал объем найденного контекста и input tokens actual.
Например, при росте top-k с 1 до 10 input tokens actual выросли примерно с 522 до 3881.
Сам поиск оставался быстрым, но нагрузка на обработку prompt росла.

Примечание:
До top-k=7 рост умеренный, на top-k=10 видно усиление overhead. Для графика использованы усредненные значения по серии вопросов, он показывает общий тренд, а не универсальные значения для top-k.
По качеству линейного улучшения не было.
Больше chunks не означало автоматически лучший ответ.
После повторной проверки на более подходящих вопросах рабочий диапазон выглядел ближе к top-k = 3–5, с осторожным допуском 7.
top-k = 1 иногда был слишком узким, а top-k = 10 уже выглядел как тяжелая пограничная точка: контекста и задержки больше, а стабильного прироста качества нет.
Главный вывод:
top-k — это не просто настройка retrieval, это параметр, который необходимо заранее планировать при проектировании системы в зависимости от контекста решаемых задач.
Его нужно выбирать по балансу между полезностью ответа, задержкой, стоимостью и лишним контекстом.
chunk size: не просто подготовка данных
Похожая история получилась с chunk size.
На первый взгляд это техническая деталь подготовки данных, но на практике chunk size определяет — какую единицу знания увидит retrieval и сколько лишнего текста попадет в prompt.
Я проверял несколько размеров:
-
500 chars
-
1000 chars
-
1500 chars
-
2500 chars
В моем дизайне проверки:
-
500-1000 chars дали наиболее устойчивое качество при низком уровне лишнего контекста (context noise);
-
1500 chars иногда оставался полезным, но уже давал нестабильность;
-
2500 chars выглядел как тяжелая верхняя точка: больше добавленного контекста (payload), выше TTFT, выше prompt eval duration, больше шума и иногда ошибки.
Важно: метрики нагрузки росли достаточно ожидаемо, но качество не росло линейно вместе с размером chunk.
Более крупный chunk может сохранить больше контекста, но он также может принести лишнюю информацию, увеличить prompt, ухудшить задержку и не дать сопоставимого улучшения ответа.

Поэтому:
chunk size — это параметр проектирования системы, а не просто техническая настройка по умолчанию при подготовке данных.
И, конечно, найденный диапазон 500-1000 chars не универсален, это результат именно для этого корпуса, этой embedding model, этой структуры документов, этого prompt contract и этой LLM.
Chunked retrieval vs document-level retrieval
Последний эксперимент оказался самым важным концептуально.
Я сравнивал разные подходя к retrieval:
-
chunked 500
-
chunked 1000
-
поиск на уровне документа
-
двухэтапный поиск
И разные типы вопросов:
-
точечный поиск факта
-
различение близких терминов
-
рассуждение по полной таблице
-
вопрос по нескольким разделам документа
Здесь стало хорошо видно, что chunked vector retrieval — не универсальный вариант по умолчанию.
Для точечного поиска и различения терминов chunks часто были достаточно хороши, они давали правильный ответ с меньшим объемом prompt.
Но для рассуждения по полной таблице лучше сработал поиск на уровне документа, потому что он сохранял таблицу как цельный контекст. Chunked retrieval мог вернуть релевантные куски, но не весь контекст, нужный для группировки по строкам.
Двухэтапный поиск тоже не оказался магическим решением. Он может помочь, если первый этап правильно выбрал документ, но если выбор документа ошибочный, второй этап только усиливает ошибку: дальнейший поиск chunks идет уже внутри неправильного источника.

Главный вывод всей серии:
единица retrieval контекста должна соответствовать типу вопроса и структуре документа.
Иначе система может технически найти релевантные chunks, но все равно дать неполный или неправильный ответ.
Важно: это не означает, что поиск на уровне документов лучше всегда. Он лучше сработал именно там, где вопрос требовал цельного контекста, полной таблицы или связанного документа. Для точечного поиска факта такой режим часто избыточен, он передает больше контекста, увеличивает размер prompt и может ухудшать latency без заметного прироста качества.
То есть поиск на уровне документов решает проблему неполного контекста, но создает другую: больший prompt. Двухэтапный поиск может быть компромиссом, но только при надежном выборе документа на первом этапе.
Что из этого следует для архитектуры RAG
RAG нельзя проектировать как один универсальный pipeline:
разбить документы на chunks -> построить embeddings -> сделать top-k векторный поиск -> передать результат в LLM
Это нормальный базовый вариант, но не всегда правильное архитектурное решение.
В продуктовой системе стратегия retrieval должна зависеть от:
-
типа вопроса
-
структуры документа
-
требований к полноте ответа
-
допустимого latency budget
-
cost per request
-
риска context noise
-
необходимости groundedness
-
формата данных: текст, таблица, инструкция, диагностический документ, API-справочник
Примеры:
-
точечный поиск факта — chunked retrieval обычно достаточно
-
различение близких терминов — chunked retrieval часто работает хорошо
-
рассуждение по полной таблице — нужен поиск на уровне документа, retrieval с учетом структуры таблиц или структурированный retrieval
-
вопрос по нескольким разделам документа — может потребоваться поиск на уровне документа или двухэтапный поиск
-
термины, специфичные для конкретного корпуса — RAG полезен, если retrieval действительно приносит правильный контекст

Что важно мониторить
Если RAG используется в продуктовом / платформенном контуре, недостаточно смотреть только на E2E latency.
Минимальный набор мониторинга для RAG:
-
query class
-
retrieval mode
-
top-k
-
chunk size
-
retrieved chars
-
assembled prompt chars
-
input tokens actual
-
TTFT
-
prompt eval duration
-
E2E latency
-
answer correctness
-
groundedness
-
completeness
-
context noise
-
cost per request
Ключевой вопрос не только: retrieval вернул что-то похожее?
А скорее: retrieval вернул правильную единицу контекста для этого вопроса?
Напомню ограничения
-
локальный стенд
-
одна LLM
-
одна embedding model
-
небольшой корпус документов
-
часть документов синтетические, но реалистичные (сформированы специально для управляемого выявления потенциальных сбоев)
-
без reranking
-
без гибридного поиска
-
без конкурентной нагрузки в продуктовой среде
-
качество ответов оценивалось отдельно по простой шкале, без детальной методики оценки
-
один прогон в ряде сравнений
-
Mistral 7B мог ограничивать качество reasoning, особенно на задачах с таблицами.
Поэтому абсолютные цифры не нужно напрямую переносить на другие стеки.
Но цель была другой: посмотреть на механизмы и компромиссы и в этом смысле результаты полезны.
Финальный вывод
RAG — это не бесплатный слой улучшения качества, это операционный слой системы, который влияет на:
-
latency
-
input tokens
-
prompt processing
-
context budget
-
cost per request
-
SLA
-
качество и шум ответа
top-k, chunk size и стратегия retrieval — это не технические мелочи, а параметры проектирования системы.
Самый практичный вывод для меня такой:
RAG нужно проектировать не от технологии, а от типа вопроса, структуры данных и допустимой дополнительной нагрузки.
-
Иногда chunked vector retrieval — правильный выбор
-
Иногда нужен retrieval на уровне документа
-
Иногда нужен двухэтапный подход
-
А иногда retrieval вообще не оправдывает свою стоимость
Что это значит для продуктового / платформенного решения
Перед масштабированием RAG важно понять:
-
стоит ли использовать RAG в конкретном сценарии
-
какой latency budget допустим
-
какой тип вопросов задают пользователи
-
какая единица контекста нужна: chunk, документ, таблица, метаданные
-
какие метрики качества нужны до масштабирования
-
когда retrieval нужно улучшать, а когда сценарий лучше остановить
Именно поэтому вопрос «добавим ли RAG?» менее важен, чем вопрос:
«какая стратегия retrieval нужна для конкретного сценария использования и как мы будем измерять и контролировать, что она действительно работает?»
ссылка на оригинал статьи https://habr.com/ru/articles/1040938/