AAYMA
RU
Войти

Career Quest — карьерный навигатор

Локальное веб-приложение: профиль сотрудника, разрывы навыков относительно целевой роли или грейда, 1–3 варианта первого шага развития из реальных…

Рабочий MVP
Команда «Nomad AI» 5💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Nomad AI
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP

Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития

Суть

Локальное веб-приложение: профиль сотрудника, разрывы навыков относительно целевой роли или грейда, 1–3 варианта первого шага развития из реальных активностей, демо-подтверждение выполнения и HR-аналитика с импортом данных.

Как устроено

Навыки берутся из snapshot, поверх него применяются завершённые активности. Код исключает неподходящие активности (обязательные, не по роли или грейду, с нарушенными prerequisites, без сессии) и считает utility по критическим разрывам, покрытию, эффекту, истории и длительности. Единый адаптер rank_and_explain передаёт LLM только обезличенные факты и до пяти проверенных маршрутов. Модель возвращает ID маршрутов и ссылки на fact_id, код проверяет схему и наличие трёх категорий доказательств. Если вызов не удался, работает fallback.

Ключевые решения

  • rule-based eligibility
  • utility-ранжирование
  • LLM-переранжирование с валидацией fact_id
  • кэш решений (256 записей / 5 мин)
  • идемпотентные подтверждения с ревизиями
  • cookie-сессии с хешем токена в SQLite

Особенности

Приватность продумана: ФИО, ID и сырой CSV не передаются в модель. Модель только выбирает порядок среди вариантов, уже проверенных кодом, и ссылается на fact_id. В UI показываются шаблонные объяснения из проверенных фактов, а не свободная проза модели.

Стек

Python · SQLite · HTML/CSS/JS · PowerShell

Модели

OpenAI · NVIDIA API · локальная OpenAI-совместимая модель (порт 11434)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-ec77273d-nomad-ai.

README

README.md

Career Quest — карьерный навигатор

Рабочее локальное приложение для HackAlem AI / Halyk Bank: профиль сотрудника, проверяемые сценарии обучения, история, демо-подтверждение выполнения и HR-аналитика. Интерфейс на русском; названия и описания каталога сохраняют исходный язык. Полная казахская локализация не заявляется.

Правила взяты из backend/Dataset/README.md и предоставленного текста задания. DOCX и архив career_quest_dataset.zip в переданной рабочей папке отсутствовали: соответствие их неизвестному содержимому не утверждается. Распакованные четыре файла датасета присутствуют и проверены: 200 сотрудников, 40 активностей, 60 навыков, 32 профиля требований, 2743 записи истории. Новые ID поддерживаются.

Запуск одной командой

Из корня проекта, Windows + Python 3.10 или новее:

powershell -ExecutionPolicy Bypass -File .\scripts\start.ps1

Скрипт создаёт .venv при необходимости, устанавливает backend/requirements.txt и запускает сервер на http://127.0.0.1:8000. При уже установленных зависимостях:

.\.venv\Scripts\python.exe scripts\run.py

Конфигурация загружается из корневого .env (не коммитится). Пример — .env.example. Существующие переменные окружения имеют приоритет. При первом запуске скрипт добавляет отсутствующий AUTH_SECRET в локальный .env. Дата сценария берётся из meta.as_of_date — 2026-10-01. AS_OF_DATE позволяет задать более позднюю дату; вернуться до даты исходного snapshot нельзя.

Вход и роли

После старта откройте локальный var/demo_accounts.json: это коды доступа к синтетическим демо-профилям и отдельный код HR. Файл игнорируется Git и никогда не раздаётся HTTP-сервером. Выберите роль и введите код в форме входа. Для HR ID сотрудника необязателен; указав свой ID, HR получает также личный маршрут. Коды можно переопределить через HR_ACCESS_CODE и EMPLOYEE_ACCESS_CODES в окружении.

Серверные сессии хранят хеш токена в SQLite; браузер получает HttpOnly/SameSite cookie. Сотрудник видит только собственные профиль, рекомендации и историю. Запрос чужого ID или HR-API возвращает 403. HR имеет доступ к агрегатам, списку сотрудников, профилям и импорту. /boss открывает HR-обзор с теми же проверками прав, не отдельную непроверяемую привилегию. Это локальная система демо-кодов, а не интеграция банковского SSO.

Основные сценарии

  • Моё развитие: текущая роль/грейд, эффективные навыки, требования текущего, следующего и выбранного грейда, критические разрывы и история активности.
  • Сравнение: 1–3 варианта первого шага. Каждый маршрут содержит одну или две реальные активности, эффекты до/после, сроки, длительность и факторы выбора. progress_after относится к первому шагу; итог маршрута — steps[-1].coverage_after.
  • Цель: сотрудник выбирает существующий профиль роли/грейда; расчёт обновляется.
  • Выполнение: сотрудник явно подтверждает симуляцию завершения в демо. Эффект применяется один раз, версия профиля увеличивается, рекомендации пересчитываются. Подтверждение будущей сессии — условная симуляция, а не запись о реальном посещении.
  • HR: разрывы компетенций с корректным знаменателем, сотрудники без следующего шага и причины, уникальные участники/статусы активностей, импорт дополнительных данных.

