Расширенный RAG: LongRAG, Self-RAG и GraphRAG объяснены

LongRAG, Self-RAG, GraphRAG — Технологии следующего поколения

Содержимое страницы

Retrieval-Augmented Generation (RAG) эволюционировал далеко за пределы простого поиска по вектору сходства. LongRAG, Self-RAG и GraphRAG представляют собой передовой край этих возможностей.

Современные системы RAG должны обрабатывать огромные документы, понимать сложные взаимосвязи между сущностями и многое другое.

a-pirate-captain Это приятное изображение было сгенерировано моделью AI Flux 1 dev.

Эволюция за пределами базового RAG

Традиционные системы RAG следуют простому шаблону: разбивают документы на части, преобразуют их в векторы, извлекают похожие части с помощью косинусного сходства и передают их в LLM. Хотя этот подход эффективен для многих сценариев, он испытывает трудности с тремя критическими ситуациями:

  1. Долгосрочные зависимости: Важный контекст может охватывать тысячи токенов в нескольких частях
  2. Доверие к извлечению: Система не может оценить, действительно ли извлеченный контент актуален
  3. Сложность взаимосвязей: Сходство векторов не может захватить сложные связи между сущностями

Продвинутые варианты 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 требует обучения компонента критика для принятия надежных решений. Это обычно включает:

  1. Тонкую настройку с использованием супервизорского обучения на наборах данных, аннотированных с оценками релевантности
  2. Обучение с подкреплением с вознаграждениями за точные предсказания
  3. Контрастное обучение для различения поддерживаемых и не поддерживаемых утверждений

Рефлексивные токены могут быть реализованы как:

  • Специальные токены в словаре (например, [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"Сущность: {node.text}")
            context_parts.append(f"Тип: {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

Реализация GraphRAG от Microsoft использует уникальный подход с генерацией сводок сообществ:

  1. Построение начального графа из документов с использованием извлечения сущностей и отношений на основе LLM
  2. Обнаружение сообществ с использованием алгоритма Лейдена или аналогичных
  3. Генерация сводок для каждого сообщества с использованием LLM
  4. Иерархическая структура: Построение нескольких уровней абстракций сообществ
  5. Время запроса: Поиск релевантных сообществ и обход до конкретных сущностей

Этот подход особенно эффективен для:

  • Исследовательских запросов (“Какие основные темы в этом корпусе?”)
  • Многоходового рассуждения (“Как 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%

Юридическое обнаружение

Компания в области юридических технологий соединила 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: Готовый к производству, сильные абстракции конвейеров Кастомный: Когда вам нужна полная контроль и оптимизация

Фреймворк оценки

Реализуйте тщательную оценку перед производственным развертыванием:

Метрики поиска:

  • Точность@K, Полнота@K, MRR (Средний взаимный ранг)
  • NDCG (Нормализованная дисконтированная кумулятивная прибыль)

Метрики генерации:

  • 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, предоставляющими все более сложную поддержку этих передовых паттернов. В сочетании с мощными локальными средами выполнения LLM и моделями эмбеддингов, никогда еще не было так легко экспериментировать и развертывать системы RAG производственного уровня.

Начните с основ, тщательно измеряйте производительность и развивайте свою архитектуру по мере необходимости. Передовые варианты RAG, рассмотренные здесь, предоставляют дорожную карту для этого развития.

Полезные ссылки

Внешние ссылки