Продвинутый RAG: объяснение LongRAG, Self-RAG и GraphRAG
LongRAG, Self-RAG, GraphRAG — технологии следующего поколения
Генерация с дополнением извлечения (RAG) развилась далеко за пределы простого поиска по векторной схожести. LongRAG, Self-RAG и GraphRAG представляют собой передовой край этих возможностей.
Современные системы RAG должны уметь обрабатывать огромные документы, понимать сложные взаимосвязи между сущностями и многое другое.
Это красивое изображение сгенерировано с помощью модели ИИ Flux 1 dev.
Эволюция за пределами базового RAG
Традиционные системы RAG следуют простой схеме: разбивают документы на фрагменты (чанки), преобразуют их в векторы, извлекают похожие фрагменты с помощью косинусной схожести и передают их в LLM. Хотя этот подход эффективен для многих сценариев, он сталкивается с трудностями в трех критических ситуациях:
Понимание различий между поиском (search), углубленным поиском (deepsearch) и углубленными исследованиями (deep research) помогает прояснить, почему для сложных задач извлечения информации необходимы продвинутые варианты RAG. Для более глубокого погружения в эти концепции см. Поиск vs Углубленный поиск vs Углубленные исследования.
- Дальнодействующие зависимости: Важный контекст может охватывать тысячи токенов в нескольких фрагментах
- Уверенность в извлечении: Система не имеет возможности оценить, действительно ли извлеченный контент релевантен
- Сложность взаимосвязей: Векторная схожесть не может уловить тонкие связи между сущностями
Продвинутые варианты RAG решают эти ограничения с помощью специализированных архитектур, ориентированных на конкретные вызовы.
LongRAG: Покорение расширенного контекста
Обзор архитектуры
LongRAG фундаментально пересматривает стратегию разбивки на фрагменты, используя LLM с расширенными окнами контекста (32K, 100K или даже 1M токенов). Вместо того чтобы разбивать документы на маленькие фрагменты по 512 токенов, LongRAG использует иерархический подход:
Встраивание на уровне документа: Весь документ (или очень большие разделы) обрабатывается как единое целое. Встраивание на уровне документа захватывает общий семантический смысл, при этом сохраняя полный текст для последующей обработки.
Минимальная фрагментация: Когда разбивка на фрагменты необходима, LongRAG использует гораздо большие фрагменты (4K-8K токенов) со значительным перекрытием (20-30%). Это сохраняет нарративный поток и снижает фрагментацию контекста.
Сборка контекста: В момент извлечения LongRAG возвращает полные документы или большие связные разделы, а не разрозненные фрагменты. LLM получает непрерывный контекст, сохраняющий структурные и семантические взаимосвязи.
Стратегия реализации
Вот концептуальная реализация на Python с использованием современных моделей встраивания:
from typing import List, Dict
import numpy as np
class LongRAGRetriever:
def __init__(self, model, chunk_size=8000, overlap=1600):
self.model = model
self.chunk_size = chunk_size
self.overlap = overlap
self.doc_embeddings = []
self.documents = []
def create_long_chunks(self, text: str) -> List[str]:
"""Создание больших перекрывающихся фрагментов"""
chunks = []
start = 0
while start < len(text):
end = start + self.chunk_size
chunk = text[start:end]
chunks.append(chunk)
start += (self.chunk_size - self.overlap)
return chunks
def index_document(self, doc: str, metadata: Dict):
"""Индексация документа с иерархическим встраиванием"""
# Встраивание всего документа
doc_embedding = self.model.embed(doc)
# Создание больших фрагментов с перекрытием
chunks = self.create_long_chunks(doc)
chunk_embeddings = [self.model.embed(c) for c in chunks]
self.doc_embeddings.append({
'doc_id': len(self.documents),
'doc_embedding': doc_embedding,
'chunk_embeddings': chunk_embeddings,
'chunks': chunks,
'full_text': doc,
'metadata': metadata
})
self.documents.append(doc)
def retrieve(self, query: str, top_k: int = 3) -> List[Dict]:
"""Извлечение релевантного контента в длинном формате"""
query_embedding = self.model.embed(query)
# Оценивание на уровне документа в первую очередь
doc_scores = [
np.dot(query_embedding, doc['doc_embedding'])
for doc in self.doc_embeddings
]
# Получение лучших документов
top_doc_indices = np.argsort(doc_scores)[-top_k:][::-1]
results = []
for idx in top_doc_indices:
doc_data = self.doc_embeddings[idx]
# Для каждого документа находим лучшие фрагменты
chunk_scores = [
np.dot(query_embedding, emb)
for emb in doc_data['chunk_embeddings']
]
best_chunk_idx = np.argmax(chunk_scores)
# Возврат расширенного контекста вокруг лучшего фрагмента
context_chunks = self._get_extended_context(
doc_data['chunks'],
best_chunk_idx
)
results.append({
'text': ''.join(context_chunks),
'score': doc_scores[idx],
'metadata': doc_data['metadata']
})
return results
def _get_extended_context(self, chunks: List[str],
center_idx: int) -> List[str]:
"""Получение расширенного контекста вокруг релевантного фрагмента"""
start = max(0, center_idx - 1)
end = min(len(chunks), center_idx + 2)
return chunks[start:end]
Сценарии использования и производительность
LongRAG преуспевает в сценариях, где важен контекст:
- Анализ юридических документов: Контракты и юридические резюме часто имеют зависимости, охватывающие десятки страниц
- Извлечение научных статей: Понимание методологии требует связных разделов, а не изолированных абзацев
- Репозитории кода: Функции и классы должны быть поняты в контексте их модуля
Характеристики производительности:
- Задержка: Выше из-за обработки больших фрагментов (в 2-5 раз медленнее стандартного RAG)
- Точность: Улучшение на 15-25% в бенчмарках QA для длинных текстов
- Память: Требуется в 3-4 раза больше памяти для окон контекста
Self-RAG: Рефлексивное извлечение
Основные принципы
Self-RAG вводит метакогнитивный слой в системы RAG. Вместо слепого извлечения и генерации система активно размышляет о своих собственных процессах с помощью специальных токенов размышления:
Токен извлечения: Решает, необходимо ли извлечение для данного запроса Токен релевантности: Оценивает, являются ли извлеченные документы действительно релевантными Токен поддержки: Проверяет, поддерживается ли сгенерированный ответ извлеченным контентом Токен критики: Оценивает общее качество сгенерированного ответа
Архитектурные компоненты
Архитектура Self-RAG состоит из трех переплетающихся фаз:
class SelfRAGSystem:
def __init__(self, retriever, generator, critic):
self.retriever = retriever
self.generator = generator
self.critic = critic
def generate_with_reflection(self, query: str,
max_iterations: int = 3):
"""Генерация ответа с самоанализом"""
# Фаза 1: Решение о необходимости извлечения
retrieve_decision = self.critic.should_retrieve(query)
if not retrieve_decision:
# Прямая генерация без извлечения
return self.generator.generate(query)
# Фаза 2: Извлечение и оценка релевантности
retrieved_docs = self.retriever.retrieve(query)
relevant_docs = []
for doc in retrieved_docs:
relevance_score = self.critic.assess_relevance(
query, doc
)
if relevance_score > 0.7: # Порог
relevant_docs.append(doc)
if not relevant_docs:
# Откат к генерации без извлечения
return self.generator.generate(query)
# Фаза 3: Генерация и проверка поддержки
best_answer = None
best_score = -1
for _ in range(max_iterations):
# Генерация кандидата на ответ
answer = self.generator.generate(
query, context=relevant_docs
)
# Оценка поддержки и качества
support_score = self.critic.check_support(
answer, relevant_docs
)
quality_score = self.critic.assess_quality(answer)
total_score = 0.6 * support_score + 0.4 * quality_score
if total_score > best_score:
best_score = total_score
best_answer = answer
# Ранняя остановка при достижении высокого качества
if total_score > 0.9:
break
return {
'answer': best_answer,
'confidence': best_score,
'sources': relevant_docs,
'reflections': {
'retrieved': retrieve_decision,
'relevance': len(relevant_docs),
'support': support_score
}
}
Обучение механизмов рефлексии
Self-RAG требует обучения компонента критика для принятия надежных решений. Обычно это включает:
- Обучение с учителем на датасетах, аннотированных суждениями о релевантности
- Обучение с подкреплением с наградами за точные предсказания
- Контрастивное обучение для различения подтвержденных и неподтвержденных утверждений
Токены рефлексии могут быть реализованы как:
- Специальные токены в словаре (например,
[RETRIEVE],[RELEVANT]) - Отдельные классифицирующие головы на модели
- Внешние модели-критики (ансамблевый подход)
Соображения для внедрения в производство
При развертывании Self-RAG в производственных системах:
Компромиссы задержки: Каждый шаг рефлексии добавляет 20-40% накладных расходов на инференс. Балансируйте тщательность с требованиями к времени отклика.
Пороги уверенности: Настройте пороги рефлексии в зависимости от вашего случая использования. Юридические или медицинские приложения требуют более высокой уверенности, чем общие чат-боты.
Мониторинг: Отслеживайте решения рефлексии для выявления закономерностей. Если извлечение редко требуется, вы можете извлечь выгоду из более простой архитектуры.
GraphRAG: Извлечение с усилением графов знаний
Концептуальная основа
GraphRAG трансформирует проблему извлечения из векторной схожести в обход графа. Вместо поиска семантически схожих текстовых фрагментов, GraphRAG идентифицирует релевантные подграфы связанных сущностей и отношений.
Извлечение сущностей: Идентификация именованных сущностей, концепций и их типов Картирование отношений: Извлечение отношений между сущностями (временные, причинно-следственные, иерархические) Построение графа: Создание графа знаний, где сущности являются узлами, а отношения — ребрами Извлечение подграфа: По запросу найти релевантные связанные подграфы
Конвейер построения графа
Построение графа знаний из неструктурированного текста включает несколько этапов:
class GraphRAGBuilder:
def __init__(self, entity_extractor, relation_extractor):
self.entity_extractor = entity_extractor
self.relation_extractor = relation_extractor
self.graph = NetworkGraph()
def build_graph(self, documents: List[str]):
"""Построение графа знаний из документов"""
for doc in documents:
# Извлечение сущностей
entities = self.entity_extractor.extract(doc)
# Добавление сущностей как узлов
for entity in entities:
self.graph.add_node(
entity['text'],
entity_type=entity['type'],
context=entity['surrounding_text']
)
# Извлечение отношений
relations = self.relation_extractor.extract(
doc, entities
)
# Добавление отношений как ребер
for rel in relations:
self.graph.add_edge(
rel['source'],
rel['target'],
relation_type=rel['type'],
confidence=rel['score'],
evidence=rel['text_span']
)
def enrich_graph(self):
"""Добавление производных отношений и метаданных"""
# Вычисление важности узлов (PageRank и т.д.)
self.graph.compute_centrality()
# Идентификация сообществ/кластеров
self.graph.detect_communities()
# Добавление временного упорядочивания, если доступны временные метки
self.graph.add_temporal_edges()
Обработка запросов с графами
Запросы в GraphRAG включают многошаговое рассуждение по графу знаний:
class GraphRAGRetriever:
def __init__(self, graph, embedder):
self.graph = graph
self.embedder = embedder
def retrieve_subgraph(self, query: str,
max_hops: int = 2,
max_nodes: int = 50):
"""Извлечение релевантного подграфа для запроса"""
# Идентификация начальных сущностей в запросе
query_entities = self.entity_extractor.extract(query)
# Поиск совпадающих узлов в графе
seed_nodes = []
for entity in query_entities:
matches = self.graph.find_similar_nodes(
entity['text'],
similarity_threshold=0.85
)
seed_nodes.extend(matches)
# Расширение подграфа путем обхода
subgraph = self.graph.create_subgraph()
visited = set()
for seed in seed_nodes:
self._expand_from_node(
seed,
subgraph,
visited,
current_hop=0,
max_hops=max_hops
)
# Ранжирование узлов по релевантности
ranked_nodes = self._rank_subgraph_nodes(
subgraph, query
)
# Извлечение и форматирование контекста
context = self._format_graph_context(
ranked_nodes[:max_nodes],
subgraph
)
return context
def _expand_from_node(self, node, subgraph, visited,
current_hop, max_hops):
"""Рекурсивное расширение подграфа"""
if current_hop >= max_hops or node in visited:
return
visited.add(node)
subgraph.add_node(node)
# Получение соседей
neighbors = self.graph.get_neighbors(node)
for neighbor, edge_data in neighbors:
# Добавление ребра в подграф
subgraph.add_edge(node, neighbor, edge_data)
# Рекурсивное расширение
self._expand_from_node(
neighbor,
subgraph,
visited,
current_hop + 1,
max_hops
)
def _format_graph_context(self, nodes, subgraph):
"""Преобразование подграфа в текстовый контекст"""
context_parts = []
for node in nodes:
# Добавление контекста узла
context_parts.append(f"Entity: {node.text}")
context_parts.append(f"Type: {node.entity_type}")
# Добавление информации об отношениях
edges = subgraph.get_edges(node)
for edge in edges:
context_parts.append(
f"- {edge.relation_type} -> {edge.target.text}"
)
return "\n".join(context_parts)
Реализация GraphRAG от Microsoft
Графический RAG от Microsoft использует уникальный подход, генерируя сводки сообществ:
- Построение начального графа из документов с использованием извлечения сущностей/отношений на базе LLM
- Обнаружение сообществ с использованием алгоритма Лейдена или аналогичных
- Генерация сводок для каждого сообщества с использованием LLM
- Иерархическая структура: Построение нескольких уровней абстракции сообществ
- Время запроса: Извлечение релевантных сообществ и обход к конкретным сущностям
Этот подход особенно эффективен для:
- Исследовательских запросов («Каковы основные темы в этом корпусе?»)
- Многошагового рассуждения («Как A связано с C через B?»)
- Временного анализа («Как эволюционировали отношения этой сущности?»)
Сравнительный анализ
Когда использовать каждый вариант
Используйте LongRAG, когда:
- Документы имеют сильную внутреннюю связность
- Окна контекста вашего LLM поддерживают большие входы (32K+)
- Ответы на запросы требуют понимания дальнодействующих зависимостей
- Вы работаете со структурированными документами (отчеты, статьи, книги)
Используйте Self-RAG, когда:
- Точность и доверие критически важны
- Вам нужны объяснимые решения по извлечению
- Ложные срабатывания от нерелевантного извлечения стоят дорого
- Сложность запросов сильно варьируется (некоторые требуют извлечения, другие нет)
Используйте GraphRAG, когда:
- Ваша область имеет богатые отношения между сущностями
- Запросы требуют многошагового рассуждения
- Важны временные или иерархические отношения
- Вам нужно понимать связи между сущностями
Сравнение метрик производительности
| Метрика | Стандартный RAG | LongRAG | Self-RAG | GraphRAG |
|---|---|---|---|---|
| Время индексации | 1x | 0.8x | 1.1x | 3-5x |
| Задержка запроса | 1x | 2-3x | 1.4x | 1.5-2x |
| Использование памяти | 1x | 3-4x | 1.2x | 2-3x |
| Точность (QA) | базовая | +15-25% | +20-30% | +25-40%* |
| Интерпретируемость | Низкая | Средняя | Высокая | Высокая |
*Улучшения GraphRAG сильно зависят от предметной области
Гибридные подходы
Самые мощные производственные системы часто комбинируют несколько техник:
LongRAG + GraphRAG: Используйте структуру графа для идентификации релевантных кластеров документов, затем извлекайте полные документы, а не фрагменты
Self-RAG + GraphRAG: Применяйте механизмы рефлексии к решениям обхода графа (какие пути следовать, когда остановиться)
Трехэтапный конвейер: Используйте GraphRAG для начального извлечения на основе сущностей → Self-RAG для фильтрации релевантности → LongRAG для сборки контекста
Соображения реализации
Модели встраивания
Различные варианты RAG имеют разные требования к встраиванию:
LongRAG: Требует встраиваний, которые хорошо работают как на уровне документа, так и на уровне фрагментов. Рассмотрите модели, обученные с контрастивным обучением на длинных последовательностях.
Self-RAG: Выигрывает от встраиваний, которые захватывают семантические нюансы для тонкой оценки релевантности.
GraphRAG: Требует встраиваний, осознающих сущности. Модели, дообученные на задачах связывания сущностей, работают лучше.
Выбор модели встраивания значительно влияет на производительность. При работе с локальными моделями инструменты вроде Ollama предоставляют простой способ экспериментировать с различными моделями встраивания перед переходом к производному развертыванию.
Стратегии разбивки на фрагменты: пересмотр
Традиционная разбивка на фрагменты фиксированного размера недостаточна для продвинутого RAG:
Семантическая разбивка: Разбивка на естественных границах (абзацы, разделы, смены тем) Рекурсивная разбивка: Создание иерархических фрагментов с отношениями родитель-потомок Скользящее окно: Использование перекрывающихся фрагментов для сохранения контекста на границах Осознание структуры: Уважение структуры документа (заголовки markdown, XML-теги, блоки кода)
Для реализаций на Python библиотеки вроде LangChain и LlamaIndex предоставляют встроенную поддержку этих стратегий разбивки.
Интеграция переранжирования
Переранжирование dramatically улучшает качество извлечения во всех вариантах RAG. После начального извлечения специализированная модель переранжирования переоценивает результаты на основе признаков взаимодействия запрос-документ. Это обеспечивает значительный прирост точности (10-20%) с минимальным влиянием на задержку при продуманной интеграции.
Масштабирование до производства
Конвейер индексации:
- Используйте распределенную обработку (Ray, Dask) для больших корпусов документов
- Реализуйте инкрементальную индексацию для обновлений в реальном времени
- Храните встраивания в оптимизированных векторных базах данных (Pinecone, Weaviate, Qdrant)
Оптимизация запросов:
- Кэшируйте частые запросы и их результаты
- Реализуйте маршрутизацию запросов (различные варианты RAG для разных типов запросов)
- Используйте поиск приближенных ближайших соседей для сублинейного масштабирования
Мониторинг:
- Отслеживайте оценки релевантности извлечения
- Мониторьте решения рефлексии в Self-RAG
- Измеряйте пути и глубины обхода графа
- Логируйте оценки уверенности и отзывы пользователей
Реальные применения
Поиск по технической документации
Крупный облачный провайдер внедрил GraphRAG для своей документации:
- Сущности: конечные точки API, параметры, коды ошибок, названия сервисов
- Отношения: зависимости, совместимость версий, пути миграции
- Результат: 35% сокращение обращений в службу поддержки, 45% ускорение времени решения проблем
Юридическая экспертиза (Legal Discovery)
Компания в сфере юридического технологий объединила Self-RAG и LongRAG:
- Self-RAG отсекает нерелевантные документы на ранних этапах
- LongRAG сохраняет контекст в сохраненных документах
- Юристы просматривают на 60% меньше ложных срабатываний
- Сохранение критического контекста улучшилось с 71% до 94%
Обзор научной литературы
Академический поисковик с гибридным подходом:
- GraphRAG идентифицирует сети цитирований и научные сообщества
- LongRAG извлекает полные разделы, сохраняя контекст методологии
- 40% улучшение в обнаружении релевантных статей
- Сокращение времени обзора литературы с недель до дней
Продвинутые темы
Мультимодальный RAG
Расширение этих вариантов для обработки изображений, таблиц и кода:
- Визуальное заземление: Связывание текстовых сущностей с изображениями в документах
- Понимание таблиц: Парсинг структурированных данных в формат графа
- Анализ кода: Построение графов зависимостей из кодовых баз
Адаптивный RAG
Динамический выбор стратегии RAG на основе характеристик запроса:
- Классификатор сложности запроса
- Детектор типа документа
- Оптимизатор выгоды/затрат для выбора стратегии
RAG с сохранением приватности
Реализация этих вариантов с ограничениями конфиденциальности:
- Федеративное извлечение через изолированные хранилища данных
- Дифференциальная приватность в встраиваниях
- Зашифрованный поиск по схожести
Начало работы
Быстрый старт на Python
Для тех, кто хочет реализовать эти техники, начало с прочной базы Python является обязательным. Богатая экосистема Python для машинного обучения делает его естественным выбором для разработки RAG.
Вот простая отправная точка для экспериментов:
# Установка зависимостей
# pip install sentence-transformers faiss-cpu langchain
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# Базовая настройка для экспериментов с длинными фрагментами
model = SentenceTransformer('all-MiniLM-L6-v2')
documents = [
# Ваши длинные документы здесь
]
# Создание встраиваний
embeddings = model.encode(documents)
# Построение индекса FAISS
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings.astype('float32'))
# Запрос
query = "Ваш вопрос здесь"
query_embedding = model.encode([query])
distances, indices = index.search(
query_embedding.astype('float32'), k=3
)
Выбор фреймворка
LangChain: Лучший для быстрого прототипирования, обширные интеграции LlamaIndex: Оптимизирован для индексации и извлечения документов Haystack: Готов к производству, сильные абстракции конвейеров Кастомный: Когда вам нужен полный контроль и оптимизация
Фреймворк оценки
Реализуйте строгую оценку перед развертыванием в производство:
Метрики извлечения:
- Precision@K, Recall@K, MRR (Mean Reciprocal Rank)
- NDCG (Normalized Discounted Cumulative Gain)
Метрики генерации:
- ROUGE, BLEU для текстовой схожести
- BERTScore для семантической схожести
- Человеческая оценка для оценки качества
Метрики end-to-end:
- Успешность выполнения задачи
- Оценки удовлетворенности пользователей
- Процентили задержки (p50, p95, p99)
Заключение
Ландшафт систем RAG значительно зрел за пределы базового поиска по векторной схожести. LongRAG, Self-RAG и GraphRAG каждый решает конкретные ограничения традиционных подходов:
LongRAG решает проблему фрагментации контекста, принимая расширенные окна контекста и минимальную разбивку на фрагменты. Это выбор по умолчанию, когда важна связность документа и у вас есть вычислительные ресурсы для обработки больших контекстов.
Self-RAG добавляет критическое самосознание в системы извлечения. Размышляя о своих собственных решениях, он снижает ложные срабатывания и повышает доверие — это необходимо для приложений с высокими ставками, где точность важнее скорости.
GraphRAG открывает силу структурированного представления знаний. Когда ваша область включает сложные отношения между сущностями, извлечение на основе графов может выявить связи, которые векторная схожесть полностью упускает.
Будущее RAG, вероятно, будет включать гибридные подходы, сочетающие сильные стороны этих вариантов. Производственная система может использовать GraphRAG для идентификации релевантных кластеров сущностей, Self-RAG для фильтрации и валидации извлечений, а LongRAG для сборки связного контекста для LLM.
По мере того как LLM продолжают совершенствоваться, а окна контекста расширяются, мы увидим появление еще более изощренных вариантов RAG. Ключом является понимание ваших конкретных требований к использованию — структуры документов, паттернов запросов, требований к точности и вычислительных ограничений — и выбор соответствующей техники или их комбинации.
Экосистема инструментов быстро развивается, и фреймворки вроде LangChain, LlamaIndex и Haystack предоставляют все более изощренную поддержку для этих продвинутых паттернов. В сочетании с мощными локальными runtime для LLM и моделями встраивания, никогда еще не было так легко экспериментировать и развертывать системы RAG производственного уровня.
Начните с основ, строго измеряйте производительность и развивайте свою архитектуру по мере того, как диктуют требования. Продвинутые варианты RAG, рассмотренные здесь, предоставляют дорожную карту для этой эволюции.
Полезные ссылки
- Переранжирование с моделями встраивания
- LLM и структурированный вывод: Ollama, Qwen3 & Python или Go
- Облачные провайдеры LLM
- Сравнение LLM: Qwen3:30b vs GPT-OSS:20b
- Пошаговый учебник по RAG
- Сравнение стратегий разбивки в RAG
- Сравнение векторных баз данных для RAG
Внешние ссылки
- Microsoft GraphRAG: Модульная система генерации с дополнением извлечения на основе графов
- Self-RAG: Обучение извлечению, генерации и критике через саморефлексию
- LongRAG: Улучшение генерации с дополнением извлечения с помощью LLM с долгим контекстом
- Генерация с дополнением извлечения для больших языковых моделей: Обзор
- FAISS: Библиотека для эффективного поиска по схожести
- Документация LangChain: Продвинутые техники RAG
- HuggingFace: Sentence Transformers для моделей встраивания
- Обзор RAG: Комплексный анализ генерации с дополнением извлечения