Разработка с помощью 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.

1. Постановка задачи и выбор инструментов

1.1. Зачем это все нужно?

Есть такая замечательная штука, которую придумали для "обучения" нейросетей, которая называется Embeddings. Как правильно подсказали в комментариях, это не совсем обучение, но выглядит именно так.

Embeddings — это векторное представление текстовых данных. Они используются для того, чтобы потом можно было из вопроса пользователя получить векторное представление (наборы чисел). Интересно то, что если потом и из вопроса получить Embeddings, то окажется, что векторное представление вопроса и наиболее релевантных ответов будут максимально близко находятся друг к другу.

Если выбрать N‑записей, которые будут максимально близко к вопросу и извлечь релевантный текст этих записей, а потом скормить все это богатство уже модели AI (например, GPT-4), но с вопросом пользователя и в контекст подкинуть те N‑записей, что мы нашли, то нейросеть подготовит хороший ответ на вопрос пользователя. Схема примерно следующая:

Упрощенная схема работы с базой знаний AI
Упрощенная схема работы с базой знаний AI

Зачем такие сложности и почему сразу не спросить нейросеть и задать ей тот вопрос, который задал клиент? Дело в том, что нейросеть может ничего не знать о каких‑то специфических вещах. Ну например, на предприятии есть какой‑нибудь регламент и вопрос прилетает именно по этому регламенту. Что в таком случае ответит нейросеть? Правильно, ерунду…

Мемчик
Мемчик

Поэтому общая схема ответа на вопрос пользователя по базе знаний с использованием AI будет такой:

Упрощенная схема ответа на вопрос пользователя по базе знаний Embeddings AI
Упрощенная схема ответа на вопрос пользователя по базе знаний Embeddings AI

1.2. Как работает RAG

  1. Retrieval (извлечение)

    Модель получает запрос и обращается к базе данных (чаще всего с эмбеддингами) для поиска релевантных документов или фрагментов текста.

  2. Augmentation (обогащение)

    Найденная информация добавляется к исходному запросу.

  3. Generation (генерация ответа)

    Языковая модель (например, GPT-4) использует расширенный контекст (вопрос + найденные документы), чтобы выдать точный и обоснованный ответ.

Это очень упрощенная формулировка и алгоритм. Очень хорошее описание RAG в статье Архитектура RAG: полный гайд.

1.3. Формализация требований: сила хорошего ТЗ

Итак, наша задача общими словами — это на первом этапе научиться получать текст из всего, что может понадобиться: 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‑ассистентов.

1.4. Почему Cursor и AI?

Cursor — современная IDE, ориентированная на интеграцию с AI‑моделями. В связке с Claude 4.0 и Gemini Pro 2.5 она позволяет:

  • быстро генерировать boilerplate‑код

  • получать архитектурные рекомендации

  • автоматизировать рутинные задачи (настройка Docker, Makefile, тестов)

  • проводить ревью и рефакторинг с помощью AI

Практический пример: Я использовал Cursor для генерации FastAPI‑контроллеров, интеграции с Uvicorn и Docker, а также для написания unit и integration‑тестов.

2. Архитектура решения: от идеи к коду

2.1. Общая структура проекта

Проект был организован по классическим принципам Python‑разработки:

  • app/ — исходный код (extractors, utils, main, config)

  • tests/ — тесты и тестовые данные

  • Makefile, Dockerfile, docker-compose.yml — автоматизация сборки и запуска

  • docs/TZ.md — живое техническое задание, обновляемое по мере развития проекта

Совет: Ведение актуального ТЗ в репозитории — залог прозрачности и воспроизводимости разработки. Это облегчает ревью, автоматизацию и масштабирование команды.

2.2. Ключевые архитектурные решения

Асинхронность и изоляция

Все ресурсоемкие операции (OCR, парсинг PDF, работа с архивами) выполняются вне основного event loop с помощью run_in_threadpool. Это позволяет обрабатывать большие файлы, не блокируя сервер, и масштабировать API горизонтально.

Безопасность

  • Fail‑closed: любые сомнительные файлы отклоняются.

  • Валидация MIME‑типов: ароверка соответствия расширения и содержимого.

  • Ограничения на размер и глубину архивов: защита от zip‑бомб и path traversal.

  • Изоляция временных файлов: использование контекстных менеджеров и автоматическая очистка.

Все параметры (порт, языки OCR, таймауты, лимиты) задаются через переменные окружения, что облегчает деплой и CI/CD.

API снабжен автогенерируемой Swagger‑документацией, что критично для интеграции с внутренними сервисами.

2.3. Пример реализации эндпоинта

@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) и защищает сервер от зависаний.

3. Тестирование: автоматизация, проблемы и решения

3.1. Автоматизация тестирования

В проекте реализованы:

  • Unit‑тесты для extractors и utils,

  • Integration‑тесты для API,

  • Legacy‑тесты с реальными файлами (через run_tests.sh).

