Продвинутый RAG: объяснение LongRAG, Self-RAG и GraphRAG
LongRAG, Self-RAG, GraphRAG — передовые техники
Генерация с усилением поиска (RAG) давно вышла за рамки простого поиска векторного сходства. LongRAG, Self-RAG и GraphRAG представляют передовой край этих возможностей.
Современные системы RAG должны обрабатывать огромные документы, понимать сложные связи между сущностями и многое другое.
Это приятное изображение сгенерировано моделью ИИ Flux 1 dev.
Эволюция за пределами базового RAG
Традиционные системы RAG следуют простому шаблону: разбивают документы на блоки, превращают их в векторы, извлекают похожие блоки через косинуснуюSimilarity и подают их в LLM. Хотя этот подход эффективен во многих сценариях, он испытывает трудности с тремя критическими ситуациями:
Понимание различий между поиском, глубоким поиском (deepsearch) и глубоким исследованием (deep research) помогает прояснить, почему для сложных задач извлечения информации необходимы продвинутые варианты RAG. Для более глубокого погружения в эти концепции см. Поиск против Deepsearch против Deep Research.
- Дальние зависимости: Важный контекст может охватывать тысячи токенов в нескольких блоках
- Уверенность извлечения: Система не имеет способа оценить, действительно ли извлеченное содержимое релевантно
- Сложность связей: Векторное сходство не может отразить сложные соединения между сущностями
Продвинутые варианты 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]:
"""Create overlapping large chunks"""
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):
"""Index document with hierarchical embedding"""
# Embed entire document
doc_embedding = self.model.embed(doc)
# Create large chunks with overlap
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]:
"""Retrieve relevant long-form content"""
query_embedding = self.model.embed(query)
# Score at document level first
doc_scores = [
np.dot(query_embedding, doc['doc_embedding'])
for doc in self.doc_embeddings
]
# Get top documents
top_doc_indices = np.argsort(doc_scores)[-top_k:][::-1]
results = []
for idx in top_doc_indices:
doc_data = self.doc_embeddings[idx]
# For each document, find best chunks
chunk_scores = [
np.dot(query_embedding, emb)
for emb in doc_data['chunk_embeddings']
]
best_chunk_idx = np.argmax(chunk_scores)
# Return extended context around best chunk
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]:
"""Get extended context around relevant chunk"""
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-hosted Deep Research — см. Системы Self-Hosted Deep Research: Сравнение 12 инструментов для того, как инструменты вроде Local Deep Research и lukeswade/deep-research оценивают собственные пробелы в доказательствах и решают, что искать дальше:
Токен извлечения: Определяет, необходимо ли извлечение для данного запроса Токен релевантности: Оценивает, действительно ли извлеченные документы релевантны Токен поддержки: Проверяет, поддерживается ли сгенерированный ответ извлеченным содержимым Токен критики: Оценивает общее качество сгенерированного ответа
Компоненты архитектуры
Архитектура 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):
"""Generate answer with self-reflection"""
# Phase 1: Decide if retrieval needed
retrieve_decision = self.critic.should_retrieve(query)
if not retrieve_decision:
# Direct generation without retrieval
return self.generator.generate(query)
# Phase 2: Retrieve and evaluate relevance
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: # Threshold
relevant_docs.append(doc)
if not relevant_docs:
# Fallback to generation without retrieval
return self.generator.generate(query)
# Phase 3: Generate and verify support
best_answer = None
best_score = -1
for _ in range(max_iterations):
# Generate candidate answer
answer = self.generator.generate(
query, context=relevant_docs
)
# Evaluate support and quality
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
# Early stopping if high quality achieved
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]):
"""Build knowledge graph from documents"""
for doc in documents:
# Extract entities
entities = self.entity_extractor.extract(doc)
# Add entities as nodes
for entity in entities:
self.graph.add_node(
entity['text'],
entity_type=entity['type'],
context=entity['surrounding_text']
)
# Extract relationships
relations = self.relation_extractor.extract(
doc, entities
)
# Add relationships as edges
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):
"""Add derived relationships and metadata"""
# Compute node importance (PageRank, etc.)
self.graph.compute_centrality()
# Identify communities/clusters
self.graph.detect_communities()
# Add temporal ordering if timestamps available
self.graph.add_temporal_edges()
Обработка запросов с графами
Запросы GraphRAG включают многошаговое рассуждение (multi-hop reasoning) через граф знаний:
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):
"""Retrieve relevant subgraph for query"""
# Identify seed entities in query
query_entities = self.entity_extractor.extract(query)
# Find matching nodes in graph
seed_nodes = []
for entity in query_entities:
matches = self.graph.find_similar_nodes(
entity['text'],
similarity_threshold=0.85
)
seed_nodes.extend(matches)
# Expand subgraph via traversal
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
)
# Rank nodes by relevance
ranked_nodes = self._rank_subgraph_nodes(
subgraph, query
)
# Extract and format context
context = self._format_graph_context(
ranked_nodes[:max_nodes],
subgraph
)
return context
def _expand_from_node(self, node, subgraph, visited,
current_hop, max_hops):
"""Recursively expand subgraph"""
if current_hop >= max_hops or node in visited:
return
visited.add(node)
subgraph.add_node(node)
# Get neighbors
neighbors = self.graph.get_neighbors(node)
for neighbor, edge_data in neighbors:
# Add edge to subgraph
subgraph.add_edge(node, neighbor, edge_data)
# Recursively expand
self._expand_from_node(
neighbor,
subgraph,
visited,
current_hop + 1,
max_hops
)
def _format_graph_context(self, nodes, subgraph):
"""Convert subgraph to textual context"""
context_parts = []
for node in nodes:
# Add node context
context_parts.append(f"Entity: {node.text}")
context_parts.append(f"Type: {node.entity_type}")
# Add relationship information
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
GraphRAG от Microsoft использует уникальный подход, генерируя сводки сообществ:
- Построение начального графа из документов с использованием LLM-извлечения сущностей/отношений
- Обнаружение сообществ с использованием алгоритма Leiden или аналогичного
- Генерация сводок для каждого сообщества с использованием 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 предоставляют встроенную поддержку этих стратегий разбиения на блоки.
Интеграция повторного ранжирования
Повторное ранжирование значительно улучшает качество извлечения во всех вариантах RAG. После начального извлечения специализированная модель повторного ранжирования пересчитывает баллы результатов на основе признаков взаимодействия запрос-документ. Это обеспечивает значительный прирост точности (10-20%) с минимальным влиянием на латентность при продуманной интеграции.
Масштабирование до продакшена
Конвейер индексирования:
- Используйте распределенную обработку (Ray, Dask) для больших корпусов документов
- Реализуйте инкрементальное индексирование для обновлений в реальном времени
- Храните встраивания в оптимизированных векторных базах данных (Pinecone, Weaviate, Qdrant)
Оптимизация запросов:
- Кэшируйте частые запросы и их результаты
- Реализуйте маршрутизацию запросов (разные варианты RAG для разных типов запросов)
- Используйте приближенный поиск ближайших соседей для сублинейного масштабирования
Мониторинг:
- Отслеживайте баллы релевантности извлечения
- Мониторьте решения о рефлексии в Self-RAG
- Измеряйте пути и глубину обхода графа
- Логгируйте баллы уверенности и обратную связь от пользователей
Приложения в реальном мире
Поиск по технической документации
Крупный облачный провайдер реализовал GraphRAG для своей документации:
- Сущности: точки входа API, параметры, коды ошибок, имена сервисов
- Отношения: Зависимости, совместимость версий, пути миграции
- Результат: Снижение числа обращений в поддержку на 35%, ускорение времени разрешения на 45%
Юридическое обнаружение (Discovery)
Юридическая технологическая компания объединила Self-RAG с LongRAG:
- Self-RAG фильтрует нерелевантные документы на ранней стадии
- LongRAG сохраняет контекст в оставленных документах
- Юристы проверяют на 60% меньше ложных положительных результатов
- Сохранение критического контекста улучшилось с 71% до 94%
Обзор исследовательской литературы
Академический поисковый движок, использующий гибридный подход:
- GraphRAG идентифицирует сети цитирования и исследовательские сообщества
- LongRAG извлекает полные разделы, сохраняя контекст методологии
- Улучшение обнаружения релевантных статей на 40%
- Сокращение времени обзора литературы с недель до дней
Продвинутые темы
Мультимодальный RAG
Расширение этих вариантов для обработки изображений, таблиц и кода:
- Визуальная привязка: Связывать текстовые сущности с изображениями в документах
- Понимание таблиц: Разбирать структурированные данные в графический формат
- Анализ кода: Строить графы зависимостей из кодовых баз
Адаптивный RAG
Динамический выбор стратегии RAG на основе характеристик запроса:
- Классификатор сложности запроса
- Детектор типа документа
- Оптимизатор выгоды для выбора стратегии
RAG с сохранением конфиденциальности
Реализация этих вариантов с ограничениями конфиденциальности:
- Федеративное извлечение между изолированными данными
- Дифференциальная конфиденциальность в встраиваниях
- Зашифрованный поиск сходства
Начало работы
Быстрый старт с Python
Для тех, кто хочет реализовать эти техники, начало с солидной основы на Python необходимо. Богатая экосистема Python для машинного обучения делает его естественным выбором для разработки RAG.
Вот простая отправная точка для экспериментов:
# Install dependencies
# pip install sentence-transformers faiss-cpu langchain
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# Basic setup for experimenting with long chunks
model = SentenceTransformer('all-MiniLM-L6-v2')
documents = [
# Your long-form documents here
]
# Create embeddings
embeddings = model.encode(documents)
# Build FAISS index
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings.astype('float32'))
# Query
query = "Your question here"
query_embedding = model.encode([query])
distances, indices = index.search(
query_embedding.astype('float32'), k=3
)
Выбор фреймворка
LangChain: Лучший для быстрого прототипирования, обширные интеграции LlamaIndex: Оптимизирован для индексирования и извлечения документов Haystack: Готов к продакшену, сильные абстракции конвейеров Кастомный: Когда вам нужен полный контроль и оптимизация
Фреймворк оценки
Реализуйте строгую оценку перед производственным развертыванием:
Метрики извлечения:
- Precision@K, Recall@K, MRR (Средний реципрокальный ранг)
- NDCG (Нормализованный дисконтированный кумулятивный выигрыш)
Метрики генерации:
- ROUGE, BLEU для текстового сходства
- BERTScore для семантического сходства
- Человеческая оценка для оценки качества
Сквозные метрики:
- Уровень успешности задачи
- Баллы удовлетворенности пользователей
- Процентили латентности (p50, p95, p99)
Заключение
Ландшафт систем RAG значительно созрел за пределами базового векторного поиска сходства. LongRAG, Self-RAG и GraphRAG каждый решают конкретные ограничения традиционных подходов:
LongRAG решает проблему фрагментации контекста, принимая расширенные окна контекста и минимальный чанкинг. Это выбор для случаев, когда связность документа важна и у вас есть вычислительные ресурсы для обработки больших контекстов.
Self-RAG добавляет критически важную самоосознанность системам извлечения. Рефлексируя над собственными решениями, он уменьшает ложные положительные результаты и улучшает надежность — что обязательно для высокоответственных приложений, где точность важнее скорости.
GraphRAG открывает мощь структурированного представления знаний. Когда ваша область включает сложные отношения между сущностями, графовое извлечение может выявить связи, которые векторное сходство полностью упускает. Более глубокий вопрос о том, как структурировать знания до того, как они будут извлечены, — и почему представление так же важно, как и извлечение, — исследуется в Извлечение против Представления в Системах Знаний.
Будущее RAG, вероятно, будет включать гибридные подходы, которые объединяют преимущества этих вариантов. Производственная система может использовать GraphRAG для идентификации релевантных кластеров сущностей, Self-RAG для фильтрации и валидации извлечений и LongRAG для сборки связного контекста для LLM.
По мере того, как LLM продолжают улучшаться, а окна контекста расширяются, мы увидим появление еще более изощренных вариантов RAG. Ключом является понимание ваших конкретных требований сценария использования — структура документов, паттерны запросов, требования к точности и вычислительные ограничения — и выбор соответствующей техники или комбинации.
Экосистема инструментов быстро созревает, при этом фреймворки вроде LangChain, LlamaIndex и Haystack предоставляют все более изощренную поддержку для этих продвинутых паттернов. В сочетании с мощными локальными рантаймами LLM и моделями встраивания, никогда ранее не было так просто экспериментировать и разворачивать RAG-системы производственного уровня.
Начните с основ, строго измеряйте производительность и развивайте вашу архитектуру по мере того, как это диктуют требования. Продвинутые варианты RAG, рассмотренные здесь, предоставляют дорожную карту для этой эволюции.
Полезные ссылки
- Повторное ранжирование с моделями встраивания
- LLM и структурированный вывод: Ollama, Qwen3 и Python или Go
- Облачные провайдеры LLM
- Сравнение LLM: Qwen3:30b против GPT-OSS:20b
- Пошаговый учебник по RAG
- Сравнение чанкинга в RAG
- Сравнение векторных баз данных для RAG
Внешние ссылки
- Microsoft GraphRAG: Модульная система генерации с усилением поиска на основе графов
- Self-RAG: Обучение извлечению, генерации и критике через саморефлексию
- LongRAG: Усиление генерации с усилением поиска с помощью LLM с длинным контекстом
- Генерация с усилением поиска для больших языковых моделей: Обзор
- FAISS: Библиотека для эффективного поиска сходства
- Документация LangChain: Продвинутые техники RAG
- HuggingFace: Sentence Transformers для моделей встраивания
- Обзор RAG: Комплексный анализ генерации с усилением поиска