Активности не присваивают грейд автоматически. Нет публичных рейтингов сотрудников, очков за обязательные процессы, принудительных серий или обещаний повышения. Числа в интерфейсе всегда берутся из backend, включая при успешной работе модели.

Проверяемая логика

  1. Исходные skills отражают последнюю оценку. Только completed после last_review_date и не позднее даты сценария воспроизводятся поверх snapshot. Отсутствующий навык = 0.
  2. Эффект ограничен gain и max_level; активность никогда не уменьшает уже высокий навык. Все реальные эффекты присутствуют в impacts, включая навыки без требования цели.
  3. Исключаются mandatory, неподходящие роль/грейд, нарушенные prerequisites, завершённые неповторяемые активности и события без доступной сессии. self_paced доступен без сессий; EV_036 повторяется только для другой сессии.
  4. Utility учитывает критические разрывы, покрытие требований, эффект, историю формата и длительность. Это не вероятность завершения или повышения. Пропуски не превращаются в рейтинг сотрудника; причины пропусков не выводятся.
  5. Сроки сценария предполагают два часа обучения в день. Для self_paced историческая дата зачисления служит приближением; неизвестная дата фактического окончания не выдумывается.

Демо-прогресс сохраняется по (import_id, employee_id) и переживает повторный вход и перезапуск. Атомарные revision/idempotency-проверки защищают от двойного начисления и устаревших подтверждений. Источник JSON/CSV не перезаписывается. SQLite версии 1/2 обновляется до 3 добавлением таблиц; существующие данные сохраняются.

Career Navigator и приватность

Один адаптер rank_and_explain(facts) в backend/app/engine/ai_layer.py выбирает порядок среди максимум пяти проверенных вариантов. В модель передаются только роль, грейд, цель, разрывы, агрегированные факторы истории, допустимые маршруты и fact_id. ФИО, employee_id, manager_id, сырой CSV и полные профили не передаются.

Модель возвращает JSON с ID маршрутов и ссылками на факты. Проверяются схема, уникальность/существование ID, разрешённые позиции перестановки и минимум три категории доказательств (грейд/цель, разрыв, история) для каждого объяснения. Свободную прозу невозможно автоматически признать истинной: в UI используются короткие шаблоны из проверенных фактов, выбранных моделью. Модель определяет ранжирование и факторы; приросты и допуск определяет код.

Провайдер конфигурируется окружением. Пример локального совместимого сервиса:

AI_PROVIDER=local
AI_MODEL=имя_установленной_локальной_модели
AI_BASE_URL=http://127.0.0.1:11434/v1/chat/completions

Модель локального сервиса должна быть установлена отдельно. Поддерживаются также openai, nvidia, openai-compatible; используйте OPENAI_MODEL/OPENAI_API_KEY, NVIDIA_MODEL/NVIDIA_API_KEY или общие AI_MODEL/AI_API_KEY. Имя модели задаёт владелец проекта; код не меняет его автоматически.

Для внешнего контура производные факты допускаются только при AI_ALLOW_EXTERNAL_DERIVED=true, после разрешения организаторов. Без флага работает локальный endpoint либо честный fallback external_not_allowed. Страница HR /admin/ai проверяет реальный вызов на фиксированном синтетическом примере сервера; никакие поля загруженных сотрудников для этого теста не используются.

Общий таймаут одного вызова — 6 секунд, повторов нет. mode=llm возможен только после настоящего успешного вызова и валидации; иначе mode=fallback и причина. Кэш успешных решений ограничен 256 записями/5 минутами и включает employee_id, revision, цель, факты, конфигурацию модели и версию prompt. Изменение цели, подтверждение выполнения или импорт сбрасывают соответствующие записи.

Профиль и локальные сценарии загружаются независимо от модели. После отображения расчёта UI отдельно запрашивает AI и отвергает устаревшие результаты по revision.

Импорт для жюри

Войдите HR → Загрузка данных:

  • Дополнение: employees.json (обёртка starter kit или массив сырых профилей) + activity_history.csv. Новые ID не ограничены исходными 200; ссылки/уровни проверяются.
  • Замена: все четыре исходных файла либо ZIP с ними. Нужны employees.json, events.json, skills.json, activity_history.csv с одной датой snapshot.

Проверка выполняется до активации. Неверные ссылки, диапазоны, типы, даты, дубликаты и несогласованные статусы дают ошибку с путём поля. Готовый API Employee нельзя импортировать как raw snapshot: в нём навыки уже рассчитаны. Неудачный импорт не заменяет текущий набор. При успешной замене исходный набор сохраняется локально, активируется новая версия; другие сессии должны войти заново. Демо-прогресс прежнего импорта остаётся в SQLite, но не смешивается с новым snapshot.

API и модули

