RAG на практике: уроки Kaggle соревнования Data-Feeling-School-RAG-Challenge | AiManual
AiManual Logo Ai / Manual.
11 Янв 2026 Гайд

Как создать качественный RAG: уроки из Kaggle-соревнования Data-Feeling-School-RAG-Challenge

Разбор реального Kaggle-соревнования по RAG: детерминированность ответов, косинусное сходство эмбеддингов, оценка качества и подводные камни.

Зачем еще одно Kaggle-соревнование по RAG?

Потому что большинство туториалов врут. Они показывают идеальный мир, где эмбеддинги всегда находят нужный контекст, а LLM послушно выдает точные ответы. В реальности все иначе. Data-Feeling-School-RAG-Challenge на Kaggle - это как холодный душ после горячей ванны иллюзий.

Соревнование началось в конце 2024 и длилось месяц. Задача простая: создать RAG-систему по документации Python, которая отвечает на вопросы пользователей. Просто? Ха. Тут тебе и детерминированность ответов, и метрика косинусного сходства, и вся кухня промышленного RAG.

Главный урок: если твой RAG работает на игрушечных данных - это не значит, что он сработает на реальных. Разница как между учебной стрельбой по мишеням и настоящим боем.

Что ломается первым? Косинусное сходство

Вот типичная ошибка новичков:

# Как НЕ надо делать
from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('all-MiniLM-L6-v2')
query_embedding = model.encode("Как работает декоратор?")
doc_embedding = model.encode("Декораторы в Python")

similarity = np.dot(query_embedding, doc_embedding) / (np.linalg.norm(query_embedding) * np.linalg.norm(doc_embedding))
print(f"Сходство: {similarity:.4f}")

Кажется логичным? В соревновании такой подход давал 0.6-0.7 точности. Потому что косинусное сходство - не панацея. Оно хорошо работает для семантически близких фраз, но ужасно для синонимов или перефразировок.

💡
Победители соревнования использовали гибридный поиск: косинусное сходство + BM25. Почему? Потому что BM25 ловит точные совпадения, а эмбеддинги - семантику. Вместе они закрывают больше кейсов.

1 Выбери правильную модель эмбеддингов

all-MiniLM-L6-v2 - это как велосипед для поездки на работу. Работает, но медленно и неэффективно. В соревновании лучшие результаты показали:

  • BAAI/bge-large-en-v1.5 - для английских текстов
  • intfloat/multilingual-e5-large - если нужна поддержка нескольких языков
  • sentence-transformers/all-mpnet-base-v2 - баланс скорости и качества

Но вот что интересно: разница между лучшей и средней моделью в точности поиска достигала 15-20%. Это не проценты, это пропасть.

2 Детерминированность ответов - не миф

Вот что бесит больше всего: ты задаешь один и тот же вопрос три раза, получаешь три разных ответа. В production это катастрофа. В соревновании за это снимали баллы.

Решение? Температура = 0. Звучит просто, но есть нюанс:

# Правильная настройка для детерминированности
from transformers import pipeline

pipe = pipeline(
    "text-generation",
    model="meta-llama/Llama-2-7b-chat-hf",
    temperature=0.0,  # Ключевой параметр
    top_p=1.0,       # Не использовать вместе с temperature
    do_sample=False, # Обязательно False
    max_new_tokens=512
)

Но даже с temperature=0 некоторые модели продолжают "творить". Почему? Потому что они обучены на разнообразных данных и иногда предпочитают креативность точности. Здесь помогает правильный промптинг и ограничение контекста.

Метрики качества: что измеряем и зачем

Метрика Что измеряет Проблема
Косинусное сходство Семантическую близость Игнорирует точные совпадения
Recall@k Нашел ли релевантные документы Не оценивает качество ответа
BLEU/ROUGE Схожесть с эталонным ответом Механическая оценка, плохо для смысла

В соревновании использовали кастомную метрику: точность ответов + стабильность + скорость. И вот открытие: команды, которые фокусировались только на косинусном сходстве, проигрывали тем, кто думал о системе в целом.

3 Оптимизация чанков - не для слабонервных

Размер чанка - это как размер порции. Слишком маленький - не наешься (не хватит контекста). Слишком большой - переешь (шум забивает сигнал). В документации Python оптимальным оказался размер 512-1024 токена с перекрытием 10-15%.

