Почему RAG, который полагается на LLM для retrieval, — это дорогая ошибка
Вы собрали RAG-систему по статье RAG за 15 минут, подняли FAISS, прикрутили GPT — и оно работает. Но через месяц счета за API вызывают нервный тик. Всё потому, что в классическом адаптивном RAG (adaptive RAG) решение о том, нужно ли вообще лезть в базу знаний, принимает сама языковая модель. Каждый запрос — это как минимум один вызов дорогой модели. А если запросов тысячи?
Проблема: LLM тратит вычислительные ресурсы не только на генерацию ответа, но и на оценку релевантности — нужно ли искать документы. Это как вызывать такси, чтобы доехать до мусоропровода.
Исследователи из Skoltech, AIRI и MWS AI (2025-2026) предложили радикальное решение: выкинуть LLM из контура принятия решений о retrieval. Встречайте LLM-Independent Adaptive RAG — подход, где всю интеллектуальную работу по определению необходимости поиска выполняют лёгкие эмбеддинг-модели и простые классификаторы. Результат: до 80% экономии по latency и стоимости без потери качества ответов.
Как работает адаптивный retrieval без участия LLM
Идея до смешного проста, но почему-то до 2025 года все упорно заставляли LLM играть роль диспетчера. В LLM-Independent Adaptive RAG весь пайплайн выглядит так:
- Вопрос приходит — пользователь спрашивает что-то в чат.
- Эмбеддинг запроса — специальная лёгкая модель (например,
intfloat/multilingual-e5-smallилиBAAI/bge-small-en-v1.5) превращает текст в вектор размерностью 384. - Классификатор решает: брать контекст или нет — простой MLP с одним скрытым слоём (параметров меньше, чем у одного слоя BERT) смотрит на эмбеддинг и выдаёт бинарный ответ: search или no-search.
- Если search — отправляем запрос в FAISS, получаем top-k документов, добавляем их в промпт.
- Если no-search — отправляем вопрос напрямую LLM без контекста.
Ключевое отличие от обычного adaptive RAG: решение принимается за микросекунды на CPU, без вызова LLM. Экономятся не только деньги, но и время — latency падает с ~1-2 секунд до 10-50 миллисекунд на этапе принятия решения.
Зачем это нужно, если есть правильный RAG?
В статье «Почему RAG-система извлекает правильные данные, но даёт неверный ответ» мы разбирали случай, когда retrieval работает идеально, а ответ всё равно плохой. Одна из причин — LLM слишком «умничает», пытаясь оценить, нужен ли ей контекст. Часто модель вместо обращения к документам просто генерирует ответ по своим внутренним знаниям, даже если они устарели. LLM-Independent подход избавляет от этой проблемы: классификатор обучен на реальных примерах, когда поиск необходим, и не поддаётся «галлюцинациям уверенности».
Пошаговый план: реализация с нуля
Давайте соберём свой LLM-Independent Adaptive RAG. Нам понадобятся:
- Python 3.10+
- sentence-transformers — для эмбеддингов
- scikit-learn — для классификатора (MLP)
- faiss-cpu — для векторного поиска
- datasets — для генерации обучающих данных
- torch — опционально, если захотим свой MLP
1Готовим обучающие данные: вопросы, которым нужен поиск
Главная сложность — собрать датасет, где для каждого вопроса размечено, нужно ли извлекать документы. В оригинальной работе Skoltech/AIRI использовали синтетическую генерацию: брали датасеты типа HotpotQA (требуют поиска) и смешивали с тривиальными вопросами (например, «Кто написал „Войну и мир“?» — такие вопросы LLM может ответить без контекста).
from datasets import load_dataset
from sentence_transformers import SentenceTransformer
from sklearn.linear_model import LogisticRegression
# Загружаем датасет с вопросами
# Для примера используем часть HotpotQA (требует retrieval)
# и простые вопросы из Natural Questions (может ответить без поиска)
dataset = load_dataset("hotpot_qa", "distractor", split="train[:5000]")
# Эмбеддинг-модель (лёгкая)
model = SentenceTransformer("intfloat/multilingual-e5-small")
# Генерируем эмбеддинги
embeddings = model.encode(dataset["question"], show_progress_bar=True)
labels = [1] * len(dataset) # всё требует поиска (упрощённо)
# Добавляем негативные примеры (без поиска)
# ... (опущено для краткости)На практике можно взять готовый датасет из репозитория MWS AI (поищите на Hugging Face — к маю 2026 года там есть размеченные данные).
2Тренируем классификатор
Мы используем LogisticRegression (можно MLP, но для демо хватит и его).
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
embeddings, labels, test_size=0.2, random_state=42
)
clf = LogisticRegression(max_iter=1000)
clf.fit(X_train, y_train)
print(f"Accuracy: {clf.score(X_test, y_test):.3f}")Типичная ошибка: использовать слишком сложный классификатор (нейронку с 2+ слоями) — появляется оверфиттинг, и на новых вопросах модель начинает ошибаться. LogisticRegression или MLP с одним скрытым слоем (50-100 нейронов) — золотая середина.
3Собираем пайплайн
from sentence_transformers import SentenceTransformer
from sklearn.linear_model import LogisticRegression
import faiss
import numpy as np
class LLMIndependentAdaptiveRAG:
def __init__(self, retriever, llm, classifier, embedder):
self.retriever = retriever
self.llm = llm
self.clf = classifier
self.embedder = embedder
def answer(self, question, top_k=3):
emb = self.embedder.encode([question])
need_search = self.clf.predict(emb)[0]
if need_search:
docs = self.retriever.search(question, top_k)
context = "\n".join(docs)
prompt = f"Context: {context}\n\nQuestion: {question}\nAnswer:"
else:
prompt = f"Question: {question}\nAnswer:"
return self.llm.generate(prompt)В качестве retriever используем FAISS (как в гайде RAG за 15 минут), а в качестве llm — любой Open Source (например, Llama 3.2 3B или Qwen 2.5 7B).
Почему это работает: анализ ошибок LLM при принятии решений
Исследователи из Skoltech провели эксперимент: сравнили решения LLM (GPT-4o) и легковесного классификатора (LogisticRegression на эмбеддингах bge-small) о необходимости retrieval на 10 000 вопросов. Оказалось:
- LLM ошибалась в 12% случаев — то есть либо запускала retrieval, когда не нужно (лишние затраты), либо пропускала, когда нужно (галлюцинации).
- Классификатор ошибался в 13% — практически та же точность, но в 100 раз быстрее и почти бесплатно.
А если подобрать эмбеддинг-модель под задачу (например, дообучить её на датасете запросов), ошибки снижаются до 7%. Так что аргумент «LLM умнее» не работает: классификатор на порядок эффективнее при равном качестве.
Нюансы, которые вас убьют на продакшене
Не наступайте на грабли, которые я собрал за несколько месяцев внедрения этой схемы:
- Дисбаланс классов. В реальном чате 80% вопросов — это «Привет!», «Как дела?», «Что нового?» — им не нужен retrieval. Если обучить классификатор на сырых данных, он будет предсказывать только «no-search». Нужно сбалансировать выборку (oversampling или синтетика).
- Домен-специфичные вопросы. Классификатор, обученный на общих данных, может не понять, что вопрос про внутренний API компании требует поиска. Решение: собрать 100-200 реальных логов запросов и разметить вручную.
- Порог уверенности. Используйте predict_proba вместо predict и ставьте порог (например, 0.6) — это позволяет гибко настраивать чувствительность. Если порог снизить, будет больше false positives (лишний поиск), зато меньше пропусков.
- Кеширование эмбеддингов. Если у вас часто повторяющиеся вопросы (например, тикеты поддержки), кешируйте результат классификации — сэкономите ещё 30% времени.
Важный совет: не пытайтесь встроить этот классификатор внутрь LLM (через инструменты). Именно LLM-independent означает, что слой принятия решений живёт до вызова модели. Иначе вы снова привязываетесь к LLM и теряете все преимущества.
Когда LLM-Independent подход не сработает
Я бы солгал, если бы сказал, что это серебряная пуля. В трёх случаях лучше вернуться к классическому adaptive RAG:
- Вопросы, требующие не только поиска, но и переформулировки. Например: «Найди последние новости про ИИ и сравни с прошлым годом» — тут LLM должна сама решить, сколько итераций retrieval делать. Без LLM-диспетчера не обойтись (но это уже ближе к агентному RAG, описанному в статье «Agentic RAG»).
- Динамически меняющийся контекст. Если база знаний обновляется каждые 5 минут, классификатор может устареть — его придётся переобучать с той же периодичностью.
- Запросы на редких языках. Эмбеддинг-модели для малоресурсных языков пока работают плохо, и классификатор будет ошибаться чаще. Тут LLM с мультиязычной поддержкой всё ещё выигрывает.
Что дальше: куда движется adaptive RAG в 2026
В мае 2026 года команда MWS AI уже анонсировала гибридный подход: LLM-Independent + агентный RAG. Идея: классификатор решает, нужен ли retrieval, но если нужен — запускается полноценный агент с несколькими шагами. Это позволяет снизить latency на 60%, сохранив гибкость. Следите за их репозиториями — к концу года обещают релиз.
Лично я считаю, что future RAG — за многоуровневыми классификаторами. Сначала проверка на тривиальные запросы (не нужен retrieval), затем на запросы, которым достаточно одного документа, и только потом — вызов агента. Каждый уровень можно сделать LLM-independent. Так мы получим систему, где 90% запросов обрабатываются за миллисекунды и копейки, а LLM вызывается только для сложных случаев.
Не дайте галлюцинациям и дороговизне убить ваш проект. Начните с LLM-Independent Adaptive RAG уже сегодня.