Подписывайтесь:

Блог AST-SoftPro

Как одна боль рекрутера превратилась в ATS-систему с ИИ: от ручного подбора к трёхроликовому продукту

24.06.2026 19 мин чтения
Как одна боль рекрутера превратилась в ATS-систему с ИИ: от ручного подбора к трёхроликовому продукту

Введение

Рынок систем отслеживания кандидатов (ATS) в 2025 году превысил 7,4 млрд долларов, а к 2035 году, по прогнозам, достигнет 15,5 млрд. При этом на практике многие рекрутеры и HR-отделы до сих пор работают без какой-либо структурированной системы — вакансии публикуются вручную, резюме приходят в мессенджеры, сопоставление кандидатов с требованиями происходит в голове, а соискатели вынуждены самостоятельно мониторить новые вакансии и повторно обращаться.

В этой статье рассказана история создания системы ItMatch ATS — от конкретной боли одного IT-рекрутера до многопользовательской платформы с тремя ролями, адаптивным резюме и локальным ИИ. Мы рассмотрим архитектурные решения, выбор моделей, алгоритм матчинга и компромиссы между локальным развёртыванием и SaaS-режимом.

💡 История показывает, что реальные потребности пользователей часто не покрываются готовыми решениями — и именно этот разрыв между «есть» и «нужно» становится точкой входа для разработки.

Отправная точка: ручная работа рекрутера

Всё началось с практической ситуации. IT-рекрутеру было отправлено резюме под конкретную вакансию. После общения с ним картина оказалась типичной для многих специалистов по подбору:

  • Вакансии публикуются на hh.ru и в соцсетях вручную

  • Резюме приходят в личные сообщения, на почту, в мессенджеры

  • Сопоставление кандидата с вакансией происходит визуально — рекрутер читает резюме и сравнивает с требованиями в уме

  • База кандидатов отсутствует — каждое резюме обрабатывается как разовое событие

  • Собеседования организуются через календари и сообщения, без единой воронки

  • Соискатели не получают обратной связи и не видят новые вакансии — приходится мониторить площадки самостоятельно и обращаться повторно

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

⚠️ Типичная ошибка при автоматизации HR-процессов — начинать с покупки готовой ATS и пытаться подогнать процессы под систему. Эффективнее сначала описать реальные боли, а затем выбрать или создать инструмент, который решает именно их.

Архитектура системы

Технологический стек

Система построена на проверенном стеке, который позволяет быстро итерировать функциональность:

Компонент Технология Назначение
Веб-фреймворк Flask Маршрутизация, обработка запросов
ORM SQLAlchemy Работа с базой данных
БД SQLite (с миграциями) Хранение данных, возможность миграции на PostgreSQL
Фронтенд Jinja2 + Bootstrap 5 Шаблоны, адаптивный UI
ИИ-ядро OpenAI-compatible API Парсинг резюме/вакансий, генерация тестов, адаптация резюме
Запуск Docker + Gunicorn Контейнеризация, продакшн-сервер
Безопасность Flask-WTF, Flask-Limiter CSRF-защита, rate limiting

Выбор Flask вместо Django был продиктован гибкостью — модульная структура с blueprint'ами позволяет добавлять функциональность без раздувания проекта. SQLite на старте упрощает разработку и развёртывание, при этом архитектура допускает переход на PostgreSQL через Alembic по мере роста нагрузки.

Модульная структура