Инструменты: pytest, httpx, pytest‑asyncio, pytest‑cov.

3.2. Проблемы и ограничения

Несмотря на автоматизацию, тесты не всегда покрывают все edge‑cases:

  • Некоторые форматы (например, архивы с вложенными файлами) сложно тестировать автоматически.

  • Генерация тестовых данных для всех поддерживаемых форматов требует времени и ручной работы.

  • Legacy‑тесты не всегда интегрируются с CI/CD и могут давать ложноположительные результаты.

Совет: для сложных форматов используйте property‑based testing (например, с помощью Hypothesis), а для интеграционных сценариев — мокайте внешние зависимости (LibreOffice, Tesseract).

3.3. Практические рекомендации по тестированию

  • Покрытие кода: Сейчас ~60% (контролируется через pytest‑cov).

  • Изоляция тестов: Каждый тест должен быть независимым и не оставлять временных файлов.

  • Воспроизводимость: Все тестовые данные должны храниться в репозитории, а результаты — игнорироваться через.gitignore.

  • CI/CD: Интегрируйте тесты в pipeline, чтобы не допускать регрессий.

4. Опыт работы с AI и Cursor: плюсы, минусы, лайфхаки

4.1. Как AI помогал (и мешал)

Я использовал Claude 4.0 в качестве основной нейросети. После создания проекта, просим его по файлу ТЗ реализовать функциональность. Если есть вопросы задать их нам перед началом.

Дальше AI набросал вполне годное API на Python и FastAPI. Я разобрал структуру созданного проекта и завел правила для курсора (Cursor Rules). В правилах не жестил, просто нашел шаблон, который нужен, и добавил от себя где искать основные файлы проекта. Это обязательный шаг. Нужен он для того, чтобы при каждом запросе нейросеть не исследовала проект с нуля, а использовала готовую информацию о том, как организован код и что разработчик от нее ждет.

После этого пошли уже улучшения, добавление новых файлов для поддержки и т. д.

Основной кейс использования такой:

  1. Мне нужно реализовать по TZ.md такой‑то блок / возможность (пишем что нужно). Напиши код, при необходимости добавь тесты и обнови документацию.

  2. Он пишет код.

  3. Мы проверяем и находим какие‑то недочеты.

  4. Просим исправить если находятся ошибки.

  5. Повторяем до того момента, пока блок / возможность / фича / ошибка будут сделаны. Возможно правим что‑то самостоятельно.

Таких итераций было достаточно много.

Далее наступил момент, когда сделано немало и вроде как всё работает, но все равно страшно:) Например, а вдруг есть какие‑то проблемы с безопасностью. Когда код написан нейросетью и ты не уверен в его правильности, то необходимо все перепроверить. Каким образом? Просим другую нейросеть))) Я использовал Gemini 2.5 Pro.

Промпт:

Я написал исходный код в проекте. Файл ТЗ находится в папке docs. Проверь проект на соответствие ТЗ, дополнительно ты должен найти в коде ошибки, уязвимости, неточности, проблемы с производительностью и все то, что может вызвать проблемы на prodaction.

Далее было найдено несколько серьезных моментов, которые снова скармливаем Claude 4.0. Например, обработка архивов с path traversal, zip‑bomb, синхронная работа некоторых распаковщиков файлов, вместо асинхронной и еще парочка интересных моментов были найдены на этих моментах.

На все про все у меня ушло 2 дня (!) и получил готовый API. Я бы не поверил, если бы сам лично в этом не участвовал ?

Конечно то, что нейросеть не нашла больше проблем не значит что их нет. Надо самому проводить ревью и анализ кода.

Плюсы:

  • Быстрая генерация шаблонного кода (FastAPI, Docker, Makefile).

  • Автоматизация рутинных задач (валидация, логирование, обработка ошибок).

  • Генерация тестов и документации.

Минусы:

  • AI не всегда понимает специфику (например, обработка архивов с path traversal).

  • Требуется ручная доработка и ревью, особенно для сложных сценариев.

  • Иногда AI генерирует избыточный или неэффективный код (например, дублирует проверки).

Ну и куда же без ложки дегтя. Было и такое, что AI забывал контекст и делал не то и после того, как его поправляешь, он начинает писать и хвалить тебя:

  • Вы правы, я допустил ошибку …

  • Вы подняли очень важный вопрос! …

  • И т.д.

Выглядит это все забавно, но забавно это ровно до того момента, если ты увидел и нашел проблему. А если же нет, то это останется в проекте и возможно потом выстрелит в не самое подходящее время...

Совет: используйте AI как ассистента, а не как единственный источник истины. Всегда проводите ревью и тестирование вручную. Также не стоит одним промптом решать сразу несколько сложных вопросов. Это чревато тем, что это будет выполнено не очень качественно.

