Гибридный поиск: Совмещение RAG и длинного контекста
Введение: Дилемма «Окна» и «Базы»
Коллеги, добро пожаловать в четвертый модуль. До этого момента мы рассматривали RAG (Retrieval-Augmented Generation) и длинный контекст как две конкурирующие парадигмы. Обычно дискуссия строится так: «Что лучше: использовать векторную базу данных для поиска кусочков информации или просто загрузить всю книгу в промпт?».
С выходом Gemini 3 и моделей с контекстным окном в миллионы токенов этот вопрос стал неактуальным. Ответ — и то, и другое. Мы вступаем в эру Гибридного поиска.
Традиционный RAG (Chunking + Vector Search) страдает от проблемы «фрагментации». Когда вы разбиваете сложный документ на куски по 500 токенов, вы теряете глобальный нарратив и связи между удаленными частями текста. С другой стороны, «Грубая сила» (Brute Force Long Context), когда мы пытаемся запихнуть в модель гигабайты данных, сталкивается с проблемами latency (задержки) и стоимости.
В этом уроке мы научимся строить архитектуру, которая использует RAG для грубой фильтрации, а длинный контекст Gemini — для глубокого анализа и синтеза информации. Это «золотая середина» для Enterprise-решений.
Концепция: RAG как пре-фильтр для Long Context
Давайте переосмыслим роль RAG. В классической схеме мы ищем ответ или параграф с ответом. В гибридной схеме мы используем RAG, чтобы найти область интереса.
Сравнение подходов:
- Классический RAG: Найти 5 чанков (кусков текста) по 512 токенов, наиболее похожих на запрос. Скормить модели ~2500 токенов.
Проблема: Если ответ требует понимания всей главы, модель ошибется, так как видит только вырванные из контекста фразы. - Чистый Long Context: Загрузить 100 книг (10 млн токенов). Задать вопрос.
Проблема: Дорого, долго, риск «галлюцинаций» из-за переизбытка шума. - Гибридный подход (Context RAG): Использовать векторный поиск, чтобы найти 5-10 наиболее релевантных документов целиком (не чанков!). Загрузить эти документы в контекстное окно (скажем, 200,000 токенов).
Результат: Модель имеет полный контекст необходимых материалов, но не перегружена лишней информацией из других тем.
Gemini 3 идеально подходит для этого благодаря своей способности удерживать внимание на огромных массивах данных (needle-in-a-haystack) и высокой скорости обработки кэшированного контекста.
import google.generativeai as genai
import os
# Представим, что у нас есть эмуляция векторного поиска
# В реальности здесь был бы вызов к ChromaDB, Pinecone или pgvector
class MockVectorDB:
def search(self, query, top_k=3):
# Возвращает ID документов, а не просто чанки
# Логика: RAG находит релевантные документы целиком
print(f"Searching vector DB for: {query}...")
return ["doc_id_101", "doc_id_204", "doc_id_333"]
class DocumentStore:
def get_full_content(self, doc_ids):
# Извлекаем ПОЛНЫЙ текст документов
# Это ключевое отличие от обычного RAG
docs = {
"doc_id_101": "Полный текст технической спецификации А... (20k токенов)",
"doc_id_204": "Полный текст протокола испытаний Б... (15k токенов)",
"doc_id_333": "Полный текст инцидента В... (10k токенов)"
}
return [docs[id] for id in doc_ids if id in docs]
# Инициализация Gemini 3 (предполагаем наличие API ключа)
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
model = genai.GenerativeModel('gemini-1.5-pro-latest') # или gemini-3-ultra
def hybrid_search_query(user_query):
db = MockVectorDB()
store = DocumentStore()
# Шаг 1: Грубая фильтрация через RAG
relevant_ids = db.search(user_query, top_k=3)
# Шаг 2: Загрузка полного контекста
full_docs = store.get_full_content(relevant_ids)
# Объединяем контент. Для Gemini это "легкий вес" (всего ~45k токенов)
combined_context = "\n\n---\n\n".join(full_docs)
# Шаг 3: Генерация с глубоким пониманием
prompt = f"""
Ты - аналитик. Используй предоставленные ниже документы как ЕДИНСТВЕННЫЙ источник правды.
Проанализируй их полностью, чтобы ответить на вопрос пользователя.
Обрати внимание на детали и связи между документами.
КОНТЕКСТ:
{combined_context}
ВОПРОС: {user_query}
"""
response = model.generate_content(prompt)
return response.text
# Пример вызова
# print(hybrid_search_query("Какие риски описаны в спецификации А в контексте инцидента В?"))
Паттерн: Иерархическое сжатие (Hierarchical Summarization)
Еще одна мощная техника гибридного поиска — использование иерархии. Представьте, что у вас есть огромный архив юридической документации за 10 лет.
- Уровень 1 (Метаданные и Саммари): Вы создаете краткие выжимки (summary) для каждого документа и индексируете их векторами.
- Уровень 2 (Поиск): Когда пользователь задает вопрос, вы ищете по саммари. Это быстро и дешево.
- Уровень 3 (Развертывание): Найдя релевантные саммари, система подтягивает оригинальные полные документы, к которым эти саммари относятся.
- Уровень 4 (Инференс): Полные документы отправляются в Gemini.
Зачем это нужно? Векторный поиск по полному тексту часто дает сбои (шум, смешивание контекстов). Поиск по качественным саммари гораздо точнее определяет тему документа. А Gemini уже разбирается с деталями внутри полного текста.
Роль Context Caching
В Gemini API доступна функция Context Caching. Это game-changer для гибридного поиска. Если у вас есть набор «золотых стандартов» (например, Трудовой Кодекс, Внутренний Регламент, Брендбук), которые используются в 80% запросов, вы можете:
- Загрузить их в кэш Gemini (они становятся «горячей» памятью).
- Использовать RAG только для поиска переменных данных (свежие новости, тикеты пользователей за сегодня).
- Объединять кэшированный (статичный) и найденный (динамический) контекст в одном запросе.
Это снижает стоимость токенов ввода до 90% и значительно ускоряет ответ модели.
Спроектируйте функцию `smart_context_builder`. Она должна принимать запрос пользователя и список доступных категорий документов (например, ['tech_specs', 'hr_policies', 'meeting_notes']). <br><br>Логика:<br>1. Если запрос касается технических деталей, загружать ВСЕ документы из 'tech_specs' (предполагаем, что их объем влезает в окно).<br>2. Если запрос общий, использовать симуляцию векторного поиска для выбора топ-5 документов из всех категорий.<br>3. Возвращать итоговый промпт.
Оптимизация промптов для большого контекста
Когда вы подаете в Gemini 100,000+ токенов текста, структура промпта меняется. Вот ключевые правила для гибридного режима:
- Инструкции в конце (Post-prompting): В моделях с длинным контекстом феномен Lost in the Middle (потеря середины) минимизирован, но эффект Recency Bias (внимание к последнему) сохраняется. Всегда дублируйте сам вопрос и инструкции ПОСЛЕ блока с контекстом.
- Явная разметка (Delimiters): Используйте XML-теги. Gemini отлично понимает структуру вроде:
<documents> ... </documents><user_query> ... </user_query>. Это помогает модели отделить данные от инструкций. - Chain-of-Thought (CoT): При работе с большим объемом данных требуйте от модели сначала «найти релевантные цитаты», а потом «сформулировать ответ». Это заставляет модель физически пройтись по загруженному контексту.
Пример эффективной структуры:
Вы - эксперт по финансовому анализу.
[Здесь 50 страниц отчетов, найденных через RAG]
Твоя задача: Сравнить показатели Q3 и Q4.
Инструкция:
1. Выпиши все цифры прибыли за Q3 из документов.
2. Выпиши цифры за Q4.
3. Сделай таблицу сравнения.
Вопрос пользователя: Как изменилась прибыль во второй половине года?
В каком случае использование Гибридного подхода (RAG фильтр + Long Context) НАИБОЛЕЕ оправдано по сравнению с обычным RAG (Retrieval of Chunks)?