Career Quest
Навигатор развития сотрудника Halyk Bank: рекомендует 1–3 учебные активности под требования следующего грейда с объяснением, есть AI-наставник…
О проекте
Команда: NovaAI
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Доведённый продукт
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Навигатор развития сотрудника Halyk Bank: рекомендует 1–3 учебные активности под требования следующего грейда с объяснением, есть AI-наставник, личный прогресс, демо-магазин наград и HR-аналитика дефицитов компетенций.
Как устроено
Импорт официального датасета (employees, events, skills, activity_history) с валидацией. Для каждого события score = Σ gap × effective_gain × criticality × acceptance, где gap берётся из требований роли и грейда, critical_skills имеют вес 3, acceptance сглажен по Лапласу по истории навыка и формата. Учитываются prerequisites, будущие сессии и исключение обязательных и пройденных активностей. AI-коуч в режиме только чтения опирается на факты профиля (prompts/coach.md), есть офлайн-режим. Роли employee/HR/manager с разграничением доступа, SQLite, интерфейс на KK/RU/EN.
Ключевые решения
- скоринг разрыва навыков с весами критичности
- сглаживание Лапласа по истории участия
- проверка prerequisites
- RBAC по токенам
- i18n KK/RU/EN
Особенности
Рекомендация не сводится к «прокачай самый слабый навык»: отдельный тест test_jury_case_no_minimum_skill_rule проверяет, что учитываются критичность и история отказов. Геймификация без публичных рейтингов, демо-Coins только за добровольное закрытие разрывов. В README честно разделены проверенный и ожидаемый эффект.
Стек
Python 3.12 · SQLite · React · TypeScript · Vite · pnpm · nginx · Docker Compose
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-7840be72-novaai.
README
README.mdCareer Quest · NovaAI
AI-навигатор развития сотрудника для HackAlem AI, кейс Halyk Bank. Приложение связывает обучение с требованиями следующего грейда: показывает 1–3 шага, объясняет выбор через разрыв навыков, критичность и историю участия, обновляет личный прогресс и предоставляет HR служебную аналитику. Публичных рейтингов сотрудников нет.
Зачем мы создали Career Quest
Сотрудник получает приглашения на курсы и напоминания о дедлайнах, но не всегда понимает, как конкретная активность поможет его карьере. Обучение превращается в формальность, добровольные мероприятия пропускаются, а HR видит отдельные результаты вместо понятной картины развития.
Наша цель — помочь сотруднику ответить на три вопроса: куда я расту, что сделать следующим и почему именно этот шаг важен сейчас. Для банка это способ связать каталог обучения с реальными дефицитами компетенций и сделать помощь HR адресной.
Как это работает для сотрудника
- Сотрудник видит свой профиль, личного персонажа и требования следующего грейда.
- Получает до трёх доступных активностей с объяснением: какой разрыв они закрывают, насколько навык важен для следующего уровня и что показывает история участия.
- Может обсудить рекомендацию с AI-наставником, который опирается на факты профиля.
- После выполнения видит рост соответствующих навыков и продвижение к цели.
- За добровольное закрытие разрывов получает личные демо-Coins и выбирает награду.
Например, самый слабый навык не обязательно является лучшим следующим шагом: если сотрудник неоднократно пропускал публичные выступления, а для Senior критичен System Design, алгоритм учитывает оба обстоятельства. Выбор не сводится к минимуму одного показателя. Точная проверка этого сценария описана ниже.
Персонаж — визуальное отражение собственного развития. Выбор аниме или футбольного стиля не влияет на навыки. Сотрудник не соревнуется с коллегами, а видит свои достижения и следующий доступный шаг.
Польза для Halyk Bank
| Для кого | Что даёт решение |
|---|---|
| Сотрудник | Понятную связь обучения с карьерой и объяснимый следующий шаг |
| HR | Срез дефицитных компетенций и признаки, по которым можно предложить помощь |
| Руководитель | Служебную картину развития своей команды в пределах разрешённого доступа |
| Банк | Основание для более адресного использования обучения и проверки его востребованности |
Категории наград «Для работы», «Для себя», «Для семьи и детей» связывают профессиональный рост с личными интересами сотрудника. Семейный поход в кино или мастер-класс — пример заботы о близких, а не отдельная игровая задача. Coins связаны только с добровольным развитием профессиональных навыков; обязательные процессы и публичность профиля не вознаграждаются. Все награды в текущей версии демонстрационные.
Ожидаемый эффект, который ещё нужно проверить в пилоте: рост завершения добровольных активностей и доли закрытых разрывов, более понятные карьерные шаги, возможное улучшение удовлетворённости сотрудников. Измерять предлагаем долю принятых рекомендаций, завершение добровольных активностей, изменение skill gaps и обратную связь о полезности объяснений. Рост eNPS, снижение оттока и экономию бюджета мы пока не заявляем как достигнутые результаты.
Быстрый запуск для жюри (Windows, без Docker)
Требуются Python 3.12+, Node.js 24 и pnpm 11. В корне репозитория один раз установить зависимости:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r backend/requirements.txt
pnpm --dir frontend install --frozen-lockfile
Затем запуск одной командой:
.\start.bat
Дождитесь строки Career Quest is ready: http://127.0.0.1:... и откройте именно этот
адрес. Порты выбираются автоматически; занятому порту находится замена.
Окно нужно оставить открытым. Ctrl+C останавливает только запущенный им экземпляр.
После перезагрузки компьютера команду запуска нужно повторить.
Без локального .env используются демонстрационные аккаунты:
| Токен | Доступ |
|---|---|
demo-employee | Свой профиль E0028 |
demo-hr | HR-аналитика и импорт |
demo-manager | Служебные данные только E0028 |
demo-colleague | Получатель адресованной ему карточки E0029 |
Если настроен .env, действуют токены из него; переменные среды имеют приоритет.
Демо-токены предназначены для локальной проверки. Серверы слушают только 127.0.0.1.
Для Linux/macOS после установки зависимостей запуск: .venv/bin/python run.py.
Официальный набор и произвольный сотрудник
Для отдельной демонстрации официального набора, без изменения существующего прогресса:
.\start.bat --dataset examples/official --database .runtime/jury.sqlite3 --employee E0028 --offline
Для другого профиля остановить этот экземпляр и выполнить:
.\start.bat --database .runtime/jury.sqlite3 --employee E0030 --offline
Войти тем же employee-токеном. --employee привязывает аккаунт к ID на сервере при
запуске; браузер не может переключиться на чужой профиль. Подходит и для новых ID,
загруженных жюри. Если ID отсутствует, профиль не открывается; войдите HR и загрузите
соответствующий набор. --offline отключает внешний AI только для этого запуска.
--dataset требует отдельного --database. Набор загружается при создании новой
базы. Существующая база сохраняется: изменить её содержимое можно через HR-импорт.
По умолчанию база .runtime/career-quest.sqlite3; CQ_DB_PATH задаёт другой путь.
Ранее использовавшийся локальный сеанс может находиться в .runtime/qa.sqlite3.
Проверка основного сценария за 5 минут
- Запустить отдельную базу с официальным набором командой выше.
- Войти сотрудником. Проверить роль, грейд, навыки, историю, траекторию и дату среза.
- Раскрыть «Почему именно это?» у рекомендации: требования Senior, разрыв, критичность, история и оценка принятия формата показаны явно.
- Нажать «Демо: завершить активность». Навык растёт с учётом gain/max_level, траектория пересчитывается. Повторное завершение не даёт повторного роста.
- Открыть Halyk Store: за добровольное закрытие разрыва появились демо-Coins. Выбрать доступную награду, проверить сумму и подтвердить демо-обмен.
- Выйти и войти как HR. Проверить дефициты компетенций, обязательное обучение, фильтры «без рекомендованного шага» и стагнации, черновик персонального предложения.
- Переключить интерфейс KK/RU/EN. Нестандартные названия входного датасета остаются на исходном языке; уровень грейда не изменяется при переводе.
Магазин и демо-завершение доступны при DEMO_MODE=true (launcher включает этот режим по умолчанию, если переменная не задана). Это не подтверждение реального обучения.
Загрузка проверочных файлов жюри
Войти HR, выбрать четыре файла с исходными именами:
employees.json, events.json, skills.json, activity_history.csv.
Поддерживаются схема организаторов v1.0 и небольшой пример из data/.
ZIP напрямую не принимается. Лимит комплекта — 12 MiB, кодировка UTF-8, BOM допустим.
- «Проверить файлы» выполняет валидацию и показывает состав и дату среза без записи.
- «Заменить датасет» заменяет профили/историю, сбрасывает демо-Coins и обмены, отзывает выданные карточки. Предупреждение показано до подтверждения.
- Изменение файлов или ревизии между проверкой и импортом возвращает 409.
- Неизвестная ссылка, дубликат ID, навык 6, неверный CSV-статус или повреждённый JSON отклоняются; действующая база сохраняется.
Официальный комплект: 200 профилей, 40 мероприятий, 60 навыков, 2743 записи истории.
Дополнительные профили и история принимаются в той же схеме; количество не зафиксировано
на 200. Для просмотра нового сотрудника использовать --employee ID после импорта.
Менеджеры и токены не создаются из данных автоматически.
Датасет предоставлен только для хакатона. Репозиторий предназначен для участников
и жюри; комплект examples/official нельзя переносить в публичные материалы вне
разрешённого организаторами контура. README организаторов сохранены рядом с файлами.
Скоринг и обработка истории
Для навыка события:
gap = max(0, required(next_grade, current_role) - current)
effective_gain = min(gap, gain, max(0, max_level - current))
p_skill = (completed_skill + 1) / (attempts_skill + 2)
p_format = (completed_format + 1) / (attempts_format + 2)
acceptance = (p_skill + p_format) / 2
score_event = sum(gap * effective_gain * criticality * acceptance)
- Требования роли/грейда берутся из role_profiles. Вес critical_skills = 3, остальных = 1: это явно выбранные веса алгоритма.
- Учитываются роль, грейд, prerequisites и будущие сессии. self_paced не требуют даты сессии. mandatory и уже начатые курсы не рекомендуются как новые.
- Завершённые неповторяемые события исключаются; EV_036 допускает повторение.
- completed повышает оценку принятия; dropped/no_show/declined учитываются как незавершённые попытки. in_progress, overdue и обязательные активности не ухудшают оценку добровольного формата. При отсутствии истории действует сглаживание 0.5.
- Это эвристическая оценка, не калиброванная вероятность и не прогноз увольнения.
- Официальная дата расчётов — meta.as_of_date (2026-10-01). Навыки из профиля дополняются completed строго после last_review_date с ограничением max_level. Пересчёт происходит один раз при импорте исходного набора, а не при чтении базы.
- Цель — следующий грейд текущей роли. career_goal сохраняется, но траектория смены профессии пока не реализована. Для Lead используются требования Lead.
Почему это не выбор самого низкого навыка
Тест test_jury_case_no_minimum_skill_rule задаёт System Design=2, Public Speaking=2,
три no_show клуба и доступный EV_006. Приоритет получает System Design с учётом
требований Senior, критичности и истории.
На полном исходном наборе у E0028 System Design после пересчёта становится 3, а ряд курсов уже пройден. Поэтому первые рекомендации — Kubernetes in Practice, Cloud Certification Prep и Mentor Track. Мы не заставляем алгоритм выбирать System Design вопреки данным. Отдельный тест использует изменённую копию профиля.
AI-наставник
Скоринг выбирает мероприятия; LLM объясняет переданные факты и предлагает план.
Без API приложение работает в явно обозначенном режиме правил.
Для внешней модели скопировать .env.example в .env и заполнить локально:
OPENAI_API_KEY=YOUR_API_KEY
OPENAI_MODEL=gpt-6-luna
ALLOW_EXTERNAL_AI=true
Ключ не отправлять в чат, не писать в .env.example и не коммитить.
После изменения настроек перезапустить приложение без --offline.
Статус «LLM настроена» означает наличие настроек; успешный ответ помечается LLM.
Ошибка/таймаут провайдера даёт явно обозначенный резервный ответ по правилам.
Доступность модели и API-биллинг зависят от проекта владельца ключа.
Провайдер получает вопрос, до шести сообщений и факторы только своего профиля.
ID и сырая история автоматически не передаются. Текст вопроса может содержать то,
что написал пользователь. Используются Responses API, store=false, пустой список
инструментов. Это не обещание отсутствия хранения на стороне провайдера.
Промпт: backend/coach.py: PROMPT. Максимум 8с на генерацию, 3 параллельных запроса,
20 запросов/минуту на аккаунт в процессе. Диалог в нашей БД не сохраняется.
У чата нет API записи: он не подтверждает обучение, не изменяет навыки/Coins и не читает чужие профили. Текст LLM может ошибаться; рядом доступны исходные факторы. Официальная документация OpenAI.
HR, приватность и награды
Сотрудник видит свой профиль. HR — агрегаты, служебные ID/роль/грейд, статус следующего шага и обязательное обучение. Руководитель ограничен серверным MANAGER_ACCOUNTS_JSON. Личные уровни навыков, добровольная история и диалоги в служебную проекцию не входят. Сигнал стагнации — более шести календарных месяцев без completed; отсутствие истории не доказывает отсутствие обучения. «Три пропуска рекомендаций» применяется только при явном recommended=true в расширенном демо-CSV. assigned_by=manager/hr в официальном наборе не считается журналом AI-рекомендаций. Подбор ментора — черновик запроса, без выдуманного имени и без отправки сообщений.
Повторные обязательные назначения есть в официальной истории: показывается последнее назначение с индивидуальным due_date, старый completed не скрывает новую просрочку. Баллов за mandatory нет. Демо-награда = 100 Coins за закрытый уровень разрыва в добровольной активности. Импорт и старые завершения не начисляют Coins задним числом. Начисление и прогресс атомарны в SQLite. Повтор event_id не награждается; повтор request_id не списывает повторно. Транзакция защищает от одновременной двойной траты. Награды условные, настоящие сертификаты и банковские обязательства не создаются.
Добровольная карточка показывает только псевдоним, стиль и выбранные завершённые добровольные достижения конкретным зарегистрированным получателям. Уровни навыков, баланс, грейд и история не публикуются. Доступ можно отозвать; уже увиденное нельзя «забрать обратно». Рейтингов, наград за публичность и сравнения коллег нет.
Архитектура
| Компонент | Назначение |
|---|---|
| backend/dataset.py, official.py | Строгая валидация, адаптер официального формата |
| backend/engine.py | Скоринг, фильтры, прогресс |
| backend/main.py | FastAPI, роли, импорт, ревизии |
| backend/storage.py | SQLite, транзакции, постоянное состояние |
| backend/reporting.py, insights.py | HR/manager-проекции и сигналы поддержки |
| backend/coach.py | Чат, факты, опциональная LLM и fallback |
| backend/rewards.py, sharing.py | Личный кошелёк и адресный показ достижений |
| frontend/src | React + TypeScript + Vite, адаптивный CSS, KK/RU/EN |
| run.py, start.bat | Локальный запуск, свободные порты, проверка proxy |
Авторизация демо использует Bearer-токены в памяти вкладки, не URL/localStorage. В localStorage хранятся только язык и стиль. Секреты находятся в серверной среде/.env. .env читается как буквальные KEY=value, без исполнения команд и интерполяции.
Проверки и воспроизводимость
$env:ALLOW_EXTERNAL_AI="false"
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
.\start.bat --smoke --offline
Тесты используют отдельные временные SQLite. Они проверяют официальный набор,
пересчёт всех 200 профилей, кейс жюри, роли, ошибки импорта, ревизии,
повторное завершение, обмен и конкурентное списание, fallback AI и конфигурацию.
--smoke собирает интерфейс, запускает оба сервера, проверяет страницу и API через
proxy и останавливает свои процессы. Реальный внешний AI в тестах не вызывается.
Результаты последней проверки: docs/verification.md.
Диагностика: ERR_CONNECTION_REFUSED означает, что сервер по этому адресу не отвечает;
запустите start.bat и используйте новый напечатанный адрес. Если процесс завершился,
смотрите .runtime/backend-*.log и .runtime/frontend-*.log. При 409 обновите экран.
При ошибке токена используйте токен из серверной конфигурации, без кавычек и пробелов.
Docker (альтернатива)
docker compose up --build
Интерфейс: http://localhost:8080. Нужен работающий Docker Engine. В текущей среде контейнерный запуск не проверен; основной проверенный путь — start.bat без Docker.
Границы демо
Нет SSO, интеграции LMS, реальной выдачи наград и каталога конкретных менторов. Демо-кнопка имитирует выполнение доступной активности в дату среза и не доказывает посещение. Статус готовности по навыкам не гарантирует повышение. Карта навыков использует шкалы требований; радар 60 навыков не реализован. Защита агрегатов малых групп, промышленный аудит и нагрузочная проверка нужны перед банковским внедрением.
Ключевой бизнес-эффект — сделать связь обучения с карьерой понятной и дать HR инструмент помощи. Рост завершаемости, eNPS и снижение оттока пока гипотезы, а не измеренные результаты пилота.
Авторы коммитов
История коммитов
- 2026-09-23 16:48Merge pull request #1 from BAITC-Hacks/masterabilmnnsur
- 2026-09-23 16:37Explain project purpose and business valueadmin
- 2026-09-23 16:35Prepare submission docs and jury verificationadmin
- 2026-09-23 16:24Support official Career Quest datasetadmin
- 2026-09-23 16:11Add Halyk Store, local launcher and AI configurationadmin
- 2026-09-23 15:52Add Halyk Store and personal rewardsadmin
- 2026-09-23 15:38Fix login token validationadmin
- 2026-09-23 15:23Add read-only career coach and verify applicationadmin
Все коммиты (13)
- 2026-09-23 15:08feat: add trilingual UI and stagnation supportadmin
- 2026-09-23 14:53feat: redesign employee workspaceadmin
- 2026-09-23 14:46feat: add scoped manager access and employee training overviewadmin
- 2026-09-23 14:38feat: add validated imports, persistent progress and private card sharingadmin
- 2026-09-23 14:08feat: bootstrap Career Quest with explainable recommendationsadmin
Структура репозитория (67 файлов)
.dockerignore .env.example .gitattributes .gitignore README.md backend/Dockerfile backend/__init__.py backend/coach.py backend/config.py backend/dataset.py backend/engine.py backend/insights.py backend/main.py backend/official.py backend/reporting.py backend/requirements.txt backend/rewards.py backend/sharing.py backend/storage.py compose.yaml data/activity_history.csv data/employees.json data/events.json data/skills.json docs/verification.md examples/official/README.kz.md examples/official/README.md examples/official/README.ru.md examples/official/activity_history.csv examples/official/employees.json examples/official/events.json examples/official/skills.json examples/stagnation/activity_history.csv examples/stagnation/employees.json examples/stagnation/events.json examples/stagnation/skills.json frontend/.dockerignore frontend/Dockerfile frontend/index.html frontend/nginx.conf frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml frontend/src/Coach.tsx frontend/src/EmployeeWorkspace.tsx frontend/src/HrDashboard.tsx frontend/src/Rewards.tsx frontend/src/Sharing.tsx frontend/src/i18n.ts frontend/src/main.tsx frontend/src/style.css frontend/src/translations.json frontend/vite.config.js prompts/coach.md prompts/explanation.md run.py start.bat tests/test_api.py tests/test_coach.py tests/test_config.py tests/test_dataset.py tests/test_engine.py tests/test_insights.py tests/test_official.py tests/test_reporting.py tests/test_rewards.py tests/test_sharing.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.