Привет! Это снова Денис Куров.
В первой статье мы сделали простую RAG-систему: загружали PDF, резали на куски фиксированной длины, создавали эмбеддинги и искали ответы.
Это работало, но был нюанс: мы резали текст просто по символам. Иногда предложения и даже смысл обрывались — это снижало точность поиска.
В этой статье мы улучшим систему:
теперь будем делить текст по смыслу — с помощью семантического чанкирования.
📌 Что такое семантическое чанкирование
- Вместо того, чтобы резать текст каждые 1000 символов, мы делим его на предложения.
- Для каждого предложения делаем эмбеддинг (вектор смысла).
- Меряем, насколько соседние предложения похожи по смыслу (косинусное сходство).
- Если похожесть резко падает — значит, изменилась тема → ставим границу чанка.
- Склеиваем предложения в смысловые блоки (чанки).
Аналогия:
В прошлой версии мы делили фильм на куски по 10 минут — независимо от сюжета.
В новой версии — режём фильм по смене сцен. Логично, цельно, понятно.
🛠 Практическая часть — Пошаговый код в Google Colab
>>>>>>>>>>>>>> Ссылка на блокнот в Google Collab
1. Установка зависимостей и импорт библиотек
Что происходит:
Ставим библиотеки и подключаем инструменты для:
- чтения PDF
- работы с массивами (numpy)
- обращений к Nebius/OpenAI API
- загрузки файлов в Colab
2. Загрузка PDF
Что происходит:
Открывается диалог загрузки, пользователь выбирает PDF, он сохраняется в виртуальную папку Colab.
3. Извлечение текста из PDF
Что происходит:
Мы открываем PDF, извлекаем текст со всех страниц и склеиваем в одну строку.
Результат:
В переменной extracted_text — весь текст документа.
🔑 Как получить API-ключ в Nebius Studio
Перед тем как выполнять 4-ю ячейку, нам нужен API-ключ.
Шаги:
Зарегистрируйтесь в Nebius Studio
Перейдите на сайт: https://studio.nebius.com/playground
Нажмите кнопку Sign in (в правом верхнем углу).
Выберите способ входа: Google, GitHub или Email.
Подтвердите вход.
Получите API-ключ
Войдя в систему, нажмите на значок профиля (справа вверху).
Выберите пункт Get API key.
В открывшемся окне нажмите Create API key.
Дайте ключу понятное имя, например:rag_tutorial_key
Нажмите Create.
Сохраните ключ в безопасном месте
После создания ключ покажут один раз.
Скопируйте его и запишите в надёжное место — больше его посмотреть нельзя.
Используйте ключ в Google Colab
4. Делим текст на предложения и создаём эмбеддинги
📍 Что мы сделали здесь
- Получили API-ключ Nebius Studio (даёт доступ к моделям).
- Создали клиента OpenAI для работы через api.studio.nebius.com.
- Написали функцию для получения эмбеддингов.
- Разбили текст на отдельные предложения.
- Для каждого предложения создали векторное смысловое представление.
🔍 В чём разница с первой статьёй
💡 В первой версии RAG:
- Брали куски текста по 1000 символов (с перекрытием 200).
- Резали "по линейке" — иногда обрывали мысль на полуслове.
- Эмбеддинги создавались для куска текста фиксированной длины.
📌 Минус: смысл мог распасться между чанками, а один чанк мог содержать две разные темы.
💡 В новой версии:
- Сначала делим текст на логичные законченные предложения.
- Для каждого предложения делаем эмбеддинг.
- Смотрим, насколько предложения похожи по смыслу.
- Объединяем только те, что действительно связаны темой.
- Разрезаем там, где смысл меняется.
📌 Плюс: чанки получаются логичными, цельными и идеально подходящими для поиска.
📌 Пример результата
🧠 Создано 3232 эмбеддингов предложений.
📏 Пример длины вектора: 3584 чисел
Ячейка 5 — Меряем смысловую связанность предложений (Cosine Similarity)
Зачем: нам нужно понять, где соседние предложения резко меняют тему. Там мы потом порежем текст на смысловые чанки.
📌 Что происходит
- У нас есть эмбеддинги каждого предложения.
- Мы берём два соседних и считаем косинусное сходство —
число от -1 до 1:1.0 → смыслы полностью совпадают.
0.0 → смыслы вообще никак не связаны.
-1.0 → противоположные по смыслу (в текстах почти не встречается).
Видно:
- Первые три значения высокие (тема продолжается).
- Потом 0.42 и 0.39 — это явный перелом смысла → туда поставим «ножницы».
Ячейка 6 — Находим точки разреза (Percentile Method)
Зачем: выделить 10% самых низких значений сходства как места, где скорее всего меняется тема.
В прошлой версии мы резали каждые 1000 символов, независимо от того, меняется тема или нет.
Теперь мы делаем эти разрывы там, где это диктует содержание, а не фиксированный размер.
📊 Пример результата
📌 Как это читать
- Порог 0.45 значит: всё, что меньше этого значения — мы считаем границей тем.
- Первое значение 6 означает:
→ Чанк закончится после 6-го предложения. - Дальше [61, 113, ...] — места, где мы порежем на новые смысловые блоки.
Ячейка 7 — Склеиваем смысловые чанки
📌 Что это значит
- Этот чанк — законченное объяснение одной мысли.
- В нём нет «обрезанных» предложений.
- Он логически отделён от следующего чанка, который, например, может говорить уже про подходы к тестированию или CI/CD.
💡 Аналогия:
В старом подходе у нас могло быть «половина абзаца → кусок следующего абзаца, который не связан по смыслу».
В новом подходе чанки похожи на аккуратно вырезанные параграфы из книги, каждый из которых про одно.
Ячейка 8 — Получаем эмбеддинги для смысловых чанков
📊 Пример вывода
Сделано 324 эмбеддингов чанков.
Размерность вектора: 3584
Пример вектора: [0.00161648 0.00265312 0.02503967 0.00477982 0.00801849]
📌 Что это значит
- Мы получили по одному вектору для каждого смыслового чанка.
- Размерность 3584 — это значит, что каждый чанк описан 3584 числами, кодирующими его смысл.
- Пример выше — первые 5 чисел одного такого вектора.
✅ Теперь у нас есть структурированная база смысловых векторов, и мы можем искать по смыслу, а не по ключевым словам.
Ячейка 9 — Поиск по смыслу (Semantic Search)
📊 Реальный пример запуска
📌 Что это значит
- По запросу, написанному даже с ошибками (т три типа взаимодействия), поиск нашёл релевантные блоки.
- Модель вернула точные смысловые фрагменты о командах, запросах и событиях — при этом не отвлекаясь на весь остальной текст книги.
- Это 100% иллюстрирует главное преимущество RAG — мы извлекаем ровно то, что нужно.
Ячейка 10 — Генерация ответа на основе найденных чанков
📊 Реальный вывод при запросе:
📌 Что важно
- Мы получили структурированный и исчерпывающий ответ без "галлюцинаций".
- Всё взято только из найденных чанков контекста.
- Для каждого типа есть реальный пример из книги.
- Читатель сразу видит, что поиск сработал корректно и LLM не выдумывает лишнего.
🏁 Заключение
Мы прошли весь путь построения RAG‑потока (Retrieval-Augmented Generation) — от сырого текста до точного и аргументированного ответа модели.
- Разделили текст на предложения — чтобы модель работала не с «грубыми кусками», а с осмысленными единицами.
- Построили эмбеддинги предложений — превратили смысл каждой фразы в векторное представление.
- Нашли точки смены темы — автоматически определили границы, где меняется смысл, а значит, и место для «разреза» текста.
- Собрали смысловые чанки — логические блоки, внутри которых сохраняется связность и контекст.
- Построили вектор для каждого чанка — получили "отпечаток смысла" всего блока.
- Выполнили поиск по смыслу — выбрали релевантные чанки для исходного запроса, даже если в нём были опечатки или неточные формулировки.
- Передали найденные фрагменты в LLM — снабдили модель только необходимым контекстом вместо всей базы.
- Получили точный, лаконичный ответ — без выдуманных фактов и с примерами из оригинального текста.
💡 Итог: мы построили систему, которая отвечает на вопросы точно по тексту, а не «по памяти» модели. Такой подход масштабируется на книги, документацию, базы знаний — и работает эффективно даже при очень большом объёме исходного материала.