4.2. Практические лайфхаки

  • Cursor + Claude 4.0: Отлично подходит для генерации boilerplate и архитектурных решений.

  • Gemini Pro 2.5: Хорош для ревью и генерации тестов.

  • Промпт‑инжиниринг: Чем подробнее и структурированнее ваш запрос, тем качественнее результат. Не стесняйтесь давать AI примеры и контекст.

  • Интеграция с git: Используйте AI для генерации changelog и автоматического обновления документации.

4.3. Статистика и метрики

  • Время разработки: С помощью AI и Cursor MVP был реализован за 2 дня!

  • Покрытие тестами: 60% кода покрыто unit и integration тестами.

  • Производительность: Обработка PDF‑файла 10 МБ — менее 10 секунд на сервере с 4 CPU.

Заключение

Приступая к этому проекту при использовании Cursor, я совсем не ожидал, что проект будет реализован за такой короткий срок.

Главный вывод, который я сделал для себя: программист в случае использования AI‑инструментов — это как дирижер. Он может не уметь играть на каких‑то инструментах, но он должен хорошо понимать музыку и точно знать, что ему нужно получить от музыкантов. Если этого понимания нет, то ничего хорошего не выйдет.

Просьба к нейросети «напиши хорошую программу» вовсе не гарантирует, что понятие хорошего результата у AI и у вас будут одинаковыми ?

Мне нравится этот мем
Мне нравится этот мем

Второй важный вывод. AI в текущем виде еще не так хорош. Но как мне кажется это только самое начало и этот инструмент точно займет свое место в корпоративной среде. Будущее уже наступило.

Современные инструменты — AI, Cursor — позволяют существенно ускорить и упростить разработку ПО, особенно для задач, связанных с обработкой неструктурированных данных. Однако автоматизация не отменяет необходимости в хорошем проектировании, тестировании и ревью.

Надеюсь, мой опыт будет полезен тем, кто планирует внедрять подобные решения в своих компаниях.

Если вы работаете с корпоративными данными, интегрируете RAG или строите внутренние API — не бойтесь экспериментировать с AI и современными IDE. Делитесь своим опытом, задавайте вопросы в комментариях и не забывайте про тесты и безопасность!

Планы на будущее

Этот кейс с созданием Text Extract API — лишь первый шаг на пути интеграции нейросетей в наши корпоративные решения. Лично я вижу большой потенциал в использовании RAG для повышения эффективности работы в нашем решении. Следующий шаг по плану включает интеграцию этого API в другой сервис, который станет основой для полноценного RAG‑решения. Этот будущий сервис сможет не только извлекать текст, но и проводить семантический поиск по базе знаний, формировать базы знаний из файлов и предоставлять контекст для нейросети и генерировать максимально релевантные ответы на заявки клиентов.

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

P. S. Если вам интересны детали реализации, архитектурные решения или примеры кода — пишите, с радостью поделюсь дополнительными материалами и отвечу на вопросы! Github проекта.

© 2025 ООО «СОФТОНИТ»

Комментарии (4)


  1. bitrix24ru
    08.07.2025 14:55

    Очень подробно изложил, делал подобное в начале года + данные до этого собирал. А если Авито не отдает телефон и пользователь звонит по телефону? Да и во сколько обошлось в целом?


    1. Diversus Автор
      08.07.2025 14:55

      Спасибо за обратную связь, но я не совсем понимаю о чем вы ))) В статье вообще нет упоминания Авито и телефонных звонков.
      Что же касается финансового вопроса, то специально не считал. Но я думаю не так много 20$ Cursor и модели где то еще на 50. Это я прям с запасом взял, скорее всего меньше.


  1. Lyrkchan
    08.07.2025 14:55

    Только в RAG всё же не происходит "обучение модели", это важный аспект.

    К слову, я делал тоже самое, но кроме .zip и прочего, а для OCR я использовал кроме tesseract ещё simpletex api. Делал по заказу одного ху~.., кхм, "бизнесмена": по знакомству начал с ним работать, а спустя месяц работы он отказался оплачивать хоть сколько-то. Далее я забросил проект: очевидно ничего не скидывал этому существу, но всё равно обидно ведь в целом я пошёл на такое сомнительное рискованное сотрудничество из-за жёсткой нужды в деньгах. Кстати хабром я пользуюсь не особо давно, и уж тем более не пишу посты/комментарии. В общем мне хочется узнать: было бы интересно если бы я выложил полностью историю как меня нагрел недобизнесмен, фаундер одной переводческой компании? Было бы это легитимно? Я имею ввиду в рамках правил хабра. И я бы наверное даже указал конкретные имена, название компании и даже выложил бы переписку чтобы подпортить репутацию данному существу.


    1. Diversus Автор
      08.07.2025 14:55

      Хорошее замечание про обучение. Это действительно моя оговорка. Все выглядит так, что мы модель как будто бы обучили, но это не так. Мы просто подсовываем ей нужный контекст в момент вопроса пользователя. Вот и вся магия.

      Что касается вашей ситуации, то тут сложно что-то комментировать.