Подбор
Сервис подбора до трёх event-подрядчиков (ведущий, фотограф, зал, флорист и другие) по городу, дате, формату, категории и бюджету.
О проекте
Команда: Steppe Tech
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Сервис подбора до трёх event-подрядчиков (ведущий, фотограф, зал, флорист и другие) по городу, дате, формату, категории и бюджету. Каждый выбор объясняется, а поверх детерминированного движка работает ИИ-агент, который понимает запрос свободным текстом.
Как устроено
Движок на стандартной библиотеке Python нормализует запрос и отбирает кандидатов жёсткими фильтрами (город, категория, занятость на дату, формат, бюджет, язык, часы), сохраняя все причины отказа. Прошедших он ранжирует по 5 критериям (смысл описания 35%, запас по бюджету 30%, язык 15%, часы 10%, надёжность данных 10%) и считает «эффект даты». Агент на OpenAI разбирает фразу и вызывает движок как инструмент, при пустом результате делает до двух альтернативных поисков, а каждое число в его совете сверяется с данными движка. Работает через веб-интерфейс, JSON API и CLI.
Ключевые решения
- взвешенное ранжирование
- жёсткие фильтры
- function calling
- проверка чисел в ответе
- поиск альтернатив по дате и бюджету
- словарь основ слов
Метрики
Подбор без ИИ <1 мс, ИИ-агент 2–7 с; 27 юнит-тестов; 66 профилей, 17 категорий
Особенности
Модель не может добавить подрядчика или выдумать цену: карточки и их порядок строит детерминированный движок, а схема инструмента разрешает только значения из каталога. Сервис различает три исхода, включая «кандидаты есть, но никто не подходит», и для каждого кандидата называет причины отказа и ближайшие свободные даты. Внешних pip-зависимостей нет.
Стек
Python · стандартная библиотека · HTML/JavaScript
Модели
gpt-5.4-mini (OpenAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-7c6720cb-steppe-tech.
README
README.md- Что делает проект
«Подбор» от команды Steppe Tech помогает заказчику выбрать event-подрядчика: ведущего, фотографа, банкетный зал, флориста и других. Заказчик указывает город, дату, тип события, категорию и бюджет. Длительность и язык можно добавить по желанию. Сервис возвращает не длинный список, а до трёх подрядчиков. Каждый выбор объяснён фактами из профиля: цитатой из описания, ценой и её долей в бюджете, языком, часами работы и отличием от двух других карточек.
Запрос можно написать обычным текстом, например «свадьба в Алматы 14 ноября, бюджет 500к, ведущий на казахском». ИИ-агент разбирает фразу, сам запускает подбор и даёт короткий совет. Если никто не подошёл, агент ищет вариант на соседней дате или с другим бюджетом.
Сервис честно говорит, когда подходящих меньше трёх или нет совсем, и объясняет причину. Он различает три исхода:
- Подобрали. Показаны до трёх карточек. Если их меньше трёх, сервис объясняет почему.
- В этом городе такой категории нет. Сервис называет города, где она есть, а при опечатке предлагает похожие категории.
- Кандидаты есть, но никто не подходит. Для каждого кандидата названы все причины отказа, а также ближайшие свободные даты и бюджет, при котором кто-то подошёл бы.
Бронирования и заявок в сервисе нет, он только рекомендует.
- Что реализовано
- ИИ-агент на OpenAI. Понимает запрос обычным текстом и сам вызывает движок подбора как инструмент. При пустом результате он делает до двух дополнительных поисков. Если данных не хватает, агент задаёт один уточняющий вопрос.
- Проверка фактов в советах ИИ. Каждое число в совете сверяется с данными движка. Если число не сошлось, вместо совета показывается текст движка. Альтернативный поиск явно помечается, поэтому агент не выдаст вариант дороже бюджета за подходящий.
- Жёсткие фильтры. Город, категория, занятость на дату, формат события, бюджет, язык и максимум часов. Занятые на дату отсекаются во всех категориях, включая площадки и отели.
- Прозрачное ранжирование. В каждой карточке видны итоговый балл и шкала по каждому критерию с его весом.
- Эффект даты. Сервис называет подрядчиков, которые вошли бы в тройку, но заняты именно в выбранный день. Поэтому видно, почему выдача меняется от даты к дате.
- Метка происхождения профиля. Бейдж показывает, реальный это профиль или синтетический. Отдельно помечено, если город или цену проставили при подготовке данных.
- Три способа работы. Веб-интерфейс, JSON API и командная строка.
- Готовые сценарии. Пять демо-запросов подбираются автоматически под загруженные данные и запускаются в один клик.
- Детерминизм движка. Одни и те же параметры всегда дают одну и ту же выдачу.
- Устойчивость к ошибкам. Некорректный ввод получает понятное сообщение, а не падение сервера.
- Тесты. 27 юнит-тестов покрывают требования задачи, загрузку данных и ИИ-агента.
- Технологии и архитектура
Проект написан на Python 3.10+ и использует только стандартную библиотеку. Устанавливать пакеты через pip не нужно. ИИ-агент работает через OpenAI API на модели gpt-5.4-mini. Интерфейс сделан одной HTML-страницей на чистом JavaScript.
Модули проекта:
- podbor/data.py загружает данные из CSV, XLSX и JSONL, понимает русские заголовки и нормализует поля.
- podbor/engine.py выполняет подбор: проверку запроса, фильтры, ранжирование, объяснения и выбор исхода.
- podbor/ai.py содержит ИИ-агента: разбор текста, вызов движка как инструмента и проверку фактов.
- podbor/server.py запускает HTTP-сервер со страницей и API.
- podbor/cli.py реализует командную строку.
- podbor/text.py склоняет русские слова и форматирует деньги и даты.
- podbor/scenarios.py подбирает демо-сценарии под загруженные данные.
Подбор идёт по шагам:
- Запрос проверяется и нормализуется: регистр, буква «ё», формат даты.
- Отбираются кандидаты нужной категории в нужном городе.
- К каждому кандидату применяются жёсткие фильтры, и все причины отказа сохраняются.
- Прошедшие ранжируются, и остаются три лучших.
- Выдача пересчитывается без учёта занятости, чтобы показать эффект даты.
- Для каждой карточки строится объяснение с учётом двух соседних.
Ранжирование использует пять критериев:
┌────────────────────────────────┬─────┐ │ Критерий │ Вес │ ├────────────────────────────────┼─────┤ │ Смысл описания и специализация │ 35% │ ├────────────────────────────────┼─────┤ │ Запас по бюджету │ 30% │ ├────────────────────────────────┼─────┤ │ Язык │ 15% │ ├────────────────────────────────┼─────┤ │ Часы на площадке │ 10% │ ├────────────────────────────────┼─────┤ │ Надёжность данных │ 10% │ └────────────────────────────────┴─────┘
ИИ-агент работает поверх движка, а не вместо него. Модель понимает запрос и решает, какие поиски сделать. Карточки, их порядок и объяснения всегда строит движок. Поэтому на одни и те же параметры выдача не меняется, а модель не может добавить подрядчика или выдумать цену. Схема инструмента разрешает только города, категории, форматы и языки из каталога.
- Порядок установки и запуска
Нужен Python 3.10 или новее.
git clone https://github.com/BAITC-Hacks/hack-7c6720cb-steppe-tech.git cd hack-7c6720cb-steppe-tech
Для ИИ-агента создайте в корне проекта файл .env. Файл исключён из git. Без него работает всё, кроме ИИ.
OPENAI_API_KEY=sk-...
Запуск веб-интерфейса:
python -m podbor.server
Затем откройте в браузере http://127.0.0.1:8000. На Windows лучше открывать именно этот адрес, а не localhost: с localhost каждый запрос ждёт около двух секунд.
Командная строка:
python -m podbor.cli --city Алматы --date 2026-11-14 --format свадьба --category Ведущий --budget 500000 python -m podbor.ai "той 5 декабря в Алматы, нужен флорист, бюджет 250 тысяч"
- Пример проверки
Все обязательные сценарии запускаются одной командой:
python scripts/demo.py
Скрипт прогоняет пять сценариев: плотная категория, тот же запрос на другую дату, редкая категория, категории нет в городе и кандидаты есть, но никто не подходит. Потом он повторяет каждый сценарий пять раз и проверяет, что выдача не меняется.
Тесты запускаются так:
python -m unittest discover -s tests -v
Для проверки в браузере есть быстрые ссылки. Адрес http://127.0.0.1:8000/#s1 сразу запускает первый сценарий. Адрес с окончанием #ask=текст запроса сразу отправляет текст ИИ-агенту.
Пример работы агента на запросе «той 5 декабря в Алматы, флорист, бюджет 250 тысяч»:
- На 5 декабря оба флориста в Алматы заняты, подходящих нет.
- Агент сам ищет на 1 декабря и находит подходящего флориста.
- Агент советует этого флориста и указывает, что это другая дата. Совет прошёл проверку фактов.
Ответ через API можно получить так:
curl -X POST http://127.0.0.1:8000/api/recommend -H "Content-Type: application/json"
-d '{"city":"Алматы","date":"2026-11-14","event_format":"свадьба","category":"Ведущий","budget":500000}'
Подбор без ИИ занимает меньше миллисекунды. Запрос к ИИ-агенту занимает от 2 до 7 секунд, это укладывается в лимит в 10 секунд.
- Используемые данные и внешние сервисы
Основной источник данных — анонимизированный датасет хакатона. Он лежит в репозитории в файле data/hackathon dataset anonymized .csv.
┌──────────────────────┬──────────────────────────────┐ │ Показатель │ Значение │ ├──────────────────────┼──────────────────────────────┤ │ Профилей │ 66 │ ├──────────────────────┼──────────────────────────────┤ │ Из них синтетических │ 13 │ ├──────────────────────┼──────────────────────────────┤ │ Категорий │ 17 │ ├──────────────────────┼──────────────────────────────┤ │ Городов │ 3: Алматы, Астана, Зарубежье │ ├──────────────────────┼──────────────────────────────┤ │ Окно календаря │ с 23.09.2026 по 31.12.2026 │ └──────────────────────┴──────────────────────────────┘
В репозитории также есть демо-набор data/demo-dataset.jsonl из 66 синтетических профилей с той же схемой. Он создан скриптом с фиксированным seed и нужен, если датасета хакатона нет. Можно подключить и свою таблицу в CSV, XLSX или JSONL: достаточно положить её в папку data/ или указать путь в переменной PODBOR_DATA.
Внешний сервис один: OpenAI API, он нужен только ИИ-агенту. Агенту отправляются текст запроса и сжатые результаты подбора: имена из каталога, цены и причины отказа. Движок, форма, API подбора и командная строка в сеть не ходят и работают без ключа.
- Известные ограничения
- Совет ИИ проверяется только по числам. Имена модель берёт из результатов подбора, но код их отдельно не сверяет.
- Совет ИИ может слегка меняться между запусками. Формулировка и выбор альтернативного поиска зависят от модели. Карточки на одни и те же параметры всегда одинаковы.
- Описания подрядчиков сопоставляются по словарю основ слов. Перефразирования вне словаря сервис не находит. Например, «проводы невесты» без слова «узату» не распознаются.
- Веса ранжирования подобраны вручную. Данных о том, кого заказчики выбирают на самом деле, нет.
- Бюджет относится к одному подрядчику. Сравнивается только цена «от», а итоговая цена может оказаться выше.
- Профили без цены, форматов или языков не отсекаются. Пробел отражается в тексте карточки и снижает балл.
- Занятость известна только с 23.09.2026 по 31.12.2026. Для дат вне этого окна сервис предупреждает, что занятость неизвестна.
- Склонения прописаны вручную. Для нового города текст будет корректным, но более казённым.
- Судьям без своего ключа OpenAI ИИ-агент недоступен. Остальной сервис работает полностью.
Планы развития: эмбеддинги для поиска по смыслу описаний, разметка описаний через LLM с кешированием, диалог с агентом поверх готового подбора, подбор нескольких подрядчиков на одну дату и настройка весов по реальным выборам заказчиков.
- Ссылка на развёрнутую версию
Развёрнутой версии пока нет. Сервис можно развернуть на любом хостинге с Python 3.10+ без сборки и установки пакетов:
python -m podbor.server --host 0.0.0.0 --port $PORT
Ключ OpenAI на хостинге задаётся переменной окружения OPENAI_API_KEY.
Репозиторий: https://github.com/BAITC-Hacks/hack-7c6720cb-steppe-tech
Авторы коммитов
История коммитов
- 2026-09-23 17:46Add files via uploaddiwarti
- 2026-09-23 17:46Delete README.mddiwarti
- 2026-09-23 17:45Delete README (1).mddiwarti
- 2026-09-23 17:44Update README.mddiwarti
- 2026-09-23 17:40Add files via uploaddiwarti
- 2026-09-23 17:30ИИ-агент: явно помечать альтернативный поиск, чтобы совет не выдавал вариант дороже бюджета за подходящийar1anbek
- 2026-09-23 17:27ИИ-агент: запрос текстом, поиск альтернатив, проверка фактовar1anbek
- 2026-09-23 16:29Update projectD1ret1
Все коммиты (10)
- 2026-09-23 15:00Initial commit: podbor vendor recommendation servicear1anbek
- 2026-09-23 14:58Add files via uploadar1anbek
Структура репозитория (20 файлов)
.gitignore README.md data/demo-dataset.jsonl data/hackathon dataset anonymized .csv data/hackathon dataset preview.html podbor/__init__.py podbor/ai.py podbor/cli.py podbor/data.py podbor/engine.py podbor/scenarios.py podbor/server.py podbor/text.py podbor/xlsx.py scripts/demo.py scripts/make_demo_data.py static/favicon.svg static/index.html tests/test_ai.py tests/test_engine.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.