Career Quest
Веб-приложение, показывающее сотруднику разрыв навыков до следующего грейда и 1–3 доступных шага развития с объяснением, с пересчётом прогресса…
О проекте
Команда: Participants
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Веб-приложение, показывающее сотруднику разрыв навыков до следующего грейда и 1–3 доступных шага развития с объяснением, с пересчётом прогресса после выполнения, HR-дашбордом и импортом профилей жюри.
Как устроено
FastAPI загружает профили, историю и каталог из PostgreSQL; доменный модуль считает coverage = Σmin(уровень, требуемый)/Σтребуемых и разрывы. Каталог фильтруется по роли, грейду, prerequisites, датам сессий и полезности для цели, затем кандидаты получают многофакторный локальный score (разрыв, критичность, история пропусков и отказов, длительность). Опционально LLM переупорядочивает только допустимых кандидатов; ответ принимается, если в нём известные event_id, ≥3 фактора, а первый выбор входит в локальный Top-3. Иначе используется детерминированный fallback.
Ключевые решения
- coverage-based trajectory
- eligibility filtering
- multi-factor scoring
- LLM rerank with validation
- deterministic fallback
- 5-min cache invalidation
Особенности
LLM разрешено только переранжировать заранее проверенных кандидатов с жёсткими серверными проверками (топ-1 LLM обязан входить в локальный Top-3). Если курса нет, система генерирует конкретный запрос к HR вместо выдуманного шага.
Стек
Python 3.12 · FastAPI · Pydantic · PostgreSQL 16 · psycopg · React 19 · TypeScript · Vite · Docker Compose
Модели
OpenAI Responses API · NVIDIA NIM
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-ea50d4e9-participants.
README
README.mdCareer Quest
AI-навигатор развития сотрудника для HackAlem AI × Halyk Bank
Career Quest превращает разрозненные HR-активности в понятную карьерную траекторию. Сотрудник видит, какие навыки отделяют его от следующего грейда, получает 1–3 доступных шага с проверяемым объяснением и сразу видит модельный эффект выполнения. HR получает агрегированный срез по дефицитам компетенций и участию — без публичных рейтингов сотрудников.
Решение работает на синтетическом стартовом наборе и поддерживает загрузку дополнительных профилей жюри. Внешняя LLM опциональна: без API-ключей приложение использует прозрачный локальный ранжировщик.
Краткое описание
Обычный каталог обучения отвечает на вопрос «что доступно?», но не объясняет сотруднику, зачем ему конкретная активность. Career Quest связывает четыре контекста:
- текущий грейд и требования следующего уровня;
- фактические разрывы по навыкам;
- историю завершений, пропусков и отказов;
- доступность, prerequisites и ожидаемый прирост от активности.
Результат — не рекомендация по минимальному навыку, а следующий реалистичный шаг к карьерной цели с доказательствами, на которых он выбран.
Что реализовано
| Требование ТЗ | Реализация в Career Quest |
|---|---|
| Профиль и карьерная траектория | Роль, грейд, следующая веха, долгосрочная цель, подтверждённые и модельные уровни навыков, история и обязательные активности. |
| 1–3 рекомендации | Сервер отбирает только доступные добровольные активности, сокращающие разрыв до ближайшей или долгосрочной цели. |
| Объяснимость минимум по трём факторам | Карточка показывает цель, текущий/требуемый/ожидаемый уровень навыка, историю похожих активностей, доступность и место в локальном рейтинге. |
| Обновление прогресса | «Отметить пройденным» применяет gain с учётом max_level, пересчитывает траекторию и рекомендации. Демо-отметку можно отменить. |
| HR-view | Карта дефицитов, сотрудники с разрывом без доступного шага, сотрудники без цели и статистика участия по активностям. |
| Загрузка проверочных профилей | HR может предварительно проверить и атомарно импортировать JSON профилей и CSV истории в схеме стартового набора. |
| Разграничение ролей | В демо сотрудник видит только выбранный профиль; импорт и агрегаты доступны роли HR. Границы демо-авторизации явно обозначены ниже. |
| Запуск одной командой | Приложение и PostgreSQL поднимаются через Docker Compose; схема и стартовые данные загружаются автоматически. |
Установка и запуск
Потребуется Docker Desktop с запущенным Linux engine.
Copy-Item .env.example .env
docker compose up --build -d
После запуска:
- приложение — http://localhost:8000;
- health check — http://localhost:8000/api/health;
- OpenAPI — http://localhost:8000/docs.
Первый старт создаёт таблицы PostgreSQL и загружает data/: 200 профилей, 40 событий, 60 навыков и 2 743 записи истории. Повторный запуск не дублирует данные.
Проверить состояние контейнеров:
docker compose ps
docker compose logs app --tail 100
Остановить приложение без удаления данных:
docker compose down
PostgreSQL хранится в Docker volume postgres_data. Команда docker compose down -v удалит volume вместе с импортами и смоделированными завершениями — используйте её только для полного сброса демо.
Приложение по умолчанию привязано к 127.0.0.1. При конфликте порта измените APP_PORT в .env.
Как проверить решение
- Откройте «Моя траектория» и выберите
E0028либо произвольный профиль. Покажите текущий грейд, следующую веху, покрытие требований и историю. - Перейдите к рекомендациям. В каждой карточке видны разрыв, прогнозируемый прирост, влияние истории и доступность. Если подходящего курса нет, система честно объяснит ограничение и сформирует конкретный запрос HR по главному разрыву или карьерной цели. Копирование запроса не изменяет навыки.
- Для самостоятельной активности нажмите «Отметить пройденным». Демо-отметка сохраняется датой среза, а прогресс и рекомендации пересчитываются. Очную или онлайн-активность можно отметить только после состоявшейся сессии; созданную в приложении отметку можно отменить в истории.
- Переключитесь на роль HR и покажите карту дефицитов, разрывы без шага, профили без цели и участие по активностям.
- В разделе «Импорт данных» загрузите проверочный JSON/CSV: сначала «Проверить файлы», затем «Загрузить набор». Импорт не изменяет исходные файлы и выполняется атомарно.
«Отметить пройденным» создаёт обратимую демо-запись. Исходная история датасета при этом не изменяется и не удаляется.
Как работает решение
Основной пользовательский сценарий:
- Платформа получает профиль сотрудника, текущий грейд, уровни навыков и историю участия из PostgreSQL.
- Доменный модуль определяет следующую карьерную веху и рассчитывает разрывы между текущими и требуемыми уровнями.
- Каталог фильтруется по роли, грейду, prerequisites, датам сессий и уже выполненным активностям; оставшиеся варианты получают многофакторную оценку.
- Если настроен AI-провайдер, он переупорядочивает только допустимых кандидатов. Сервер проверяет ответ модели и при любой ошибке использует локальный рейтинг.
- Сотрудник получает 1–3 шага с объяснением цели, разрыва, ожидаемого прироста, истории и доступности. Если курса нет, система показывает причину и готовит запрос для HR без обращения к OpenAI.
- После демо-отметки выполнения модельный прогресс и рекомендации пересчитываются. HR видит агрегированные дефициты и статистику участия.
flowchart LR
A[Профиль и история] --> B[Цель и разрывы навыков]
C[Каталог активностей] --> D[Фильтр доступности]
B --> D
D --> E[Прозрачный локальный score]
E --> F{LLM настроена?}
F -- нет или timeout --> G[Детерминированный Top 1–3]
F -- да --> H[LLM rerank допустимых кандидатов]
H --> I[Проверка ID, фактов и локального Top 3]
I -- ответ валиден --> J[Объяснимые рекомендации]
I -- ответ невалиден --> G
G --> J
J --> K[Модельное выполнение]
K --> B
1. Расчёт траектории
Ближайшая веха — следующий грейд в текущей роли. Если следующего грейда нет, используется только явно заданная и валидная карьерная цель; система не придумывает направление развития. Прогресс считается по требованиям целевого профиля:
coverage = Σ min(модельный уровень, требуемый уровень) / Σ требуемых уровней
Исходные employees.skills остаются подтверждённой оценкой. Завершения после last_review_date образуют отдельный модельный уровень. Прирост ограничивается диапазоном 0–5 и значением max_level активности.
2. Фильтр допустимости
До обращения к LLM сервер исключает:
- обязательные мероприятия — они показываются отдельно;
- активности не для текущей роли или грейда;
- шаги с невыполненными prerequisites;
- уже завершённые неповторяемые активности;
- активности в процессе или без будущей сессии;
- шаги, которые не сокращают ни одного разрыва до цели.
Поэтому внешняя модель не может предложить несуществующую или недоступную активность.
3. Многофакторный рейтинг
Для каждого допустимого кандидата локальный слой учитывает:
- величину закрываемого разрыва и повышенный вес критичных навыков;
- вклад в ближайшую и долгосрочную цель;
- завершения активностей того же типа;
- пропуски, прерывания и отказы по тем же навыкам;
- длительность активности.
Шаг по критичному разрыву включается в контекст LLM, но критичность сама по себе не отменяет штрафы за пропуски и отказы. Первый выбор LLM обязан входить в локальный Top 3; если локальный лидер закрывает критичный разрыв, этот приоритет сохраняется. Правила повторно проверяются сервером.
4. Роль LLM и fail-safe
LLM не генерирует каталог и не рассчитывает уровни. Она только выбирает и переупорядочивает заранее проверенных кандидатов. Ответ принимается, если:
- содержит только известные
event_id; - ссылается минимум на три разрешённых фактора и факты из серверного контекста;
- ставит первым один из локальных Top 3 и сохраняет критичный приоритет локального лидера.
При отсутствии ключа, таймауте, сетевой ошибке или невалидном ответе автоматически используется детерминированный Top 1–3. Результат кэшируется на пять минут и инвалидируется после импорта или выполнения активности.
Что означает источник рекомендации в интерфейсе
- «AI · OpenAI» — OpenAI ответил, после чего сервер проверил выбранные
event_id, подтверждающие факты и соблюдение правил ранжирования и только затем принял результат. Список допустимых курсов и расчёт их пользы до обращения к модели формирует код платформы: OpenAI не создаёт активности и не изменяет уровни навыков. - «Анализ данных» — для сотрудника не нашлось подходящих курсов. Система локально объясняет причину и показывает запасной шаг — готовый запрос к HR по главному разрыву или карьерной цели. В этом сценарии запрос к OpenAI не отправляется, а копирование текста не влияет на прогресс.
Технологии
| Слой | Технологии | Ответственность |
|---|---|---|
| Frontend | React 19, TypeScript, Vite | Траектория, рекомендации, демо-отметка выполнения, HR-dashboard, импорт. |
| API | Python 3.12, FastAPI, Pydantic | HTTP API, проверка доступа, оркестрация доменной логики. |
| Recommendation core | Чистый Python | Прогресс, фильтрация, scoring, объяснения и fallback без зависимости от БД/LLM. |
| AI adapters | OpenAI Responses API / NVIDIA NIM, httpx | Опциональный rerank со структурированным и валидируемым ответом. |
| Data | PostgreSQL 16, psycopg | Профили, история, импорты и модельные завершения. |
| Delivery | Docker, Docker Compose | Сборка frontend и единый локальный endpoint приложения. |
Архитектура проекта
Frontend собран в статические файлы и раздаётся тем же FastAPI-приложением, что обслуживает API. FastAPI получает профиль и историю из PostgreSQL, передаёт их в независимый доменный модуль, а при наличии допустимых кандидатов может вызвать настроенный AI-провайдер для rerank. Любой ответ модели проходит серверную проверку; при ошибке используется локальный результат.
Основной поток запроса:
Browser → FastAPI → domain rules → PostgreSQL
└→ optional LLM rerank → validator → fallback
Ключевые модули:
backend/
├── main.py # API, роли, импорт и раздача собранного frontend
├── domain.py # траектория, фильтр, scoring и объяснения
├── ai_provider.py # OpenAI/NVIDIA, schema validation и fallback
├── analytics.py # HR-агрегаты
├── ingestion.py # парсинг и валидация JSON/CSV
├── database.py # доступ к PostgreSQL и первичная загрузка
└── schema.sql # схема БД
frontend/src/ # React/TypeScript интерфейс
data/ # синтетический стартовый набор
tests/ # предметные и acceptance-тесты
Данные и интеграции
Стартовый синтетический набор хранится локально в каталоге data/ и содержит:
employees.json— 200 профилей сотрудников;events.json— 40 HR-активностей и правила прироста навыков;skills.json— 60 навыков, шкалу уровней и требования профилей;activity_history.csv— 2 743 записи истории за 24 месяца.
После первого запуска данные загружаются в PostgreSQL. Дополнительные профили и историю можно импортировать через HR-интерфейс. Из внешних интеграций реализованы опциональные OpenAI Responses API и NVIDIA NIM Chat Completions; при отсутствии ключей решение полностью работает на локальном детерминированном алгоритме.
Конфигурация
| Переменная | По умолчанию | Назначение |
|---|---|---|
APP_PORT | 8000 | Локальный порт веб-приложения. |
POSTGRES_DB | careerquest | Имя БД PostgreSQL. |
POSTGRES_USER | careerquest | Пользователь PostgreSQL. |
POSTGRES_PASSWORD | careerquest | Пароль локальной демо-БД. |
DEMO_MODE | true | Включает локальный переключатель ролей и профилей. |
AI_PROVIDER | auto | auto, openai, nvidia или off. |
OPENAI_API_KEY | — | Ключ OpenAI; для запуска не обязателен. |
OPENAI_MODEL | gpt-4.1-mini | Доступная аккаунту модель Responses API. |
NVIDIA_API_KEY | — | Ключ NVIDIA NIM; для запуска не обязателен. |
NVIDIA_MODEL | meta/llama-3.3-70b-instruct | Доступная модель NVIDIA NIM. |
AI_TIMEOUT_SECONDS | 7.5 | Общий бюджет внешнего AI; остаётся внутри лимита ТЗ в 10 секунд. |
Режимы AI_PROVIDER:
auto— OpenAI → NVIDIA → локальный fallback;openaiилиnvidia— выбранный провайдер → локальный fallback;off— только детерминированное ранжирование.
Ключи не нужны для локального демо. Не коммитьте .env: файл исключён через .gitignore. Во внешний AI передаются целевая роль, агрегированные разрывы и обезличенные кандидаты — без имени сотрудника и сырой истории.
Импорт проверочных данных
Импорт доступен в HR-режиме и принимает файлы до 3 МБ:
employees.json: один профиль, массив профилей, объект{ "employees": [...] }или полный формат стартового файла;activity_history.csv: CSV с теми же колонками, что вdata/activity_history.csv.
Минимальный пример профиля:
{
"employee_id": "JURY_001",
"full_name": "Test Employee",
"department": "Backend Development",
"role": "Backend Engineer",
"grade": "Middle",
"manager_id": null,
"hire_date": "2023-01-01",
"tenure_months": 44,
"work_format": "hybrid",
"preferred_language": "ru",
"career_goal": {
"target_role": "Backend Engineer",
"target_grade": "Senior"
},
"skills": {
"SK_PYTHON": 3,
"SK_SYSTEM_DESIGN": 2,
"SK_PUBLIC_SPEAKING": 2
},
"last_review_date": "2026-09-01"
}
CSV-заголовок:
record_id,employee_id,event_id,date,due_date,status,completion_pct,score,feedback_rating,assigned_by
Preview проверяет уникальность ID, существование ролей, грейдов, навыков и событий, диапазоны значений и ссылки истории на сотрудников. Commit выполняется одной транзакцией. Повторная загрузка тех же файлов определяется по хэшу и не создаёт дубликаты; исходный batch удалить нельзя.
API
| Метод | Endpoint | Назначение |
|---|---|---|
GET | /api/health | Готовность приложения и БД. |
GET | /api/meta | Версия/дата набора и импортированные batches. |
GET | /api/employees | Доступные текущей роли профили. |
GET | /api/employees/{id} | Профиль, история и обязательные активности. |
GET | /api/employees/{id}/progress | Траектория, покрытие и разрывы. |
GET | /api/employees/{id}/recommendations | 1–3 объяснимых шага и причины исключений. |
POST | /api/employees/{id}/activities/{event_id}/complete | Модельное выполнение и пересчёт прогресса. |
DELETE | /api/employees/{id}/activities/{event_id}/complete | Отмена созданной в приложении демо-отметки. |
GET | /api/hr/overview | Агрегированный HR-срез с фильтрами. |
POST | /api/import/preview | Валидация файлов без записи. |
POST | /api/import/commit | Атомарная загрузка проверочного набора. |
DELETE | /api/import/{batch_id} | Удаление дополнительного batch. |
В демо доступ задают заголовки X-Demo-Role: employee|hr и X-Demo-Employee: <id>; интерфейс устанавливает их автоматически. Полные схемы запросов доступны в /docs.
Проверка проекта
Предметные тесты не требуют запущенной БД:
python -m unittest discover -s tests -v
Они проверяют, в частности, многофакторный выбор вместо правила «минимальный навык», однократное применение прироста, ограничения каталога, влияние истории, валидацию AI-ответа и HR-агрегацию.
Сборка frontend:
Set-Location frontend
npm ci
npm run build
End-to-end smoke test после запуска Compose:
Invoke-RestMethod http://localhost:8000/api/health
Invoke-RestMethod http://localhost:8000/api/meta
Ограничения текущей версии
- Данные стартового набора синтетические; приложение не отправляет репозиторий или данные куда-либо автоматически.
- HR-view содержит агрегаты и рабочие списки, но не публичный рейтинг результативности сотрудников.
- Обязательные процессы отделены от добровольных рекомендаций и не используются как игровая механика.
DEMO_MODEи заголовки — только имитация ролей для защиты, не корпоративная авторизация.- Перед работой с реальными данными необходимы SSO/RBAC, аудит доступа, управление согласиями, секрет-хранилище и согласованная политика передачи данных внешнему AI.
- Дата расчёта фиксирована метаданными набора (
2026-10-01), поэтому демо воспроизводимо и не зависит от часов компьютера. - Для self-paced активности историческая дата может означать назначение, а не завершение. Неоднозначные записи до последней оценки не повышают уровень автоматически.
- Процент покрытия показывает соответствие требованиям профиля, а не вероятность повышения сотрудника.
- Контент каталога в стартовом наборе на английском; интерфейс текущей версии — на русском.
Deployed-версия
Публичная deployed-версия в репозитории не указана. После локального запуска приложение доступно по адресу http://localhost:8000.
Возможности развития
- SSO и корпоративная матрица ролей;
- согласованный каталог на русском и казахском языках;
- обратная связь сотрудника для learning-to-rank;
- календарь, мессенджер и напоминания по добровольному opt-in;
- конструктор активностей и симуляция карьерных сценариев для HR;
- мониторинг качества рекомендаций, fairness и drift;
- командные и менторские механики без публичного соревнования сотрудников.
Career Quest показывает сотруднику не просто список курсов, а следующий объяснимый шаг: куда он ведёт, какой разрыв закрывает и как изменит траекторию.
Авторы коммитов
История коммитов
- 2026-09-23 17:23fixAlmas456732
- 2026-09-23 17:23отредактировал read meAlmas456732
- 2026-09-23 17:17Merge main and update project documentationAlmas456732
- 2026-09-23 17:14added read me fileAlmas456732
- 2026-09-23 17:12Add honest fallback steps and reversible dated completionsalanselivanov
- 2026-09-23 17:03Merge branch 'main' of https://github.com/BAITC-Hacks/hack-ea50d4e9-participantsAlmas456732
- 2026-09-23 17:03сделал анализ недостатковAlmas456732
- 2026-09-23 16:44Account for demo history and prioritize critical developmentalanselivanov
Все коммиты (21)
- 2026-09-23 16:20Merge recommendation explanations into mainalanselivanov
- 2026-09-23 16:16Explain recommendation choices and blocked critical skillsalanselivanov
- 2026-09-23 16:16Merge pull request #3 from BAITC-Hacks/codex/fix-requirements-bugsAlmas
- 2026-09-23 16:12changed the frontendAlmas456732
- 2026-09-23 15:56Merge pull request #2 from BAITC-Hacks/codex/fix-goal-recommendationsalanselivanov
- 2026-09-23 15:54Fix goal-relevant recommendations and activity history scoringalanselivanov
- 2026-09-23 15:36Merge pull request #1 from BAITC-Hacks/codex/fix-requirements-bugsAlmas
- 2026-09-23 15:32Merge origin/main and resolve application conflictsAlmas456732
- 2026-09-23 15:29Fix requirements bugs and restore application UIAlmas456732
- 2026-09-23 15:20fixed some bugsAlmas456732
- 2026-09-23 15:07Created MVP for starting point of the project, added deployalanselivanov
- 2026-09-23 14:31added project planAlmas456732
- 2026-09-23 14:29initial architecture of the appalanselivanov
Структура репозитория (29 файлов)
.dockerignore .env.example .gitignore Dockerfile README.md backend/ai_provider.py backend/analytics.py backend/config.py backend/database.py backend/domain.py backend/ingestion.py backend/main.py backend/requirements.txt backend/schema.sql compose.yaml data/activity_history.csv data/employees.json data/events.json data/skills.json frontend/index.html frontend/package-lock.json frontend/package.json frontend/src/App.tsx frontend/src/main.tsx frontend/src/styles.css frontend/tsconfig.json frontend/vite.config.ts tests/test_domain.py tests/test_requirements.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.