English translation is not available yet. Showing Russian content.

RAG с semantic chunking (кластеризация эмбеддингов предложений)

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: RAG с semantic chunking (кластеризация эмбеддингов предложений)

1. Цель задачи

Реализовать метод семантического разбиения (semantic chunking) текста на основе кластеризации эмбеддингов предложений. Встроить полученные чанки в RAG-конвейер и сравнить качество retrieval с наивным chunking по фиксированной длине. Основной фокус — обеспечить смысловую целостность чанков (каждый чанк — логически завершённый фрагмент).

Ключевой результат Работающий семантический чанкер, интегрированный в RAG, с метриками retrieval (hit rate, MRR, recall@k) не ниже, чем у baseline фиксированной длины, и качественной оценкой целостности через человеческую валидацию.

2. Исходные данные

Что нужноОткуда взять
Корпус текстов (10–20 документов, 500–2000 слов каждый)Любые открытые статьи на русском/английском (Wikipedia, Habr, научные публикации)
Baseline chunking (фиксированная длина 256 токенов, overlap 25)Реализовать самостоятельно с помощью langchain.text_splitter.RecursiveCharacterTextSplitter
Набор вопросов для тестирования retrieval (20–30 шт.)Составить вручную по содержанию корпуса
Векторное хранилищеChromaDB / FAISS (in-memory)
Embedding модельintfloat/multilingual-e5-small или all-MiniLM-L6-v2

Если нет реального инструмента — симулируем:

  1. Взять любой текстовый файл (например, docs.txt) и разбить на предложения через nltk.sent_tokenize или spacy.
  2. Для кластеризации использовать scikit-learn без GPU — все эксперименты проводить на CPU с небольшим корпусом.
  3. Если нет готового RAG-пайплайна — собрать минимальный с помощью LangChain и ChromaDB (установка через pip).

3. Технологический стек

КомпонентИнструментыНазначение
Язык программированияPython 3.10+Разработка
Обработка текстаspacy / nltk, sentence-transformersТокенизация, эмбеддинги предложений
Кластеризацияscikit-learn (KMeans, DBSCAN)Группировка предложений по смыслу
Chunking (baseline)LangChain RecursiveCharacterTextSplitterБазовое разбиение
Векторная БДChromaDB / FAISSХранение и поиск чанков
RAG orchestrationLangChain (или DIY)Построение цепочки retrieval
Оценка retrievalRAGAS (или ручной расчёт)Метрики hit rate, MRR, recall@k
Визуализацияmatplotlib, seabornГрафики кластеризации и распределения чанков

4. Этапы выполнения

Этап 1: Подготовка данных и baseline chunking (1 час)

Действия

  1. Загрузка корпуса

    • Прочитать 10–15 текстов из папки docs/.
    • Для каждого документа сохранить исходный текст в список raw_docs.
  2. Разбиение на предложения

    • Установить spacy и загрузить модель: python -m spacy download en_core_web_sm.
    • Пройти по всем документам, извлечь предложения ([sent.text for sent in nlp(doc).sents]).
    • Сохранить список предложений c меткой документа: [{"doc_id": i, "text": sent}].
  3. Baseline chunking

    • Использовать RecursiveCharacterTextSplitter(chunk_size=256, chunk_overlap=50).
    • Разбить каждый документ, сохранить чанки в список baseline_chunks.
    • Векторизовать baseline чанки эмбеддинговой моделью и загрузить в ChromaDB (коллекция baseline).

Ожидаемый результат этапа

  • Корпус предложений (sentences.json).
  • Заполненная векторная БД с baseline чанками.
  • Скрипт baseline_chunking.py.

Этап 2: Семантический chunking через кластеризацию (2–3 часа)

