Career Quest
Веб-приложение и Telegram-бот с 1–3 обоснованными карьерными рекомендациями для сотрудника, HR-дашбордом с тепловой картой разрывов и AI-ассистентом…
О проекте
Команда: Nexon
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Веб-приложение и Telegram-бот с 1–3 обоснованными карьерными рекомендациями для сотрудника, HR-дашбордом с тепловой картой разрывов и AI-ассистентом с function calling (поиск ментора, симуляция по отделу).
Как устроено
Детерминированный recommender.py считает эффективные навыки, разрыв до грейда или цели и скор активности: закрытие разрыва, вес ×2 за критичность навыка и штраф за историю пропусков в данном формате. Он же оценивает срок до повышения по личному темпу. GPT-4o-mini (или NVIDIA NIM) только переводит готовые факты в текст на preferred_language, для него есть шаблонный fallback. Агент через OpenAI function calling вызывает find_mentor и simulate_department_impact, а каталог ID передаётся в системный промпт против выдуманных идентификаторов. Бэкенд на FastAPI, данные в памяти с догрузкой jury-файлов.
Ключевые решения
- многофакторный скоринг рекомендаций
- штраф за историю пропусков
- OpenAI function calling
- LLM-объяснитель с fallback
- Telegram-бот и Mini App
- ролевой доступ через заголовки
Особенности
Явно разобрана «ловушка жюри»: некритичный навык с максимальным разрывом не вытесняет критичный. Переключатель «Показать логику AI» показывает сырые веса скоринга. Есть HR-симуляция «что если назначить курс всему отделу».
Стек
Python · FastAPI · Pydantic · vanilla HTML/CSS/JS · Telegram Bot API · ngrok
Модели
OpenAI gpt-4o-mini · NVIDIA NIM
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-82404745-nexon.
README
README.mdCareer Quest — AI-навигатор развития
HackAlem AI 2026 · Halyk Bank case
Веб-приложение, которое отвечает сотруднику на вопрос «что мне делать дальше в карьере и почему именно это» — не списком случайных курсов, а 1-3 рекомендациями с прозрачным, проверяемым обоснованием. Плюс HR-дашборд, показывающий проседающие компетенции и людей, выпавших из развития.
Почему это не «LLM угадывает»
Ключевое архитектурное решение: расчёт и объяснение — разные слои.
-
Детерминированный движок (
engine/recommender.py) — обычный Python, без единого обращения к нейросети. Считает:- эффективный уровень навыков сотрудника (базовый профиль + прирост от активностей, завершённых после последней аттестации);
- разрыв до следующего грейда и/или личной карьерной цели;
- скоринг каждой доступной активности по нескольким факторам: сколько разрыва закрывает, критичен ли навык для повышения (вес ×2), как сотрудник вёл себя на активностях такого формата раньше (штраф за историю пропусков/отказов);
- честную оценку «сколько ещё месяцев» — по фактическому темпу самого сотрудника из истории, а не наугад.
-
LLM (
engine/llm_explainer.py, GPT-4o-mini) подключается только на последнем шаге — превращает уже посчитанные факты в связный текст на предпочитаемом языке сотрудника. Ей запрещено что-либо решать или выдумывать цифры. Если LLM недоступна или не отвечает вовремя — есть детерминированный текстовый fallback, который склеивает те же факты без единого обращения к сети. Демо никогда не падает из-за таймаута API.
Это защищает от главного риска подобных кейсов: наивное правило «рекомендуй то, что просело сильнее всего» ошибается, если самый слабый навык — некритичный, а сотрудник уже трижды проигнорировал мероприятия в этом формате. Наш скоринг учитывает это явно (см. «Проверка на ловушке» ниже).
AI-агент (диалог поверх той же математики)
Третий слой — карьерный ассистент с настоящим OpenAI function-calling (engine/agent.py, engine/agent_tools.py), а не имитацией диалога через промпт. Модель сама решает, вызывать ли инструмент, но инструменты — обычный Python по реальным данным:
find_mentor— ищет реальных коллег с сильным уровнем нужного навыка (для наставничества), а не только «пройди курс»;simulate_department_impact— HR-версия «что если»: массово применяет тот же скоринг ко всему отделу и честно считает, сколько разрыва закроется.
Модели никогда не даётся возможность угадывать ID — в системный промпт передаётся точный каталог skill_id/event_id, иначе она рано или поздно придумает несуществующий (например, SK_APPLICATION_SECURITY вместо настоящего SK_APP_SECURITY) и молча получит пустой результат. Ответ агента также подстраивается под preferred_language сотрудника (ru/kk/en). Каждый вызов инструмента виден в интерфейсе — раскрывающаяся плашка показывает точные аргументы и результат, чтобы это нельзя было принять на веру.
Что внутри
| Экран | Что показывает |
|---|---|
| Профиль сотрудника | Траектория до следующего грейда и до личной карьерной цели, разрывы по навыкам (с отметкой критичных), 1-3 рекомендации с факторами и объяснением, оценка «сколько до повышения», кнопка «Выполнено» с мгновенным пересчётом, история активностей |
| Показать логику AI (тумблер на карточке рекомендации) | Заменяет текст объяснения на сырые веса скоринга (gap_score, critical_weight_applied, history_risk_ratio, risk_multiplier, final_score) — доказательство, что под текстом реальная математика, а не история, придуманная моделью |
| HR-обзор | Топ проседающих навыков по компании, тепловая карта разрывов по отделам, сотрудники без доступных рекомендаций, сотрудники без прогресса 6+ месяцев, явка по активностям |
| Спросить AI-ассистента (чат на вкладках профиля и HR) | Диалог поверх движка: сотрудник может спросить «кто может быть моим ментором», HR — «что если назначить курс X всему отделу Y». Каждый ответ можно раскрыть и увидеть, какой инструмент был вызван и с какими данными |
| Загрузка профилей жюри | Drag-and-drop для employees.json / activity_history.csv в формате датасета — данные домешиваются в память без перезапуска сервера, сразу доступны в поиске и в HR-обзоре |
Интерфейс поддерживает светлую и тёмную тему (переключатель в шапке). Бонус: параллельно с веб-сервером поднимается Telegram-бот на том же движке, с привязкой к личности и интерактивной кнопкой «Выполнено» прямо в чате — подробности в разделе «Как проверить» ниже.
Проверка на ловушке жюри
Мы сознательно тестировали кейс: сотрудник, у которого сильнее всего просел некритичный навык (Public Speaking), но при этом он трижды подряд пропускал офлайн-мероприятия — а критичный для повышения System Design просел меньше, но именно он нужен для грейда. Наивное правило «бери максимальный разрыв» рекомендует Public Speaking. Наш движок — нет: критичность даёт вес ×2, а штраф за историю снижает приоритет активностей в формате, который сотрудник систематически игнорирует. System Design остаётся в топе.
Это воспроизводимо через сам интерфейс: загрузите в разделе «Загрузка профилей жюри» файл с похожим профилем и откройте его карточку.
Загрузка принимает JSON в любом разумном виде — {"employees": [...]}, один объект без обёртки (как в примере из ТЗ), или голый массив объектов — на случай, если проверочный файл или скрипт пришлёт формат чуть иначе, чем в датасете.
Запуск
pip install -r requirements.txt
cp .env.example .env # заполнить OPENAI_API_KEY (или NVIDIA_*), опционально BOT_TOKEN
python app.py
Откройте http://localhost:8791.
Без ключа LLM приложение тоже работает — просто объяснения будут собираться из детерминированного шаблона вместо GPT (тот же принцип, что и в основном движке: сначала факты, LLM только для формулировки).
Как проверить
Веб — http://localhost:8791 после python app.py. Если открываете не на том же компьютере, где запущен сервер, замените localhost на реальный адрес/домен.
Telegram-бот (@nexon_agent_bot) — бонусный канал на том же движке:
- Напишите
/start. - Введите свой
employee_id(напримерE0028) — бот привяжет этот чат к профилю. С этого момента бот показывает только привязанный профиль (это осознанное разграничение прав, а не баг) — чтобы проверить другого сотрудника, отправьте/resetи введите новый ID. - Под каждой рекомендацией есть кнопка «✅ Выполнено» — работает через тот же код, что и кнопка на сайте, прогресс пересчитывается сразу.
- Кнопка «📊 HR-обзор» видна только если привязанный ID имеет роль
HR Business Partnerв датасете (напримерE0014) — это тоже намеренно, не отсутствующая функциональность. - Если задан
TELEGRAM_WEBAPP_URL, появляется кнопка «🖥 Открыть в мини-приложении» — тот же веб-интерфейс, но внутри Telegram. Она указывает на туннель (ngrok), поднятый на момент демонстрации; если ссылка успела истечь — просто пользуйтесь ботом напрямую или веб-версией, функциональность идентична.
Переменные окружения (.env)
| Переменная | Назначение |
|---|---|
LLM_PROVIDER | openai или nvidia — какой провайдер использовать для объяснений |
OPENAI_API_KEY, OPENAI_MODEL | Ключ и модель OpenAI (по умолчанию gpt-4o-mini) |
NVIDIA_API_KEY, NVIDIA_MODEL, NVIDIA_URL | То же для NVIDIA NIM |
BOT_TOKEN | Токен Telegram-бота (опционально — без него бот просто не запускается) |
TELEGRAM_WEBAPP_URL | Публичный HTTPS-адрес (ngrok-туннель) для кнопки Mini App в боте (опционально) |
API_PORT | Порт веб-сервера (по умолчанию 8791 — 8000 зарезервирован Windows) |
LLM_TIMEOUT_SECONDS | Таймаут на объяснение от LLM, после которого используется fallback |
API
| Метод | Путь | Назначение |
|---|---|---|
GET | /api/employees | Список сотрудников (для поиска в сайдбаре) |
GET | /api/employees/{id} | Полный профиль: траектории, рекомендации, история |
POST | /api/employees/{id}/complete | Отметить активность выполненной → пересчёт профиля |
GET | /api/hr/overview | Агрегаты для HR-дашборда |
POST | /api/data/employees | Загрузить/домешать employees.json (jury-файлы) |
POST | /api/data/activity | Загрузить/домешать activity_history.csv |
POST | /api/agent/chat | Диалог с AI-агентом (employee_id задан → контекст сотрудника, null → HR-режим) |
GET | /health | Статус сервиса, кол-во загруженных записей, конфигурация LLM |
Разделение прав сотрудник/HR
Без дополнительных заголовков API ведёт себя так же, как раньше — полный доступ ко всем эндпоинтам (это осознанно, чтобы жюри/скрипт проверки могли тестировать любой профиль без лишних танцев с авторизацией). Веб-интерфейс и бот, когда действуют от лица конкретного сотрудника, добавляют заголовки X-Viewer-Role: employee и X-Viewer-Employee-Id: <id> — в этом режиме сервер отдаёт 403 на любой запрос к чужому профилю, общему списку сотрудников, HR-агрегатам или загрузке данных. Это настоящая проверка на бэкенде (app.py, функции require_hr/require_self_or_hr), не косметика в интерфейсе.
Структура проекта
app.py FastAPI-сервер: роуты, сборка профиля и HR-обзора, Telegram-бот
engine/
models.py Pydantic-модели домена (Employee, Event, Skill, ...)
data_store.py In-memory хранилище датасета + merge jury-загрузок
recommender.py Детерминированный скоринг: разрывы, рекомендации, оценка темпа
llm_explainer.py LLM только для текста объяснения, с fallback-шаблоном
agent.py Диалоговый слой: system-промпт, каталог id, вызов инструментов
agent_tools.py find_mentor / simulate_department_impact — чистая математика по данным
schemas.py API-контракт (request/response модели)
static/ Веб-интерфейс: index.html, app.js, styles.css (без сборки)
data/ Датасет хакатона (employees.json, events.json, skills.json, activity_history.csv)
Технологии
FastAPI · Pydantic v2 · aiogram (Telegram-бот) · OpenAI (GPT-4o-mini + function calling) / NVIDIA NIM API · ванильный JS/CSS на фронте (без сборки, без фреймворков)
Разработано в рамках HackAlem AI 2026 (команда Nexon). Синтетический датасет, реальные люди не использовались.
Авторы коммитов
История коммитов
- 2026-09-23 17:40feat: Telegram-бот с привязкой identity и мини-приложением, разделение прав employee/HR, устойчивость загрузки к разным форматам входных данныхSlyNursamatYT
- 2026-09-23 17:21feat: init project scaffoldSlyNursamatYT
- 2026-09-23 15:52feat: init project scaffoldSlyNursamatYT
- 2026-09-23 15:06feat: init project scaffoldSlyNursamatYT
- 2026-09-23 14:02feat: init project scaffoldSlyNursamatYT
- 2026-09-23 13:19feat: init project scaffoldSlyNursamatYT
Структура репозитория (24 файлов)
.claude/launch.json .env.example .gitignore README.md app.py data/README.kz.md data/README.md data/README.ru.md data/activity_history.csv data/employees.json data/events.json data/skills.json engine/__init__.py engine/agent.py engine/agent_tools.py engine/data_store.py engine/llm_explainer.py engine/models.py engine/recommender.py engine/schemas.py requirements.txt static/app.js static/index.html static/styles.css
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.