# Занятие 2 · сценарий после ревизии

180 минут. 0–20: подключение; 20–55: функции, каталог и пути по файлам; 55–80: задание 1; 80–105: цикл выпуска и версии; 105–145: задание 2; 145–180: проверки и помощь. Бонусная презентация — самостоятельное расширение для опередивших группу и продолжение дома. При необходимости больше времени отдать практике, не чтению слайдов.

Основные результаты: присутствие, разные модели, разные версии. Дополнительные: ошибки, пакет моделей. Успех требует первых трёх. Topic01 остаётся отдельным стендом; тема 2 не учит маршрутизации по возможностям воркеров (тема 4). Следующая тема 3 — признаки.

Default допускает любую строку до 2000 символов. Upper/reverse сравниваются точно. Метаданные первой задачи: model; version необязательна (null или v1). Ошибки: неизвестное имя, версия, сбой обработчика, затем успешный upper. Пакет: все выпуски реестра, не один файл.


## Модели и версии

### 1. MLOps · Занятие 2



### 2. Продолжаем нашу систему

0–10 минут. Подключить исходные клиенты темы 2. Не устраивать проверку домашки. Попросить желающего отправить запрос своим пультом. При отсутствии использовать дашборд. Не считать жизненный цикл уже пройденным: он будет объяснён после появления второй версии.

### 3. Подключение к занятию 2

Показать точный адрес второго стенда. В команду запуска достаточно подставить новый --server, старый клиент подключается в режиме совместимости: ФИО, пульс и default/v1. Другие модели и версии получают CLIENT_UPGRADE_REQUIRED. Для дальнейшей практики взять транспорт темы 2 и перенести свою функцию в default_infer. Windows: python или py; macOS/Linux: python3. Использовать один интерпретатор для pip и запуска. Ключ выдаёт преподаватель.

### 4. Два файла, которые мы изменяем

Показать файлы в редакторе. Удалить стартовый обход каталога в run_inference, когда регистратор заработает. Не оставлять две конкурирующие реализации.

### 5. Как одному клиенту запускать разные модели?

20–25 минут. Отправить строку всем. Сейчас один worker имеет одну функцию. Предложить студентам назвать способы добавить второй вариант: if, словарь, классы. Выбрать минимальный словарь функций. Не начинать с готового промышленного реестра.

### 6. Локальный каталог выбирает функцию

Показать выбор отдельно от регистрации. Внешняя модель здесь учебная функция; позже артефактом могут стать веса и конфигурация.

### 7. Функция может быть значением словаря

25–30 минут. Разобрать разницу между функцией и результатом. В нашем контракте все адаптеры async; текущая функция не ждёт внешнего ввода, но вызывающий код единообразен. Не углубляться в устройство event loop.

### 8. Что делает await?



### 9. Как функция попадает в каталог?

30–35 минут. Попросить положить ещё один py-файл рядом. Изменится ли каталог сам? Нет: необходимы импорт и явная регистрация.

### 10. Регистрация подключает обработчик

Показать на знакомом models.py. Артефакт в нашей практике — файл Python. Для весов понадобится загрузка через подходящий адаптер. Сканирование папок и плагины пока не вводим.

### 11. Первый регистратор

35–45 минут. Написать вместе сигнатуру, дать дописать проверки. В выданном catalog.py финальная сигнатура уже содержит version: можно временно её не использовать, либо сразу хранить пару с v1. Не вызывать старый пример тремя аргументами.

### 12. Регистрация при запуске: models.py

Промежуточный шаг по имени. default_infer уже есть, upper показан на предыдущем слайде. Финальный вызов: register_model("upper","v1",upper,default=True). Для frame/v2 default=False. При переходе на версии изменить все вызовы в setup.

### 13. Запускатор отделяет выбор от выполнения



### 14. Каталог внутри нашего клиента

Показать интеграцию: сервер пересылает model/version, клиент исполняет и возвращает фактические значения. В теме 2 запрос идёт всем READY, разные локальные наборы могут дать MODEL_NOT_FOUND. Выбор подходящих воркеров будет в теме 4.

### 15. Из каких файлов состоит запуск клиента?

После setup() функция run() начинает принимать задания. Стрелки привязаны к методам внутри файлов. Путь хранения ссылки не означает вызов модели при регистрации.

### 16. Как функции попадают в локальный каталог?

Регистрация НЕ вызывает upper. Она делает функцию доступной для будущих запросов. Стрелки привязаны к методам внутри файлов. Путь хранения ссылки не означает вызов модели при регистрации.

### 17. По каким файлам проходит запрос?

execute → run_inference → выбранная функция → run_inference → execute → RESULT. Стрелки привязаны к методам внутри файлов. Путь хранения ссылки не означает вызов модели при регистрации.

### 18. Как запросить нужную модель?

50–55 минут. Предложить добавить поле в существующее тело POST /infer. Старый запрос без model должен продолжить работать.