Действия

  1. Получить эмбеддинги предложений

    • Загрузить модель SentenceTransformer('all-MiniLM-L6-v2').
    • Для всех предложений рассчитать эмбеддинги: embeddings = model.encode(sentences).
    • Нормализовать эмбеддинги (L2) для косинусной близости.
  2. Кластеризация предложений

    • Вариант A (KMeans):
      • Определить оптимальное число кластеров через silhouette_score в диапазоне [2, min(20, N_sentences/2)].
      • Зафиксировать лучшее k.
    • Вариант B (DBSCAN):
      • Подобрать eps (0.3–0.6) методом перебора на малом корпусе.
      • Использовать metric='cosine'.
    • Выбрать один вариант (рекомендуется DBSCAN, т.к. не требует фиксации числа кластеров).
  3. Формирование чанков из кластеров

    • Для каждого кластера собрать предложения в порядке их появления в исходном документе.
    • Объединить в один чанк (конкатенация с пробелом).
    • Если кластер слишком мал (<3 предложений) — присоединить к ближайшему кластеру по среднему эмбеддингу.
    • Если кластер слишком велик (>15 предложений) — разбить пополам, но сохранить семантическую целостность (по границе соседних предложений с минимальным расстоянием между блоками).
  4. Загрузка semantic чанков в векторную БД

    • Создать коллекцию semantic_chunks.
    • Векторизовать каждый чанк и сохранить метаданные (doc_id, начало/конец).

Ожидаемый результат этапа

  • Ноутбук semantic_chunking.ipynb с визуализацией кластеров (2D t-SNE).
  • Скрипт semantic_chunker.py.
  • ChromaDB с коллекцией semantic_chunks.

Этап 3: Интеграция с RAG-пайплайном (1–2 часа)

Действия

  1. Построить RAG с двумя источниками

  2. Написать функцию query_evaluation

    • Вход: список вопросов, имя коллекции.
    • Выход: словарь с retrieved документами, скорами.
  3. Сгенерировать ответы (опционально)

    • Подключить простую LLM (локально через Ollama или OpenAI API) для генерации ответа на основе retrieved чанков.
    • Использовать промпт:
      Ответь на вопрос на основе следующих фрагментов. Если информации недостаточно, скажи "не знаю".  
      Фрагменты: {context}
      Вопрос: {question}
      

Ожидаемый результат этапа

  • Функция run_retrieval(questions, collection_name).
  • CSV-файл retrieval_results.csv с полями: question, collection, top3_chunks, scores.

Этап 4: Оценка качества retrieval (1–2 часа)

Действия

  1. Собрать ground truth

    • Для каждого вопроса вручную указать, какой документ (и приблизительно какие предложения) содержат ответ.
    • Например, {"question": "...", "relevant_docs": [doc_id], "relevant_chunks": [chunk_ids]}.
  2. Рассчитать метрики

    • hit_rate@3: бинарная метрика — попал ли хотя бы один релевантный чанк в top-3.
    • MRR@3: обратный ранг первого релевантного результата.
    • recall@3: доля релевантных чанков среди retrieved.
    • Реализовать вручную или через ragas.metrics.
  3. Сравнение с baseline

    • Запустить run_retrieval для обеих коллекций.
    • Построить таблицу:
МетрикаBaseline (fixed)Semantic (clustering)Delta
hit_rate@30.750.80+0.05
MRR@30.650.70+0.05
recall@30.500.55+0.05
  1. Качественная оценка семантической целостности
    • Взять 10 случайных чанков из semantic и baseline.
    • Попросить двух коллег оценить каждый чанк по шкале 1–5: насколько он является логически завершённым фрагментом.
    • Посчитать средний балл и дисперсию.

Ожидаемый результат этапа

  • metrics_comparison.csv.
  • График распределения баллов целостности.

Этап 5: Итоговый отчёт и рефакторинг (1 час)

Действия

  1. Описать архитектуру

    • Схема процесса: документ → предложения → эмбеддинги → кластеризация → чанки → retrieval.
    • Обосновать выбор алгоритма кластеризации и параметров.
  2. Собрать выводы

    • При каких условиях semantic chunking превосходит baseline? (длинные документы, тематическая смена).
    • Какие недостатки? (вычислительная стоимость, чувствительность к шуму).
  3. Подготовить презентацию

    • 5–7 слайдов: постановка, методы, результаты, демонстрация.

