Найти в Дзене

✂ Семантическое чанкирование в RAG: режем текст по смыслу, а не “по линейке”

Привет! Это снова Денис Куров.
В первой статье мы сделали простую RAG-систему: загружали PDF, резали на куски фиксированной длины, создавали эмбеддинги и искали ответы. Это работало, но был нюанс: мы резали текст просто по символам. Иногда предложения и даже смысл обрывались — это снижало точность поиска. В этой статье мы улучшим систему:
теперь будем делить текст по смыслу — с помощью семантического чанкирования. 📌 Что такое семантическое чанкирование Аналогия:
В прошлой версии мы делили фильм на куски по 10 минут — независимо от сюжета.
В новой версии — режём фильм по смене сцен. Логично, цельно, понятно. Что происходит:
Ставим библиотеки и подключаем инструменты для: Что происходит:
Открывается диалог загрузки, пользователь выбирает PDF, он сохраняется в виртуальную папку Colab. Что происходит:
Мы открываем PDF, извлекаем текст со всех страниц и склеиваем в одну строку. Результат:
В переменной extracted_text — весь текст документа. Перед тем как выполнять 4-ю ячейку, нам нужен API
Оглавление

Привет! Это снова Денис Куров.
В первой статье мы сделали простую RAG-систему: загружали PDF, резали на куски фиксированной длины, создавали
эмбеддинги и искали ответы.

Это работало, но был нюанс: мы резали текст просто по символам. Иногда предложения и даже смысл обрывались — это снижало точность поиска.

В этой статье мы улучшим систему:
теперь будем
делить текст по смыслу — с помощью семантического чанкирования.

📌 Что такое семантическое чанкирование

  • Вместо того, чтобы резать текст каждые 1000 символов, мы делим его на предложения.
  • Для каждого предложения делаем эмбеддинг (вектор смысла).
  • Меряем, насколько соседние предложения похожи по смыслу (косинусное сходство).
  • Если похожесть резко падает — значит, изменилась тема → ставим границу чанка.
  • Склеиваем предложения в смысловые блоки (чанки).

Аналогия:
В прошлой версии мы делили фильм на куски по 10 минут — независимо от сюжета.
В новой версии — режём фильм по смене сцен. Логично, цельно, понятно.

🛠 Практическая часть — Пошаговый код в Google Colab

>>>>>>>>>>>>>> Ссылка на блокнот в Google Collab

1. Установка зависимостей и импорт библиотек

-2

Что происходит:
Ставим библиотеки и подключаем инструменты для:

  • чтения PDF
  • работы с массивами (numpy)
  • обращений к Nebius/OpenAI API
  • загрузки файлов в Colab

2. Загрузка PDF

-3

Что происходит:
Открывается диалог загрузки, пользователь выбирает PDF, он сохраняется в виртуальную папку Colab.

3. Извлечение текста из PDF

-4

Что происходит:
Мы открываем PDF, извлекаем текст со всех страниц и склеиваем в одну строку.

Результат:
В переменной extracted_text — весь текст документа.

🔑 Как получить API-ключ в Nebius Studio

Перед тем как выполнять 4-ю ячейку, нам нужен API-ключ.

Шаги:

Зарегистрируйтесь в Nebius Studio

Перейдите на сайт: https://studio.nebius.com/playground Нажмите кнопку Sign in (в правом верхнем углу).
Выберите способ входа: Google, GitHub или Email.
Подтвердите вход.

Получите API-ключ

Войдя в систему, нажмите на значок профиля (справа вверху).
Выберите пункт
Get API key.

-5


В открывшемся окне нажмите
Create API key.

Дайте ключу понятное имя, например:rag_tutorial_key
Нажмите
Create.

Сохраните ключ в безопасном месте

После создания ключ покажут один раз.
Скопируйте его и запишите в надёжное место — больше его посмотреть нельзя.

Используйте ключ в Google Colab

4. Делим текст на предложения и создаём эмбеддинги

-6

📍 Что мы сделали здесь

  • Получили API-ключ Nebius Studio (даёт доступ к моделям).
  • Создали клиента OpenAI для работы через api.studio.nebius.com.
  • Написали функцию для получения эмбеддингов.
  • Разбили текст на отдельные предложения.
  • Для каждого предложения создали векторное смысловое представление.

🔍 В чём разница с первой статьёй

💡 В первой версии RAG:

  • Брали куски текста по 1000 символов (с перекрытием 200).
  • Резали "по линейке" — иногда обрывали мысль на полуслове.
  • Эмбеддинги создавались для куска текста фиксированной длины.

📌 Минус: смысл мог распасться между чанками, а один чанк мог содержать две разные темы.

💡 В новой версии:

  • Сначала делим текст на логичные законченные предложения.
  • Для каждого предложения делаем эмбеддинг.
  • Смотрим, насколько предложения похожи по смыслу.
  • Объединяем только те, что действительно связаны темой.
  • Разрезаем там, где смысл меняется.