# Пример разбивки с перекрытием
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64,  # 12.5% перекрытия
    separators=["\n\n", "\n", ".", "!", "?", ",", " ", ""]
)

chunks = text_splitter.split_text(document_text)
print(f"Получилось {len(chunks)} чанков")

Но вот секрет: победители не использовали стандартные сплиттеры. Они анализировали структуру документации Python (заголовки, примеры кода, определения) и разбивали по логическим блокам. Это давало +7% к точности.

Промптинг - где рождаются или умирают ответы

Самый простой промпт:

prompt = """Используй следующий контекст для ответа на вопрос.

Контекст: {context}

Вопрос: {question}

Ответ:"""

Работает? Да. Хорошо работает? Нет. Потому что LLM нужно больше указаний:

  1. Если ответа нет в контексте - скажи "Не знаю"
  2. Не придумывай информацию
  3. Используй только факты из контекста
  4. Будь кратким, но точным

Но даже это не гарантия. Некоторые модели (особенно маленькие) игнорируют инструкции. Решение? Использовать техники вроде PMR для контроля вероятностей.

Лучший промпт в соревновании содержал 5 ключевых элементов: роль системы, формат ответа, ограничения, примеры и fallback-стратегию.

Векторные базы: не все хранилища одинаковы

Популярный выбор - Chroma или FAISS. Быстро, просто, работает из коробки. Но в соревновании лучшие результаты показывали команды с Pinecone или Weaviate. Почему? Потому что они предлагают:

  • Гибридный поиск из коробки
  • Метаданные для фильтрации
  • Автоматическое масштабирование
  • Кэширование запросов

Но есть нюанс: эти решения платные. Для локального развертывания лучше подходит Qdrant или локальный Chroma с оптимизациями.

4 Рерайтинг и переранжирование

Нашел 10 релевантных чанков - отлично. Но какие из них действительно нужны LLM? Вот где включается рерайтинг (re-ranking).

Простейший подход: взять первые 3 чанка по косинусному сходству. Продвинутый: использовать модель для переранжирования, например, BGE-reranker-large. Разница в точности: до 12%.

# Пример с переранжированием
from sentence_transformers import CrossEncoder

reranker = CrossEncoder('BAAI/bge-reranker-large')
pairs = [[query, chunk] for chunk in candidate_chunks]
scores = reranker.predict(pairs)

# Сортируем по убыванию score
ranked_indices = np.argsort(scores)[::-1]
best_chunks = [candidate_chunks[i] for i in ranked_indices[:3]]

Ошибки, которые делают все (и как их избежать)

1. Игнорирование стоп-слов: В запросе "Как работает функция print?" слово "как" и "функция" могут снижать качество поиска. Решение - предобработка запросов.

2. Одинаковые эмбеддинги для вопросов и документов: Вопрос "Что такое декоратор?" и документ "Декораторы - это функции..." должны кодироваться по-разному. Используй разные модели или fine-tuning.

3. Слепая вера в embedding models: Модели эмбеддингов тренируются на общих данных. Для специфичной документации (медицинской, юридической) нужен fine-tuning или доменные модели.

4. Отсутствие fallback-механизмов: Когда RAG не находит ответ - он должен это признать, а не генерировать ерунду. Простая проверка: если максимальное косинусное сходство < 0.7 - возвращаем "Не знаю".

Что дальше? RAG не заканчивается на поиске

Победители соревнования думали на шаг вперед. Вместо простого RAG они строили Agentic RAG системы с цепочками рассуждений.

Вот их стек:

  • Мультимодальный поиск (текст + код + схемы)
  • Автоматическая валидация ответов
  • Кэширование частых запросов
  • Адаптивный размер контекста

Самый интересный тренд: визуализация векторных пространств для отладки. Когда видишь, как запросы и документы распределяются в 3D, понимаешь ошибки поиска на интуитивном уровне.

Главный вывод соревнования: идеального RAG не существует. Есть RAG, который достаточно хорош для конкретной задачи. И его качество измеряется не метриками, а удовлетворенностью пользователей.

Что делать сегодня? Начни с простого: возьми BGE модель, добавь гибридный поиск, настрой temperature=0 и промпт с fallback. Это даст 80% результата. Остальные 20% - это месяцы тонкой настройки, о которой не пишут в туториалах.

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