Ожидаемый результат этапа

  • Файл REPORT.md.
  • Презентация pres.pdf (опционально).
  • Чистый репозиторий с кодом, требованиями и инструкцией по запуску.

5. Критерии приемки (Definition of Done)

  • Реализован скрипт semantic_chunker.py, который принимает текст и возвращает список чанков.
  • Кластеризация выполняется без фиксации числа кластеров (DBSCAN) или с автоматическим подбором K.
  • Есть функция сравнения с baseline (фиксированная длина).
  • Получены метрики hit_rate@3, MRR@3, recall@3 для обеих стратегий.
  • Результаты сравнения представлены в виде таблицы и графика.
  • Проведена качественная оценка целостности чанков (минимум 2 рецензента).
  • Код оформлен в виде модульной структуры: src/, data/, notebooks/.
  • Написаны requirements.txt или pyproject.toml с зависимостями.
  • Векторная БД воспроизводится с нуля по инструкции.
  • В коде есть docstring и комментарии к ключевым шагам.

6. Ожидаемый результат

Основной артефакт Репозиторий с реализацией семантического чанкера и сравнением retrieval качества.

Содержание

  • src/semantic_chunker.py — класс SemanticChunker с методами fit, transform.
  • src/baseline_chunker.pybaseline реализация.
  • src/retrieval_eval.py — расчёт метрик.
  • data/ — корпус и ground truth.
  • notebooks/exploration.ipynb — визуализация кластеризации.
  • REPORT.md — отчёт с выводами.

Дополнительные результаты

  • Рабочий RAG-пайплайн, готовый к использованию с новой информацией.
  • Документация по запуску.

7. Возможные сложности и их решение

СложностьРешение
Неоптимальное число кластеров (KMeans)Использовать DBSCAN с автоматическим определением; для KMeans — silhouette score.
Кластер содержит предложения из разных документовПри формировании чанка группировать предложения по doc_id, не смешивать.
Очень маленький чанк (1–2 предложения)Объединять с соседним кластером по минимальному расстоянию между центроидами.
Высокая вычислительная стоимость на больших корпусахОграничить корпус 10 документами; использовать batch encoding.
Неоднозначность ground truth для метрикИспользовать несколько аннотаторов и majority voting.
Сложность настройки DBSCAN (eps)Нормализовать эмбеддинги и подбирать eps через поиск по сетке на малом корпусе.

8. Бюджет времени (оценка)

ЭтапВремя
1. Подготовка данных и baseline1 час
2. Семантический chunking (кластеризация)2.5 часа
3. Интеграция с RAG1.5 часа
4. Оценка качества2 часа
5. Итоговый отчёт и рефакторинг1 час
Итого8 часов

Примечание Для первого раза рекомендуется заложить +2–3 часа на отладку и настройку параметров кластеризации.

9. Связанные вопросы из базы знаний

ВопросТема
12Основы векторных эмбеддингов
34Sentence transformers: обзор моделей
56Методы кластеризации в Scikit-learn
78Метрики оценки retrieval (HR, MRR, Recall)
91LangChain: работа с текстовыми сплиттерами
112DBSCAN vs KMeans для текстовых данных
145Оценка качества RAG с помощью RAGAS
167Принципы chunking в RAG-системах
189Визуализация эмбеддингов (t-SNE, UMAP)
204Оптимизация скорости инференса эмбеддингов

10. Чек-лист самопроверки

  • Я получил корректные эмбеддинги предложений (формат numpy array, размерность 384–768).
  • Кластеризация даёт кластеры, соответствующие тематическим сдвигам в тексте (визуально проверено).
  • Чанки, сформированные из кластеров, не содержат предложений из разных исходных документов.
  • Я сравнил метрики retrieval и увидел, что semantic chunking не хуже baseline (или лучше).
  • Код покрыт комментариями и запускается из корня репозитория одной командой python main.py.