МодульОтветственность
engine/data_loader.pyСтрогая проверка исходных и дополнительных данных
engine/navigator.pyЭффективные навыки, требования, допуск, сценарии, HR
engine/ai_layer.pyЕдинственная граница модели, deadline, валидация, fallback, кэш
repository.py, schema.sqlСессии, версии, подтверждения, сохранение demo-состояния
application.py, access.pyАвторизация, API, импорт, обработка ошибок
static/portal.*Русский интерфейс сотрудника и HR
contracts.py, contracts/contract.mdОбщие модели и формат обмена

Существующий трёхшаговый planner сохранён как совместимый модуль с тестами; активный продукт использует navigator и маршруты из одной–двух активностей. OpenAPI: /docs. Основные API: /api/login, /api/session, /api/me, /api/me/recommendations?ai=false|true, /api/me/target, /api/me/completions, /api/hr/overview, /api/employees, /api/hr/import. Ошибка единообразна: {"error":{"code":"VALIDATION_ERROR","message":"…","details":[]}}. 401 — нет сессии; 403 — нет прав; 404 — неизвестный ID; 409 — конфликт версии/дубликат; 422 — входные данные; 503 — приложение не готово, никогда не отказ LLM.

Проверки и воспроизводимое демо

.\.venv\Scripts\python.exe -m unittest discover -s backend/tests -t . -v
.\.venv\Scripts\python.exe scripts\demo_scenario.py --output var/demo_report.json
.\.venv\Scripts\python.exe scripts\verify_demo.py --synthetic-ai

Первый запуск проверяет рискованные бизнес-правила, права, импорт, идемпотентность, вымышленные ID модели, таймаут и кэш. demo_scenario.py не вызывает модель и не меняет SQLite. verify_demo.py использует временную БД; флаг --synthetic-ai делает один реальный запрос на синтетическом примере. Последний отчёт: var/verification.json.

Пошаговая демонстрация E0015 и сложного профиля E0137 — docs/demo.md. Она показывает сравнение с ошибочным однофакторным выбором и однократное начисление.

Измерение API на этом компьютере, Python 3.14.7, полный исходный датасет: профиль 8,9–13,6 мс; локальные рекомендации 8,1–8,7 мс; первый HR-запрос 359 мс; синтетический реальный ответ модели — 4,93 с (mode=llm, без кэша). Это FastAPI TestClient/серверный путь, не замер отрисовки браузера. Ограничения 2/10 секунд выполнены в этой проверке, не гарантируются для другой машины или провайдера. Для отдельного сетевого измерения API отдаёт Server-Timing. В текущей агентской среде доступного браузера нет, поэтому визуальная QA не выполнена.

Не публикуйте .env, локальные коды, исходный датасет и SQLite. Используйте только синтетические профили, переданные организаторами. Раскрытый ранее ключ API нужно отозвать у провайдера; удаление его из рабочего файла не удаляет историю Git.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
7
Авторы
2
Файлы
53
Ветки
4

Авторы коммитов

CopitanCat 6myfiz 1

История коммитов

  • 2026-09-23 17:47half-finishCopitanCat
  • 2026-09-23 17:42half-finishCopitanCat
  • 2026-09-23 17:19frontCopitanCat
  • 2026-09-23 17:14making bdCopitanCat
  • 2026-09-23 15:11making bdCopitanCat
  • 2026-09-23 15:08making bdCopitanCat
  • 2026-09-23 14:33Add HR overview page and implement API testsmyfiz
Структура репозитория (53 файлов)
.env.example
.gitignore
README.md
api/Apis.txt
backend/Dataset/README.kz.md
backend/Dataset/README.md
backend/Dataset/README.ru.md
backend/Dataset/activity_history.csv
backend/Dataset/employees.json
backend/Dataset/events.json
backend/Dataset/skills.json
backend/README.md
backend/__init__.py
backend/app/__init__.py
backend/app/access.py
backend/app/application.py
backend/app/catalog_api.py
backend/app/contracts.py
backend/app/engine/__init__.py
backend/app/engine/ai_layer.py
backend/app/engine/data_loader.py
backend/app/engine/navigator.py
backend/app/engine/openai_agent.py
backend/app/engine/planner.py
backend/app/importing.py
backend/app/main.py
backend/app/repository.py
backend/app/schema.sql
backend/app/schemas.py
backend/app/static/ai_admin.html
backend/app/static/plans.html
backend/app/static/portal.css
backend/app/static/portal.html
backend/app/static/portal.js
backend/requirements.txt
backend/scripts/init_db.py
backend/tests/__init__.py
backend/tests/test_ai_layer.py
backend/tests/test_api.py
backend/tests/test_imports.py
backend/tests/test_navigator.py
backend/tests/test_planner.py
backend/tests/test_repository.py
contracts/contract.md
contracts/examples.json
data/.gitkeep
docs/demo.md
scripts/demo_scenario.py
scripts/init_db.py
scripts/run-codex-agent.ps1
scripts/run.py
scripts/start.ps1
scripts/verify_demo.py
Ветки (4)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.