Загрузка 0
ПОДЕЛИТЬСЯ

Мой блог

Листай вниз

Как создать локальный RAG на Python: разбор за семь занятий

Как создать локальный RAG на Python: разбор за семь занятий

Привет! Меня зовут Сергей Багров, и сегодня я подготовил для вас подробный разбор практического курса по созданию локальных систем поиска и генерации ответов (RAG) на Python. Если вы хотите самостоятельно разобраться, как заставить искусственный интеллект работать с вашими собственными текстовыми файлами без отправки данных в облако, этот материал станет отличной отправной точкой.

Мы поэтапно изучим архитектуру проекта local-docs-ai, который умеет читать документы в форматах Markdown и TXT, индексировать их с помощью локальной embedding-модели, пересылать релевантные фрагменты языковой модели и наглядно демонстрировать исходные строки с именами файлов. Такой подход позволяет чётко разделять возможные сбои: когда поисковый алгоритм выдал не тот кусок текста или когда сама генеративная модель некорректно пересказала найденное.

Как устроено приложение и архитектура RAG

Технология RAG, или генерация с привлечением внешнего контекста, работает по принципу предварительного подбора наиболее подходящих фрагментов из ваших документов с последующей передачей их языковой модели вместе с пользовательским вопросом. Веса самой генеративной модели при этом не подвергаются изменениям, а любые новые заметки становятся доступны сразу после пересборки поискового индекса.

Реклама

Процессы построения индекса и ответов

Вся работа программы делится на два самостоятельных этапа. Сначала файлы из папки documents/ проходят проверку кодировки UTF-8, нарезаются на отдельные куски, переводятся моделью embeddinggemma в числовые векторы и сохраняются в файле data/index.json. На втором этапе поступает вопрос пользователя, который точно так же превращается в вектор, сравнивается с базой для отбора до трёх лучших фрагментов, после чего модель qwen3:1.7b формирует окончательный ответ на базе полученного контекста.

Компоненты системы и ограничения

Запуск обеих моделей обеспечивает локальный сервер Ollama, к которому Python обращается через стандартное API по адресу http://127.0.0.1:11434. Основное ядро проекта сосредоточено в файле docqa.py и задействует стандартные библиотеки вроде pathlib, hashlib, json, math и urllib.request. Для работы веб-интерфейса в браузере используется библиотека Streamlit. Проект имеет четкие ограничения: поддерживается до 50 файлов общим объемом до 1 000 000 байт, а файлы PDF намеренно пропускаются, чтобы весь поисковый индекс помещался в оперативной памяти.

Занятие 1: Первый запуск и диагностика

Для погружения в проект потребуются установленный интерпретатор Python версии 3.10 или выше, система контроля версий Git и запущенная локально Ollama. После клонирования репозитория необходимо загрузить нужные модели через команды ollama pull embeddinggemma и ollama pull qwen3:1.7b. Загрузка потребует порядка 622 МБ для первой модели и около 1,4 ГБ для второй, однако реальный расход оперативной памяти в процессе работы будет зависеть от характеристик вашего компьютера.

Специальная диагностическая команда python docqa.py doctor обращается к серверу Ollama для проверки доступности обеих моделей. Убедившись в работоспособности окружения, можно выполнить полный цикл индексации и тестовый запрос через команды index, search и ask. Это позволит на практике сравнить исходные данные в текстовых файлах с тем ответом, который выдает модель.

Занятие 2: Фрагменты документов и номера строк

Поскольку поиск по документам всегда оперирует небольшими логическими частями, тексту необходимы четкие границы и адреса. Функция scan_documents() сканирует целевой каталог, выбирает поддерживаемые расширения, фильтрует символические ссылки и корректно декодирует байты в кодировке UTF-8, включая варианты с BOM.

Затем в дело вступает функция split_document(), ограничивающая размер каждого фрагмента 1000 символами. При этом заголовки Markdown-разметки служат естественными разделителями для новых кусков, что помогает удерживать смысловую целостность текста. Полученные диапазоны строк и текст сохраняются в памяти, а правильность разбиения можно проанализировать в интерактивной оболочке Python даже без задействования языковых моделей.

Занятие 3: Векторы и локальный индекс

Обычный поиск по точному совпадению слов часто не справляется с синонимами, поэтому embedding-модель переводит текст и вопросы в наборы чисел, позволяющие оценивать их смысловую близость. Запросы к эбеддингам отправляются через специальную вспомогательную функцию ollama_json(), которая обрабатывает ответы и страхует систему от некорректных математических значений вроде NaN.

Реклама

Чтобы избежать устаревания данных после правок файлов, программа вычисляет хеш SHA-256 по путям и содержимому документов. Если исходные тексты были изменены, система автоматически потребует пересобрать индекс. Кроме того, предусмотрена защита от повреждения данных: новый индекс сначала записывается во временный файл, и лишь затем подменяет основной файл index.json.

Занятие 4: Косинусная близость и отбор кандидатов

После вычисления вектора для пользовательского вопроса алгоритм find_chunks() сопоставляет его со всеми сохраненными векторами документов, используя меру косинусного расстояния. Направление векторов ближе к единице говорит о максимальном совпадении смыслов, однако полученное число не является прямой вероятностью правильного ответа.

Поскольку текущая реализация использует полный перебор всех сохраненных векторов и всегда выбирает три лучших варианта, при запросах на отвлеченные темы система все равно попытается найти наиболее близкие по математическим метрикам фрагменты. Для борьбы с галлюцинациями модели в дальнейшем можно использовать пороги релевантности или настраивать строгие системные инструкции.

Занятие 5: Запрос к модели и проверяемые источники

Отобранные фрагменты упаковываются в единый контекст с указанием порядковых номеров, путей к файлам и номеров строк. Полученный массив данных вместе с вопросом пользователя и жесткой системной инструкцией передается в генеративную модель через эндпоинт /api/chat.

Системный промпт предписывает модели опираться исключительно на предоставленные выписки, честно признавать нехватку информации фразой о том, что в документах нет ответа, и игнорировать возможные попытки инъекций инструкций через текст документов. При этом список источников формируется поисковым модулем независимо от модели, что позволяет пользователю самостоятельно сверять цитаты.

Занятие 6: Веб-интерфейс на Streamlit

Для создания удобного графического интерфейса используется фреймворк Streamlit. Файл app.py задействует те же функции индексации и генерации, что и интерфейс командной строки, предоставляя пользователю боковую панель для обновления индекса и удобную форму для ввода вопросов.

Последний успешный результат сессии сохраняется в состоянии приложения st.session_state.result, защищая интерфейс от потери данных при перезагрузке скрипта. Исходные фрагменты текстов выводятся в интерактивных разворачиваемых блоках с использованием моноширинного форматирования для максимальной прозрачности проверки.

Занятие 7: Диагностика ошибок и автоматические тесты

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

В проекте предусмотрен набор автоматических тестов, запускаемых стандартной командой python -m unittest discover -s tests -v. Тесты проверяют корректность чтения файлов, соблюдение лимитов размера, обработку сетевых ошибок и стабильность сохранения индекса при сбоях, позволяя разработчику уверенно развивать и масштабировать локальное ИИ-приложение.

Реклама
01.