📌 Плюс: чанки получаются логичными, цельными и идеально подходящими для поиска.

📌 Пример результата

🧠 Создано 3232 эмбеддингов предложений.
📏 Пример длины вектора: 3584 чисел

Ячейка 5 — Меряем смысловую связанность предложений (Cosine Similarity)

Зачем: нам нужно понять, где соседние предложения резко меняют тему. Там мы потом порежем текст на смысловые чанки.

-7

📌 Что происходит

  • У нас есть эмбеддинги каждого предложения.
  • Мы берём два соседних и считаем косинусное сходство
число от -1 до 1:1.0 → смыслы полностью совпадают.
0.0 → смыслы вообще никак не связаны.
-1.0 → противоположные по смыслу (в текстах почти не встречается).
-8

Видно:

  • Первые три значения высокие (тема продолжается).
  • Потом 0.42 и 0.39 — это явный перелом смысла → туда поставим «ножницы».

Ячейка 6 — Находим точки разреза (Percentile Method)

Зачем: выделить 10% самых низких значений сходства как места, где скорее всего меняется тема.

-9

В прошлой версии мы резали каждые 1000 символов, независимо от того, меняется тема или нет.
Теперь мы делаем эти разрывы там, где это диктует содержание, а не фиксированный размер.

📊 Пример результата

-10

📌 Как это читать

  • Порог 0.45 значит: всё, что меньше этого значения — мы считаем границей тем.
  • Первое значение 6 означает:
    → Чанк закончится
    после 6-го предложения.
  • Дальше [61, 113, ...] — места, где мы порежем на новые смысловые блоки.

Ячейка 7 — Склеиваем смысловые чанки

-11
Пример вывода
Пример вывода

📌 Что это значит

  • Этот чанк — законченное объяснение одной мысли.
  • В нём нет «обрезанных» предложений.
  • Он логически отделён от следующего чанка, который, например, может говорить уже про подходы к тестированию или CI/CD.

💡 Аналогия:
В старом подходе у нас могло быть «половина абзаца → кусок следующего абзаца, который не связан по смыслу».
В новом подходе чанки похожи на
аккуратно вырезанные параграфы из книги, каждый из которых про одно.

Ячейка 8 — Получаем эмбеддинги для смысловых чанков

-13

📊 Пример вывода

Сделано 324 эмбеддингов чанков.
Размерность вектора: 3584
Пример вектора: [0.00161648 0.00265312 0.02503967 0.00477982 0.00801849]

📌 Что это значит

  • Мы получили по одному вектору для каждого смыслового чанка.
  • Размерность 3584 — это значит, что каждый чанк описан 3584 числами, кодирующими его смысл.
  • Пример выше — первые 5 чисел одного такого вектора.

✅ Теперь у нас есть структурированная база смысловых векторов, и мы можем искать по смыслу, а не по ключевым словам.

Ячейка 9 — Поиск по смыслу (Semantic Search)

-14

📊 Реальный пример запуска

-15

📌 Что это значит

  • По запросу, написанному даже с ошибками (т три типа взаимодействия), поиск нашёл релевантные блоки.
  • Модель вернула точные смысловые фрагменты о командах, запросах и событиях — при этом не отвлекаясь на весь остальной текст книги.
  • Это 100% иллюстрирует главное преимущество RAG — мы извлекаем ровно то, что нужно.

Ячейка 10 — Генерация ответа на основе найденных чанков

-16

📊 Реальный вывод при запросе:

-17

📌 Что важно

  • Мы получили структурированный и исчерпывающий ответ без "галлюцинаций".
  • Всё взято только из найденных чанков контекста.
  • Для каждого типа есть реальный пример из книги.
  • Читатель сразу видит, что поиск сработал корректно и LLM не выдумывает лишнего.

🏁 Заключение

Мы прошли весь путь построения RAG‑потока (Retrieval-Augmented Generation) — от сырого текста до точного и аргументированного ответа модели.

  1. Разделили текст на предложения — чтобы модель работала не с «грубыми кусками», а с осмысленными единицами.
  2. Построили эмбеддинги предложений — превратили смысл каждой фразы в векторное представление.
  3. Нашли точки смены темы — автоматически определили границы, где меняется смысл, а значит, и место для «разреза» текста.
  4. Собрали смысловые чанки — логические блоки, внутри которых сохраняется связность и контекст.
  5. Построили вектор для каждого чанка — получили "отпечаток смысла" всего блока.
  6. Выполнили поиск по смыслу — выбрали релевантные чанки для исходного запроса, даже если в нём были опечатки или неточные формулировки.
  7. Передали найденные фрагменты в LLM — снабдили модель только необходимым контекстом вместо всей базы.
  8. Получили точный, лаконичный ответ — без выдуманных фактов и с примерами из оригинального текста.

💡 Итог: мы построили систему, которая отвечает на вопросы точно по тексту, а не «по памяти» модели. Такой подход масштабируется на книги, документацию, базы знаний — и работает эффективно даже при очень большом объёме исходного материала.