### 19. Bearer: как передаётся знакомый ключ

Не показывать настоящий ключ на слайде. Передаётся по HTTPS/WSS. Здесь впервые объясняем заголовок для личного отправителя.

### 20. POST /infer: имя необязательно

Показать запрос в форме дашборда и в готовом отправителе при наличии. JSON здесь без version. Версия появится следующим расширением. Не передавать client_secret отправителю.

### 21. Если запрошенной модели нет

Не добавлять здесь полноценный урок ошибок. Нужно только понять ветку уже показанного запускатора. Бонус: /materials/bonus.html; это дополнительный этап, первые три проверки обязательны.

### 22. Задание 1: три обработчика



### 23. Как изменить модель, сохранив старый вариант?

75–80 минут. Изменить поведение учительской функции: прежний результат нельзя повторить. Спросить, достаточно ли переименовать файл. Подвести к имени + ревизии и привязке артефакта.

### 24. Цикл разработки и выпуска

80–90 минут. Замкнуть цикл. В реальном ML изменение включает данные и обучение; мы сегодня используем изменение кода моки. Генеративный пример: дообучение улучшило ответы по теме, но нарушило JSON-формат. Обратная связь нужна до решения о новом выпуске.

### 25. Что меняется в настоящей ML-модели

Пример генеративного помощника: новые данные улучшили ответы по предмету, но ответ перестал соблюдать формат JSON. Почему одной метрики недостаточно? Где связь модели и обслуживающего кода?

### 26. Что относится к выпуску модели

Первое употребление термина манифест в основной презентации. Например model=frame, version=v2, entrypoint=infer, artifact_url и sha256. Хэш позволяет проверить целостность полученного файла. В бонусе эти поля будут прочитаны из JSON.

### 27. Почему версия — строка?



### 28. Каталог теперь хранит версии

90–100 минут. Дорабатываем тот же регистратор. Проверки имени/версии и inspect.iscoroutinefunction есть в эталоне. На слайде основной новый механизм; прежние проверки переносим. Alias current пока не нужен отдельной сущностью: defaults уже показывает изменяемую ссылку на неизменяемую ревизию.

### 29. Зачем заставлять писать default=True?



### 30. Обновляем setup() под версии



### 31. Выбор версии в запускаторе

100–105 минут. После блока вернуть output/model/version, как раньше, но version=selected. Явный None отличается от пустой строки. Входной HTTP-контракт отклоняет пустую версию.

### 32. POST /infer: конкретная версия

Повторить запросы v1, v2, v1. generation=models-v1 — поколение протокола воркера, не версия его модели. Этот термин не должен вводить студентов в заблуждение.

### 33. Как добавить оформление вокруг обработки?

105–110 минут. Требуется сохранить исходную строку и добавить рамку. Сначала реализовать две явные функции; затем показать выделение общего поведения в обёртку.

### 34. Обёртка создаёт новую функцию

110–120 минут. Если декораторы незнакомы, показать эквивалент frame_v1=framed("=====")(frame_v1). Синтаксис @ не обязателен для зачёта. Проверяем поведение, а не стиль кода.

### 35. Задание 2: frame / v1 и frame / v2

120–140 минут. Проверочные входы однострочные, содержат Unicode и пробелы. Сравнение точное. Не удалять пробелы text.strip(). Обязательно возвращать фактическую версию в метаданных.

### 36. Версия проходит через всю систему

Спросить: что изменится, если defaults["frame"]="v2"? Неявные запросы изменятся, явный v1 останется. До обязательной проверки вернуть default=v1. Это управляемая демонстрация переключения, не новый обязательный механизм.

### 37. Дальше — бонусная презентация

Оставшееся время основной части — самостоятельная работа и проверки, не лекция о загрузчике. Бонусная презентация и BONUS.md доступны на стенде.

### 38. «Проверь меня» — кнопки в карточке

POST /api/check с ключом занятия и обязательным worker_id. Ошибки и версии проверяются на выбранном участнике, а не на всех. Кнопка артефакта означает согласие начать установку подготовленного учебного пакета для выбранного клиента; отсутствие install_release даст незачёт, не отключение.

### 39. Пять отдельных результатов

175–180 минут. Показать реальную таблицу проверок. Если времени не хватило, студент может продолжить тем же клиентом, а преподаватель повторит нужный этап. Проверки models и versions запускает преподаватель, обычные HTTP-запросы их не закрывают.

### 40. Что продолжить своим проектом

Связь с темой 3: features. Не вводить обязательную домашнюю работу ради проверки. Полезный пульт и личные модели будут применяться дальше. Тему 4 про маршрутизацию не переносим сюда.

## Ошибки и пакет моделей

### 1. MLOps · Занятие 2 · Бонус



### 2. Что возвращать, если выполнить запрос невозможно?

