Разработка с помощью AI‑инструментов меняет подход к созданию ПО. Я сам убедился в этом на практике: всего за два дня мне удалось создать Text Extract API для RAG, используя Claude 4.0, Gemini Pro 2.5 и IDE Cursor. Этот эксперимент показал, что нейросети — уже не просто хайп, а мощный ассистент, способный значительно ускорить процесс разработки.
Наша команда занимается созданием ПО для IT‑специалистов — программу «Управление IT‑отделом 8». В ней есть блок для работы с заявками от клиентов и обширная база знаний. Возникла идея: интегрировать нейросети для автоматической обработки тикетов. Кейс прост:
Прилетает тикет от клиента > Нейросеть смотрит в базу знаний и готовит ответ > IT‑специалист либо использует ответ нейросети, либо нейросеть отвечает автоматически.
Для реализации такого функционала необходимо обучить AI‑модель на нашей базе знаний, а это требует качественного извлечения текста из различных документов. Эта статья посвящена первому этапу этого процесса — созданию API для извлечения текстовых данных из файлов любых форматов, что критически важно для эффективной работы с Retrieval‑Augmented Generation (RAG).
Для тех, кто хочет сразу увидеть результат, вот ссылка на GitHub.
Постановка задачи и выбор инструментов
Зачем это все нужно?
Есть такая замечательная штука, которую придумали для обучения нейросетей, которая называется Embeddings.
Embeddings — это векторное представление текстовых данных. Они используются для того, чтобы потом можно было из вопроса пользователя получить векторное представление (наборы чисел). Интересно то, что если потом и из вопроса получить Embeddings, то окажется, что векторное представление вопроса и наиболее релевантных ответов будут максимально близко находятся друг к другу.
Если выбрать N‑записей, которые будут максимально близко к вопросу и извлечь релевантный текст этих записей, а потом скормить все это богатство уже модели AI (например, GPT-4), но с вопросом пользователя и в контекст подкинуть те N‑записей, что мы нашли, то нейросеть подготовит хороший ответ на вопрос пользователя. Схема примерно следующая:
Зачем такие сложности и почему сразу не спросить нейросеть и задать ей тот вопрос, который задал клиент? Дело в том, что нейросеть может ничего не знать о каких‑то специфических вещах. Ну например, на предприятии есть какой‑нибудь регламент и вопрос прилетает именно по этому регламенту. Что в таком случае ответит нейросеть? Правильно, ерунду…
Поэтому общая схема ответа на вопрос пользователя по базе знаний с использованием AI будет такой:
Как работает RAG
-
Retrieval (извлечение)
Модель получает запрос и обращается к базе данных (чаще всего с эмбеддингами) для поиска релевантных документов или фрагментов текста. -
Augmentation (обогащение)
Найденная информация добавляется к исходному запросу. -
Generation (генерация ответа)
Языковая модель (например, GPT-4) использует расширенный контекст (вопрос + найденные документы), чтобы выдать точный и обоснованный ответ.
Это очень упрощенная формулировка и алгоритм. Очень хорошее описание RAG в статье Архитектура RAG: полный гайд.
Формализация требований: сила хорошего ТЗ
Итак, наша задача общими словами — это на первом этапе научиться получать текст из всего, что может понадобиться: docx, xlsx, pdf, png, jpg, doc, xls, zip, rar, 7z …
Если картинка, нужно распознать на ней текст, если офисный документ — достать текст оттуда, таблицу прочитать так, чтобы поняла текстовая модель, архивы распаковать и достать оттуда все вложенные файлы и с ними сделать то же самое. Фронт работы огромный.
Я начал с самого главного. С написания подробного технического задания (ТЗ). Есть такая прибаутка у аналитиков: «Без ТЗ результат ХЗ». При вайб‑кодинге с нейросетью, как я понял, это истина на 100% :)
Подготовил промпт в Google Gemini. Попросил ТЗ для извлечения текста:
Роль:
Ты — эксперт по составлению технических заданий (ТЗ).
Твоя задача:
Задавать уточняющие вопросы для формирования четкого ТЗ. Формулировать структурированное ТЗ на основе ответов. Проверять ТЗ на полноту и корректность, уточняя недостающие детали.
Контекст:
Входные данные:
Мне нужно простое API для извлечения текста из файлов различных форматов.
Изображения с OCR:.jpg,.jpeg,.png,.tiff,.tif,.bmp,.gif (распознавание на русском и английском)
Текстовые файлы:.txt
HTML документы:.html,.htm
Markdown файлы:.md,.markdown
Обработка через textract
Документы:.doc,.docx,.pdf,.rtf,.odt
Таблицы:.csv,.xls,.xlsx,.ods
Презентации:.pptx,.ppt
Электронные книги:.epub
Email:.eml,.msg
Данные:.json
Markdown:.md,.markdown
Выходные данные:
Готовое ТЗ в структурированном формате.
Проверка и уточнение ТЗ для исключения двусмысленностей.
Цель:
Создать ТЗ, которое:
Полностью описывает задачу или проект.
Учитывает все ключевые аспекты (функционал, ограничения, технологии).
Легко понимается разработчиками и другими участниками команды.
Ограничения:
Все требования должны быть изложены четко и без двусмысленностей.
Если пользователь не отвечает на вопросы, использовать значения по умолчанию.
Параметры генерации:
Формат вывода:
Черновик ТЗ → Проверка → Итоговое ТЗ.
Дополнительно:
Рекомендации по улучшению ТЗ.
Примеры типовых решений для сложных случаев.
В результате после общения с нейросетью и кучи правок, я получил отличное ТЗ для разработки.
Вот что получил в итоге:
-
Поддерживаемые форматы (PDF, DOCX, изображения,архивы, исходный код и др.)
-
Требования к безопасности (валидация MIME‑типов, защита от zip‑бомб, fail‑closed по умолчанию)
-
Нефункциональные параметры (таймауты, максимальный размер файлов, асинхронность)
-
Структуру API и примеры ответов
-
Требования к тестированию и инфраструктуре (Docker, Makefile, CI/CD).
Конечно, в процессе разработки ТЗ редактировалось, но сама суть дальше уже почти не менялась.
Совет: чем подробнее и структурированнее ТЗ, тем проще автоматизировать разработку и ревью, особенно если вы планируете использовать AI‑ассистентов.
Почему Cursor и AI?
Cursor — современная IDE, ориентированная на интеграцию с AI‑моделями. В связке с Claude 4.0 и Gemini Pro 2.5 она позволяет:
-
быстро генерировать boilerplate‑код
-
получать архитектурные рекомендации
-
автоматизировать рутинные задачи (настройка Docker, Makefile, тестов)
-
проводить ревью и рефакторинг с помощью AI
Архитектура решения: от идеи к коду
Общая структура проекта
Проект был организован по классическим принципам Python‑разработки:
-
app/ — исходный код (extractors, utils, main, config)
-
tests/ — тесты и тестовые данные
-
Makefile, Dockerfile, docker-compose.yml — автоматизация сборки и запуска
-
docs/TZ.md — живое техническое задание, обновляемое по мере развития проекта
Совет: Ведение актуального ТЗ в репозитории — залог прозрачности и воспроизводимости разработки. Это облегчает ревью, автоматизацию и масштабирование команды.
Ключевые архитектурные решения
Асинхронность и изоляция
Все ресурсоемкие операции (OCR, парсинг PDF, работа с архивами) выполняются вне основного event loop с помощью run_in_threadpool. Это позволяет обрабатывать большие файлы, не блокируя сервер, и масштабировать API горизонтально.
Безопасность
-
Fail‑closed: любые сомнительные файлы отклоняются.
-
Валидация MIME‑типов: ароверка соответствия расширения и содержимого.
-
Ограничения на размер и глубину архивов: защита от zip‑бомб и path traversal.
-
Изоляция временных файлов: использование контекстных менеджеров и автоматическая очистка.
Все параметры (порт, языки OCR, таймауты, лимиты) задаются через переменные окружения, что облегчает деплой и CI/CD.
API снабжен автогенерируемой Swagger‑документацией, что критично для интеграции с внутренними сервисами.
Пример реализации эндпоинта
@app.post("/v1/extract/") async def extract_text(file: UploadFile = File(...)): # Валидация, обработка, логирование extracted_files = await asyncio.wait_for( run_in_threadpool( text_extractor.extract_text, content, safe_filename_for_processing ), timeout=settings.PROCESSING_TIMEOUT_SECONDS ) return {"status": "success", "files": extracted_files}
Практический совет: используйте asyncio.wait_for для контроля таймаутов на уровне API — это позволяет возвращать понятные ошибки (504 Gateway Timeout) и защищает сервер от зависаний.
Тестирование: автоматизация, проблемы и решения
Автоматизация тестирования
В проекте реализованы:
-
Unit‑тесты для extractors и utils,
-
Integration‑тесты для API,
-
Legacy‑тесты с реальными файлами (через run_tests.sh).
Инструменты: pytest, httpx, pytest‑asyncio, pytest‑cov.
Проблемы и ограничения
Несмотря на автоматизацию, тесты не всегда покрывают все edge‑cases:
-
Некоторые форматы (например, архивы с вложенными файлами) сложно тестировать автоматически.
-
Генерация тестовых данных для всех поддерживаемых форматов требует времени и ручной работы.
-
Legacy‑тесты не всегда интегрируются с CI/CD и могут давать ложноположительные результаты.
Совет: для сложных форматов используйте property‑based testing (например, с помощью Hypothesis), а для интеграционных сценариев — мокайте внешние зависимости (LibreOffice, Tesseract).
Практические рекомендации по тестированию
-
Покрытие кода: Сейчас ~60% (контролируется через pytest‑cov).
-
Изоляция тестов: Каждый тест должен быть независимым и не оставлять временных файлов.
-
Воспроизводимость: Все тестовые данные должны храниться в репозитории, а результаты — игнорироваться через.gitignore.
-
CI/CD: Интегрируйте тесты в pipeline, чтобы не допускать регрессий.
Опыт работы с AI и Cursor: плюсы, минусы, лайфхаки
Как AI помогал (и мешал)
Я использовал Claude 4.0 в качестве основной нейросети. После создания проекта, просим его по файлу ТЗ реализовать функциональность. Если есть вопросы задать их нам перед началом.
Дальше AI набросал вполне годное API на Python и FastAPI. Я разобрал структуру созданного проекта и завел правила для курсора (Cursor Rules). В правилах не жестил, просто нашел шаблон, который нужен, и добавил от себя где искать основные файлы проекта. Это обязательный шаг. Нужен он для того, чтобы при каждом запросе нейросеть не исследовала проект с нуля, а использовала готовую информацию о том, как организован код и что разработчик от нее ждет.
После этого пошли уже улучшения, добавление новых файлов для поддержки и т. д.
Основной кейс использования такой:
-
Мне нужно реализовать по TZ.md такой‑то блок / возможность (пишем что нужно). Напиши код, при необходимости добавь тесты и обнови документацию.
-
Он пишет код.
-
Мы проверяем и находим какие‑то недочеты.
-
Просим исправить если находятся ошибки.
-
Повторяем до того момента, пока блок / возможность / фича / ошибка будут сделаны. Возможно правим что‑то самостоятельно.
Таких итераций было достаточно много.
Далее наступил момент, когда сделано немало и вроде как всё работает, но все равно страшно:) Например, а вдруг есть какие‑то проблемы с безопасностью. Когда код написан нейросетью и ты не уверен в его правильности, то необходимо все перепроверить. Каким образом? Просим другую нейросеть))) Я использовал Gemini 2.5 Pro.
Промпт:
Далее было найдено несколько серьезных моментов, которые снова скармливаем Claude 4.0. Например, обработка архивов с path traversal, zip‑bomb, синхронная работа некоторых распаковщиков файлов, вместо асинхронной и еще парочка интересных моментов были найдены на этих моментах.Я написал исходный код в проекте. Файл ТЗ находится в папке docs. Проверь проект на соответствие ТЗ, дополнительно ты должен найти в коде ошибки, уязвимости, неточности, проблемы с производительностью и все то, что может вызвать проблемы на prodaction.
На все про все у меня ушло 2 дня (!) и получил готовый API. Я бы не поверил, если бы сам лично в этом не участвовал