Как LLM анализируют тендерную документацию: разбор пайплайна
- AI
- LLM
- Обработка документов
- Тендеры
Зачем вообще нужен такой пайплайн
Средняя компания, участвующая в тендерах, тратит десятки часов в неделю на чтение документации. Часть лотов не стоит времени, но понимаешь это только после того, как уже потратил час на разбор. Экономия на этом простом шаге: классический сценарий для LLM-пайплайна обработки документов.
В этой статье разберём архитектуру реального пайплайна, который мы реализовали в демо-проекте по анализу тендеров. Это инженерный разбор с техническими деталями: как устроены модули, почему приняты такие решения, где случаются ошибки и как мы их ловим на практике.
Шаг 1. Приём и нормализация документов
Тендерная документация приходит в виде архивов: PDF (часто со сканами), DOCX, XLSX, изредка HTML. Первая задача: привести всё это в единый текстовый поток с сохранением структуры.
Что мы делаем:
- PDF с текстовым слоем парсим через
pdfplumber. Он аккуратно сохраняет таблицы и разрывы абзацев, чего часто не хватает более простым библиотекам. - PDF без текстового слоя (сканы) прогоняем через Tesseract OCR с русскоязычной моделью. На этом этапе точность теряется: примерно 94–96% на качественных сканах и 80–85% на плохих.
- DOCX парсим через
python-docx. XLSX черезopenpyxl, отдельно сохраняя каждый лист. - Все документы склеиваются в один поток с пометкой источника: «из файла X, страница Y». Это критично для последующего цитирования: чтобы в сводке можно было сослаться на точное место.
Типичные ошибки. OCR может перепутать цифры на плохом скане, поэтому мы отдельно валидируем все числовые поля регулярками и, если проверка падает, помечаем поле как требующее ручной проверки.
Шаг 2. Извлечение ключевых полей с помощью LLM
Главный вопрос: как из текста на 200 страниц вытащить структурированные данные: требования к участникам, ТЗ, сроки, критерии оценки, размер обеспечения?
Можно было бы попытаться написать регулярные выражения под каждое поле, но на практике это работает только на очень стандартизованных документах. Реальные тендеры пишутся по-разному, термины различаются, структура плавает. LLM справляется с этим гораздо лучше.
Как устроен промпт:
- Для каждого ключевого поля свой промпт с чёткой постановкой:
«Найди в документе требования к опыту участника. Верни JSON с полями
years_of_experience,required_certifications,similar_projects. Если данных нет, верни null.» - В промпт передаётся релевантный фрагмент документа (а не весь текст целиком). Для этого предварительно делаем разметку разделов и передаём только «Раздел 1. Требования к участникам» + соседние страницы.
- На выходе LLM возвращает JSON. Мы валидируем его через Pydantic (или Zod, если бэкенд на TypeScript): если структура не соответствует ожидаемой, повторяем запрос с уточнением.
Почему не один большой промпт на все поля сразу. Мы так пробовали, и качество заметно падает. LLM начинает забывать одни поля ради других, или генерирует неконсистентный вывод. Разделение на специализированные промпты стабильнее и дешевле (меньше токенов на каждый вызов).
Шаг 3. Валидация извлечённых данных
LLM даёт первую версию. Дальше идёт проверка.
Что валидируем:
- Типы и форматы. Даты: в формат даты, суммы: в число, лицензии: в список строк.
- Диапазоны. Если модель вернула «срок подачи: 1 января 1900 года», это явно галлюцинация, и мы её ловим.
- Консистентность. Даты подачи должны быть раньше даты открытия конвертов. Размер обеспечения: это процент от начальной цены контракта, и он должен попадать в разумный диапазон.
Если валидация падает, поле помечается как «требует ручной проверки» и выводится отдельным блоком в интерфейсе: менеджер видит, что именно нужно перепроверить.
Шаг 4. Классификация релевантности
После извлечения полей нам нужно понять: стоит ли компании вообще участвовать в этом тендере? Здесь начинается задача классификации с бизнес-правилами поверх уже извлечённых данных.
Что мы учитываем:
- Профиль клиента. Коды ОКПД, регионы работы, размер контрактов, которые компания обычно выигрывает, специализация.
- Извлечённые поля. Сумма контракта, требования к опыту, сертификаты, обеспечение заявки.
- Исторические данные. Если компания уже участвовала в похожих тендерах и проигрывала по конкретным критериям, следующие аналогичные лоты снижают оценку.
На выходе категория лота: «стоит подавать» / «возможно» / «не стоит», плюс объяснение: почему именно такая оценка. Объяснение: это ключевой элемент доверия. Менеджер видит «не стоит: требуется лицензия ФСБ, у компании её нет» и сразу понимает, согласен он с оценкой или нет.
Шаг 5. Генерация сводки
Последний шаг: короткий отчёт на 1 страницу, который менеджер может прочитать за 2 минуты. Это делает LLM на основе уже извлечённых и валидированных данных.
Сводка содержит: суть тендера одним абзацем, ключевые требования, критичные риски, общую оценку релевантности и рекомендацию. Мы специально не просим LLM делать самостоятельный анализ, она работает только с готовыми структурированными данными, чтобы не галлюцинировать.
Что в итоге
Получается честно устроенная инженерная система из пяти шагов: парсинг → извлечение → валидация → классификация → сводка. Каждый шаг можно отлаживать, оценивать и улучшать отдельно. На нашем тестовом корпусе из 10 000+ документов такой пайплайн показывает точность извлечения ключевых полей около 92% и F1 классификации релевантности около 0.85.
Это примерно в 50–70 раз быстрее ручного анализа на один документ, и, что ещё важнее, качество стабильно: нет эффекта «после обеда менеджер устал и пропустил критичное требование».
Если у вас есть похожая задача по обработке документов (договоров, заявок, отчётов), запишитесь на AI-аудит. Разберём вашу ситуацию и скажем, подходит ли вам такой подход.