Проект разделён на 20 маршрутов (blueprint'ов) и более 40 сервисных модулей:

recruter/
├── app.py              # Точка входа, регистрация blueprint'ов
├── config.py           # Конфигурация, загрузка .env
├── extensions.py       # Инициализация расширений Flask
├── migrate.py          # Миграции схемы БД
├── routes/             # 20 blueprint'ов (HTTP-слой)
│   ├── auth.py         # Авторизация, роли
│   ├── candidates.py   # CRUD кандидатов
│   ├── vacancies.py    # CRUD вакансий
│   ├── matching.py     # Матчинг
│   ├── imports.py      # LLM-импорт
│   ├── pipeline.py     # Канбан-воронки
│   ├── assessments.py  # Тестирования
│   ├── resume_variants.py  # Адаптация резюме
│   └── ...             # interviews, comments, notifications и др.
├── services/           # 40+ сервисных модулей (бизнес-логика)
│   ├── llm_importer.py      # Парсинг через LLM
│   ├── matcher.py           # Алгоритм матчинга
│   ├── resume_adapter.py    # Адаптация резюме
│   ├── github_public.py     # Анализ GitHub
│   ├── notifications.py     # Уведомления
│   └── ...
├── models/             # Модели SQLAlchemy
├── templates/          # Jinja2-шаблоны
└── static/             # CSS, JS, изображения

💡 Разделение на routes (HTTP) и services (бизнес-логика) — минимальная, но эффективная граница. Она позволяет тестировать логику без запуска веб-сервера и упрощает рефакторинг.

ИИ-ядро: парсинг и матчинг

LLM-импорт резюме и вакансий

Одна из ключевых функций системы — автоматический парсинг неструктурированных текстов (резюме, описания вакансий) в структурированные данные через LLM. Вместо регулярных выражений и шаблонного парсинга используется JSON Schema:

# Упрощённая схема для импорта кандидата
schema = {
    "name": "string",
    "email": "string",
    "direction": "backend|frontend|mobile|devops|data|ml|qa",
    "level": "junior|middle|senior",
    "experience_years": "string",
    "skills": ["React", "TypeScript", "Python"],
    "work_history": [
        {
            "company": "string",
            "position": "string",
            "period_start": "2020-03",
            "period_end": "2024-01",
            "description": "string",
            "achievements": ["string"]
        }
    ]
}

LLM получает текст резюме, промпт с описанием полей и JSON Schema, и возвращает структурированный JSON. Система дополнительно нормализует направление, уровень и опыт на сервере, что снижает зависимость от качества вывода модели.

Важный аспект — поддержка fallback: если модель не поддерживает json_schema (например, старые версии локальных моделей), система автоматически переключается на json_object или необработанный режим.

Алгоритм матчинга

Матчинг кандидатов с вакансиями реализован как детерминированный алгоритм с прозрачным scoring (0–100 баллов):

Критерий Макс. баллы Логика
Обязательные навыки 60 Полный балл, если опыт кандидата ≥ требуемого; половина балла, если навык есть, но опыт меньше
Опциональные навыки 25 Аналогично обязательным
Уровень (junior/middle/senior) 8 +8 точное совпадение, +4 смежный уровень
Формат работы 4 Совпадение remote/office/hybrid
Общий опыт 3 Опыт кандидата ≥ порогового для уровня вакансии

Алгоритм также учитывает совместимость направлений: backend-разработчик может подойти на vacancy в direction «fullstack», но не на «data science».

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

⚠️ Использование LLM для парсинга — это первый этап. Второй этап — валидация и нормализация на сервере. Без серверной валидации ошибки модели (галлюцинации, пропуск полей) попадут в базу данных, и их исправление обойдётся дороже, чем первоначальная проверка.

Эволюция: от рекрутинга к трёхроликовому продукту

Фаза 1: Инструмент для рекрутера

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

Фаза 2: Воронки и адаптация резюме

Вторая фаза добавила:

  • Канбан-воронки — 8 этапов от «Новый» до «Принят»/«Отказан» с историей переходов

  • Адаптацию резюме — соискатель загружает базовое резюме, а система генерирует адаптированную версию под конкретную вакансию, выделяя релевантные навыки и опыт

  • Собеседования — планирование, фидбек (оценка 1-5 по техническим и soft skills, рекомендация)

  • Комментарии — внутренние заметки к кандидатам и вакансиям

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

Фаза 3: Три роли и многопользовательский режим

Текущая архитектура поддерживает три персоны:

Роль Описание Ключевые функции
Рекрутер (агентство) Подбор персонала на аутсорс Воронки, матчинг, импорт, оценки, адаптация резюме
HR компании (работодатель) Внутренний подбор Вакансии, воронки, интервью, аналитика
Соискатель Поиск работы Адаптация резюме, отслеживание вакансий, тестирования

Каждая роль видит собственный дашборд и набор функций. Организации (workspaces) обеспечивают изоляцию данных между агентствами, компаниями и личными пространствами соискателей.

Локальные LLM: выбор и тестирование

Оборудование и модели

Система спроектирована так, что ИИ-ядро работает через OpenAI-compatible API, что позволяет подключать как облачные, так и локальные модели. На практике были протестированы следующие конфигурации:

Модель Платформа Наблюдения
t-lite-it-2.1 Локальный сервер, RTX 4070 12 ГБ Основная рабочая модель, стабильный парсинг с JSON Schema
Qwen 3.5 9B Локально Хорошее качество для размера, но требует строгого промпта для JSON
Gemma 4 31B Локально Высокое качество, но требует больше VRAM (квантование необходимо)
DeepSeek V4 Flash Локально Быстрый инференс, подходит для быстрых задач

RTX 4070 с 12 ГБ VRAM — это минимальная конфигурация для комфортной работы с квантованными моделями среднего размера (7-31B параметров). Формат GGUF через llama.cpp позволяет запускать модели с различными уровнями квантования (Q4_K_M, Q6_K, Q8_0), балансируя между качеством и потреблением памяти.

💡 Квантование моделей — компромисс между качеством и ресурсами. Для задач парсинга резюме (извлечение структурированных данных) разница между Q4_K_M и Q8_0 часто незначительна, но экономия VRAM позволяет работать с более крупными моделями. Для генеративных задач (адаптация резюме, планы развития) качество квантования влияет на читаемость текста сильнее.

Локально vs SaaS

Архитектура системы поддерживает оба режима:

Локальное развёртывание:

  • Полная приватность данных — резюме и вакансии не покидают периметр

  • Нет зависимости от API-лимитов и стоимости токенов

  • Требует GPU-оборудования и настройки инфраструктуры

  • Обновление моделей — ручная замена весов

SaaS-режим (облачные LLM):

  • Не требует GPU-инфраструктуры

  • Доступ к самым актуальным моделям

  • Стоимость зависит от объёма запросов

  • Данные передаются внешнему провайдеру

⚠️ При работе с персональными данными соискателей (резюме, контакты, опыт работы) локальное развёртывание — не просто вопрос стоимости, а требование соответствия законодательству о защите персональных данных. Передача ПД внешним API-провайдерам требует отдельного правового обоснования и согласия субъектов данных.

Воронки подбора и kanban

Система реализует 8-этапную воронку с историей переходов:

Новый → HR-скрининг → Тех. интервью → Финальное интервью → Оффер
                                                    ↓
                                    Принят / Отказ компании / Отказ кандидата

Каждый переход фиксируется в ApplicationStageHistory с указанием автора, времени и предыдущего этапа. Это позволяет анализировать скорость прохождения воронки, выявлять узкие места и оценивать эффективность рекрутеров.

Практические аспекты развёртывания

Docker-развёртывание

cd /app/Recruter
docker compose up --build

Приложение доступно на http://localhost:5000. Для подключения LLM задаётся переменная окружения:

$env:OPENAI_API_KEY="your_api_key"
# или для локальной модели:
$env:LLM_BASE_URL="http://localhost:8080/v1"

Nginx как reverse proxy

При развёртывании за nginx необходимо учитывать таймауты для LLM-запросов (генерация тестов и планов развития может занимать от нескольких секунд до минут):

proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
send_timeout 3600s;

Без увеличения proxy_read_timeout длинные ответы от LLM обрываются с ошибкой 504 Gateway Time-out, хотя бэкенд ещё обрабатывает запрос.

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

Система включает несколько уровней защиты:

  • CSRF через Flask-WTF с токеном в заголовке X-CSRFToken для fetch-запросов

  • Rate limiting через Flask-Limiter (в памяти или Redis)

  • Демо-аккаунты с блокировкой записи — публичный просмотр без риска изменения данных

  • Обязательный онбординг перед использованием системы

  • Изоляция организаций — данные разных workspace не пересекаются

⚠️ При развёртывании в продакшене обязательно замените SECRET_KEY на случайную строку, настройте rate limiting на /auth/login и используйте HTTPS. Поверхностное копирование конфигурации из репозитория может привести к уязвимостям — стоит проверить реализацию на соответствие OWASP Top 10.

Перспективы и дальнейшее развитие

Текущие направления развития системы включают:

  1. Надёжное хранение файлов — привязка исходных файлов резюме и вакансий к записям в БД с санитизацией путей и защитой от path traversal

  2. Документы заказа — модель OrderDocument для отслеживания ТЗ и технических требований к вакансиям

  3. Пагинация — переход от .all() к paginate() на списках кандидатов и вакансий

  4. Alembic — замена ручной миграции на версионируемую систему для поддержки PostgreSQL

  5. Индексы — добавление индексов на часто фильтруемые поля (is_active, stage, scheduled_at) для ускорения запросов при росте данных

Заключение

История ItMatch ATS иллюстрирует типичный путь от узкой проблемы к универсальному продукту. Исходная задача — автоматизация ручного сопоставления резюме с вакансиями — привела к созданию многопользовательской системы с тремя ролями, ИИ-парсингом, адаптивным резюме и канбан-воронками.

Ключевые выводы:

  • Локальные LLM на потребительском оборудовании (RTX 4070 12 ГБ) способны решать задачи парсинга HR-документов с качеством, достаточным для практического использования

  • Архитектура с OpenAI-compatible API обеспечивает гибкость — переключение между локальными и облачными моделями без изменения бизнес-логики

  • Три роли (рекрутер, работодатель, соискатель) расширяют аудиторию и делают систему ценной для всех участников процесса подбора

  • Адаптация резюме — функция, которая закрывает реальную боль соискателей и повышает релевантность откликов

💡 Выбор инструмента — лишь половина задачи. Вторая половина — корректная реализация с учётом безопасности персональных данных, валидации ввода, масштабируемости запросов и соответствия законодательству. Для продакшн-решений в области HR рекомендуется привлечение специалистов с опытом — это снижает риски ошибок безопасности и архитектурных просчётов, которые обнаружатся только при росте нагрузки.

Рынок ATS продолжает расти (прогноз — $15,5 млрд к 2035 году), и ниша систем с локальным ИИ и многопользовательским режимом остаётся открытой. Системы, которые сочетают приватность данных, гибкость развёртывания и практическую ценность для всех участников процесса подбора, будут иметь преимущество в конкурентной среде.


Источники:

AI-Помощник