140–145 минут. Неправильное имя, отсутствующая версия и исключение внутри модели требуют разных причин. Сервер должен получить RESULT, процесс не должен упасть.

### 3. Три причины ошибки

Ошибка выбора возникает до вызова handler. Ошибка исполнения перехватывается только вокруг handler. Не превращать MODEL_NOT_FOUND в INFERENCE_ERROR широким except вокруг всего запускатора.

### 4. Ошибка функции не роняет клиент

145–150 минут. Добавить broken/v1, который бросает исключение. Проверка errors вызовет неизвестное имя, неизвестную версию, broken и затем upper. Timeout в сетевом коде означает пропуск, не успешную учебную ошибку.

### 5. Дополнительное задание: ответ-ошибка

150–155 минут. Отметка errors дополнительная, обязательные models и versions не заменяет. При повторной неудаче прежний зачтённый этап не пропадает, подробности новой попытки остаются в карточке преподавателя.

### 6. Как добавить модель без обновления всего клиента?

155–160 минут. В начале мы вручную положили файл и импортировали функцию. Теперь выполняем ту же последовательность программно. Это бонус для успевающих; остальным дать наблюдать демонстрацию.

### 7. Реестр хранит сведения о выпуске

Реестр — страница /registry и JSON API /registry/models. Артефакт лежит отдельно. Manifest связывает имя, версию, хэш и точку входа. Реестр выпусков не является списком живых воркеров. После отключения всех клиентов запись выпуска остаётся.

### 8. Манифест: паспорт одного выпуска

Напомнить определение из основной части. Манифест сам не исполняет модель. Загрузка файла, импорт модуля и регистрация — разные действия.

### 9. Запись server_echo / v1

Это схема полей с описательным значением хэша, не готовый manifest для проверки. Настоящий хэш приходит от сервера. Копировать вручную не требуется. Используем только учебный артефакт преподавателя.

### 10. Семь выпусков: загрузить нужно весь список

GET /registry/models возвращает releases. Не зашивать семь имён в установщик: читать список и проходить по нему циклом. Проверка вызывает каждый выпуск. Примеры намеренно детерминированы для точного сравнения.

### 11. Сначала получаем список выпусков

Это отдельный учебный фрагмент: можно запустить как fetch_models.py. На сервере всегда JSON со списком releases. Внутри работающего async-клиента блокирующую сеть вынести в asyncio.to_thread; показано дальше.

### 12. Из списка берём паспорт, затем скачиваем код



### 13. Скачиваем файл: URL → байты

Перед urlopen проверить путь по контракту BONUS.md; не принимать произвольный адрес и перенаправления. Код — учебный фрагмент, не готовый универсальный безопасный загрузчик. SHA-256 проверяет соответствие байтов описанию, не доказывает безопасность программы.

### 14. Куда положить скачанный Python

Перед составлением filename валидировать model/version: ASCII [a-zA-Z0-9_]+, без точек и слешей. __file__ — путь текущего Python-файла. Сохранённый файл пока не импортирован. Не использовать имя файла, присланное без проверки.

### 15. Шаг 1. Открываем Python-файл как модуль



### 16. Шаг 2. Забираем функцию и регистрируем



### 17. Новая модель: от загрузчика до запускатора

Загрузчик получил module.infer → зарегистрировал → обычный запускатор может вызвать. Стрелки привязаны к методам внутри файлов. Путь хранения ссылки не означает вызов модели при регистрации.

### 18. Как теперь запустить скачанную модель

Не запускать файл артефакта как приложение: в нём только определение infer. В клиенте уже есть event loop: не вызывать внутри него asyncio.run. Для отдельной локальной проверки написать async main с показанным await, затем asyncio.run(main()).

### 19. Блокирующая сеть и живой пульс

Аналогично получить JSON-список в отдельном потоке. Общие ограничения пути, редиректов и размера сохраняются. Не даём готовый установщик: учащиеся собирают шаги самостоятельно.

### 20. Собираем пакетный установщик

Контракт INSTALL сохранён, но манифест задания теперь описывает пакет. install_release может дополнительно поддерживать старый одиночный manifest. Учительский клиент умеет оба варианта. На ошибке установки отправить INSTALL_ERROR; не говорить INSTALLED до завершения всего списка.

### 21. Почему скачанный код — отдельное доверие?

Попросить открыть oracle_location и проверить: откуда взялась локация? Это строковый литерал. Обсудить, почему хэш от того же издателя подтверждает целостность, но не благонадёжность автора. Никакие реальные эксплуатации и сбор данных не нужны.

### 22. «Проверь меня» — кнопки в карточке

POST /api/check с ключом занятия и обязательным worker_id. Ошибки и версии проверяются на выбранном участнике, а не на всех. Кнопка артефакта означает согласие начать установку подготовленного учебного пакета для выбранного клиента; отсутствие install_release даст незачёт, не отключение.