Продвинутые техники RAG для повышения качества
Базовый RAG, embed → vector search → LLM, даёт качество 60–75% на корпоративных задачах. До prod-уровня (85–93%) система доходит за счёт цепочки техник, каждая из которых решает конкретный класс ошибок.
В этом уроке, современный арсенал 2024–2026: что есть, какую проблему решает, цена внедрения, ожидаемый прирост качества.
Откуда берутся ошибки в базовом RAG
| Ошибка | Причина | Где исправлять |
|---|---|---|
| Не нашёл нужный чанк | Asymmetric query/document, узкая терминология | Indexing + query rewriting |
| Нашёл, но не в топе | Bi-encoder слабоват | Reranker |
| В чанке нет контекста (например, «Срок, 14 дней» без указания, чего срок) | Чанк вырван из документа | Contextual Retrieval, parent-document |
| Точные термины не находит | Только vector search | Hybrid + BM25 |
| Сложный многошаговый вопрос | Один retrieval не покрывает | Decomposition, agentic |
| Нет связей между сущностями | Текстовый поиск этого не видит | GraphRAG |
| Ответ выдуман | LLM не следует инструкциям | Self-RAG, CRAG, citation validation |
Техника 1. Hybrid search (Dense + Sparse)
Проблема. Vector search силён на семантике, но проваливается на конкретных терминах: артикул SKU-XJ-2847, имя клиента ООО Ромашка, ключ конфига TLS_VERSION_MIN. BM25 (sparse) их находит на ура, он считает совпадения слов.
Решение. Параллельно делать оба поиска и сливать результаты через Reciprocal Rank Fusion (RRF):
def rrf(rankings: list[list[Doc]], k: int = 60) -> list[Doc]:
scores = {}
for ranking in rankings:
for rank, doc in enumerate(ranking):
scores[doc.id] = scores.get(doc.id, 0) + 1.0 / (k + rank)
return sorted(scores, key=scores.get, reverse=True)
dense = vector_db.search(embed(query), top_k=50)
sparse = bm25.search(query, top_k=50)
candidates = rrf([dense, sparse])[:50]
Прирост качества. Anthropic: recall@20 поднимается с 5.7% (только embeddings) до 4.0% (только BM25) до 2.9% failure при гибриде, то есть failure rate падает почти в 2 раза. На общих корпоративных корпусах: +10–25% к recall@10.
Цена. +1 индекс (Elasticsearch / OpenSearch / Tantivy) + копеечный sparse-запрос. Окупается всегда.
Техника 2. Contextual Retrieval (Anthropic, Sept 2024)
Проблема. Чанк «Срок, 14 дней» в индексе. Что это за срок, не понять. Embedder не видит контекста документа.
Решение. ДО эмбеддинга обогатить каждый чанк коротким контекстом из всего документа, сгенерированным LLM:
prompt = f"""
<document>{full_document}</document>
<chunk>{chunk}</chunk>
Дай короткий (≤100 токенов) контекст, объясняющий,
куда этот чанк помещается в документе. Только контекст, без преамбулы.
"""
ctx = claude_haiku(prompt)
indexed_text = f"{ctx}\n\n{chunk}"
embed(indexed_text) # эмбеддинг идёт уже от обогащённого
Чанк становится: «Из раздела "Отпуск" регламента 2026 (про сроки подачи заявления): Срок, 14 дней».
Прирост качества. Anthropic: failure rate retrieval'а −49% (с 5.7% до 2.9% на их бенчмарке). С rerank'ом, −67%.
Цена. Один Haiku-вызов на чанк при индексации (~$1 на 1M токенов корпуса). Prompt caching снижает цену в 9 раз, сам документ кэшируется на стороне Anthropic, переиспользуется для всех его чанков.
Техника 3. HyDE (Hypothetical Document Embeddings)
Проблема. Запрос «Как взять отпуск?» (5 токенов) и документ «Положение о ежегодном оплачиваемом отпуске устанавливает порядок предоставления...» (500 токенов) по-разному устроены. Их эмбеддинги в разных частях пространства.
Решение. Сначала LLM пишет «гипотетический ответ», потом ищем по нему:
hypo = llm(f"Напиши краткий ответ на вопрос: {query}")
# hypo: "Чтобы взять отпуск, нужно за 14 дней подать заявление руководителю..."
candidates = vector_db.search(embed(hypo), top_k=50)
Гипотетический ответ может быть фактически неверным, но по форме он похож на реальный документ. Это сильно поднимает попадание.
Прирост качества. +5–15% на recall@10. Особенно помогает на коротких/расплывчатых запросах.
Цена. Дополнительный быстрый LLM-call (Haiku/mini-модели). +200–500 мс к latency.
Техника 4. Multi-Query / RAG-Fusion
Проблема. Один запрос, один взгляд. Пользователь сформулировал «как взять отпуск?», а в документе написано «оформление отгулов и отпусков».
Решение. LLM генерирует 3–5 переформулировок, делаем по каждой retrieval, сливаем через RRF:
variants = llm(f"Дай 4 разных перефраза вопроса: {query}").split("\n")
all_results = [vector_db.search(embed(v), top_k=20) for v in [query] + variants]
candidates = rrf(all_results)[:50]
RAG-Fusion (Raudaschl, 2023), это формализованная версия с RRF; стандартный паттерн в LlamaIndex/LangChain.
Прирост качества. +5–15% на recall, особенно для коротких запросов.
Цена. 1 LLM-call + N×search вместо 1×search. Latency +0.5 сек.
Техника 5. Parent-Document / Sentence-Window
Проблема. Маленькие чанки (256 токенов), точный retrieval, но мало контекста в LLM. Большие (1500), много контекста, но топ-50 загрязняется случайным.
Решение 1, Parent-Document (LangChain): индексируем мелкие, но в LLM передаём родительский чанк (или весь документ).
индекс: chunk_small (256 tok) → embed → vector_db
выдача: chunk.parent_id → load parent_chunk (1500 tok) → LLM
Решение 2, Sentence-Window (LlamaIndex): в индексе хранится 1 предложение, при выдаче возвращается ±3 соседних предложения.
Прирост качества. +10–20% на complex QA. Особенно полезно, когда ответ, конкретное число/имя в большом контексте.
Цена. Только усложнение кода indexing'а. Никаких extra LLM-calls.
Техника 6. Reranking (cross-encoder)
Уже разбирали в прошлом уроке как обязательный компонент. Краткое напоминание:
Bi-encoder (для retrieval): эмбеддинг вопроса и документа считается отдельно, потом сравниваются векторы. Быстро, грубовато.
Cross-encoder (reranker): пара (вопрос, документ) идёт в трансформер вместе, выдаёт скор 0..1. Точнее, но нельзя предвычислить.
candidates = retrieve(query, top_k=50)
reranked = cohere.rerank(query=query, documents=[c.text for c in candidates],
top_n=5, model="rerank-v3.5")
top_chunks = [candidates[r.index] for r in reranked.results]
Прирост качества. Anthropic: failure rate с 2.9% (hybrid + contextual) до 1.9% при добавлении rerank'а, ещё −34%. Универсально даёт +5–15% к Precision@5.
Цена. $1 / 1K rerank-calls (Cohere) или GPU-инференс BGE-reranker-v2-m3. +50–200 мс latency.
Техника 7. ColBERT и late-interaction
Идея. Вместо одного вектора на документ, по вектору на каждый токен. На запросе: для каждого токена вопроса ищется ближайший токен документа, скоры суммируются. Это «softmax над матрицей похожестей».
Где работает: очень точный retrieval на длинных документах с разнородным контентом. ColBERT-v2, топ на BEIR-бенчмарках.
Минус: индекс в 10–50 раз больше обычного. Нужен специализированный движок: Vespa, RAGatouille, jina-colbert-v2.
Когда брать: научная литература, юриспруденция, длинные технические документы, там качество окупает.
Техника 8. GraphRAG (Microsoft, 2024)
Проблема. «Кто из сотрудников отдела продаж работал с клиентами из строительной отрасли в Q3?», вопрос про связи, не про текст.
Решение. Помимо текстового индекса строится граф знаний:
- LLM проходит по корпусу, извлекает entities (Person, Company, Project) и relations (worked_with, reports_to).
- Граф кластеризуется (Leiden algorithm) на тематические сообщества.
- На запрос: ищется по графу + по тексту, ответы агрегируются.
Реализации:
- Microsoft GraphRAG (open-source, Python), reference implementation.
- LightRAG (HKU, 2024), упрощённый вариант с двухуровневым retrieval (low-level facts + high-level themes), в 5–10× дешевле GraphRAG.
- Neo4j + LangChain, связка для production.
- TigerGraph CoPilot, Memgraph MAGE, managed варианты.
Прирост качества. На multi-hop вопросах GraphRAG обходит baseline RAG на 20–50% (Microsoft research). На простых факт-вопросах, на уровне baseline или чуть хуже (overhead).
Цена. Дорого: построение графа = LLM-вызов на каждый чанк (~$10–100 на индексацию 10M токенов). Поддержка графа при обновлениях нетривиальна.
Когда брать: домены с густыми связями (юриспруденция, медицина, корпоративные knowledge graphs, аналитика клиентов).
Техника 9. Self-RAG / Reflection
Идея (Self-RAG, Asai et al. 2023). LLM сам решает, нужен ли вообще retrieval для конкретного вопроса, и сам критикует найденные документы и свой ответ через специальные «reflection tokens»:
[Retrieve], нужно искать?[IsRel], релевантен ли документ?[IsSup], поддерживается ли утверждение источниками?[IsUse], полезен ли финальный ответ?
Модель дотренирована генерировать эти токены наряду с обычным текстом.
Прирост качества. На FactScore точность улучшается на 15–30% против стандартного RAG. Снижает галлюцинации в полтора-два раза.
Цена. Нужна fine-tuned модель (есть открытые self-rag-llama2-7b, self-rag-llama2-13b). Или эмулировать через стандартный LLM с правильными промптами.
Техника 10. CRAG (Corrective RAG)
Идея (Yan et al. 2024). После retrieval лёгкий classifier оценивает: документы (а) корректны, (б) неоднозначны, (в) некорректны. По результату:
- Correct: обычная генерация.
- Incorrect: делать web search (fallback), брать оттуда контекст.
- Ambiguous: комбинировать оба источника.
Реализуется через любой evaluator (T5-large, GPT-mini как judge).
Прирост качества. На PopQA и Biography бенчмарках, стабильное превосходство над baseline и Self-RAG.
Цена. +1 LLM-call (judge), потенциально +1 web search.
Техника 11. Query Routing
Проблема. В компании несколько источников: HR-регламенты, тех-документация, CRM-данные. Бить во все одновременно, шум. Иметь один индекс на всё, путаница терминологии.
Решение. LLM-classifier (или fine-tuned small model) на входе решает, в какой источник идти:
intent = classify(query)
match intent:
case "hr": kb = hr_index
case "tech": kb = tech_index
case "crm": return crm_agent.query(query) # function call вместо RAG
case "general": return llm(query) # без RAG
Прирост качества. Снижает false positives, ускоряет ответ, удешевляет (не делать ненужный retrieval).
Цена. 1 классификатор на входе. Для классификации можно использовать gpt-5-mini ($0.0001 на запрос) или fine-tuned BERT.
Техника 12. Agentic RAG
Идея. LLM, не просто генератор ответа, а агент: рассуждает, планирует, вызывает инструменты (включая retrieval как один из tools), сам решает, когда остановиться.
[вопрос: "Сколько мы заработали на клиенте N в прошлом году?"]
│
▼
[Agent loop]
├─ tool: crm_lookup(name="N") → клиент с тремя дочками
├─ tool: rag_search("выручка по дочерним компаниям клиента N 2025")
├─ tool: sql_query("SELECT SUM(amount) FROM revenue WHERE client_id IN (...)")
└─ synthesize → "Совокупная выручка ~$2.4M (CRM + ERP + RAG)"
Реализации: LangGraph (LangChain), CrewAI, AutoGen (Microsoft), Semantic Kernel, Anthropic Agents SDK / Claude Code SDK, OpenAI Assistants API.
Прирост качества. На сложных multi-step вопросах, качественно другой уровень. На простых, overhead, ниже точность из-за «лишних» рассуждений.
Цена. 5–20 LLM-вызовов на сложный запрос. Latency 10–60 сек. Стоимость ×5–20 от обычного RAG.
Техника 13. Long-context post-processing (Map-Reduce, Refine)
Проблема. Иногда ответ требует синтеза из 50–100 чанков, не из 5.
Решения (LlamaIndex / LangChain паттерны):
- Map-Reduce: для каждого чанка, мини-ответ; потом reduce-LLM объединяет.
- Refine: последовательно, каждый следующий чанк уточняет предыдущий ответ.
- Tree summarize: иерархическое сжатие.
Когда нужно: обзорные вопросы («суммируй всё, что у нас есть про продукт X»). Не для precision-задач.
Сводная таблица: что когда применять
| Техника | Прирост | Цена внедрения | Когда обязательно |
|---|---|---|---|
| Hybrid search | +10–25% recall | Низкая | Всегда |
| Reranker | +5–15% precision | Низкая | Всегда |
| Contextual Retrieval | −49% failure | Средняя ($) | Длинные документы с глобальным контекстом |
| HyDE | +5–15% recall | Низкая | Короткие/расплывчатые запросы |
| Multi-query / RAG-Fusion | +5–15% recall | Низкая | Разнообразный язык пользователей |
| Parent-Document / Sent-Window | +10–20% answer quality | Низкая (только код) | Точные ответы в больших документах |
| ColBERT | +10–20% precision | Высокая (инфра) | Юриспруденция, наука, длинные тех-доки |
| GraphRAG | +20–50% multi-hop | Высокая ($$$) | Связи между сущностями |
| Self-RAG | +15–30% factuality | Средняя (fine-tune) | Высокая цена галлюцинаций |
| CRAG | Стабильность | Средняя | Возможен fallback на веб |
| Query Routing | Снижение шума | Низкая | Несколько источников |
| Agentic | Качественно | Очень высокая ($$$$) | Сложные multi-step |
Что важно понимать
Базовый рецепт прода 2026: hybrid search + Contextual Retrieval + reranker. Это даёт ~85% качества за разумные деньги. Дальше, точечно, под обнаруженные проблемы.
Не сваливайте всё сразу. Каждая техника решает конкретный класс ошибок. Без эталонного датасета (см. следующий урок) вы не поймёте, какая помогла, а какая всё запутала.
Цена усложнения растёт быстрее качества. Переход baseline → hybrid + rerank даёт +20% за 5% работы. Переход prod → agentic GraphRAG даёт +5% за 50% работы. Считайте окупаемость.
Самый недооценённый рычаг, данные. Чистый и хорошо структурированный корпус с базовым RAG бьёт грязный корпус с самыми продвинутыми техниками. Об этом, следующий урок: подводные камни и как мерить качество.