Metaflow — это фреймворк, работу над которым мы начали в 2019. В том же году мы открыли его исходный код. Теперь он обеспечивает функционирование широкого спектра ML/AI-систем в Netflix, а так же — во многих других компаниях. Он пользуется любовью тех, кто его применяет, так как он помогает им доводить их ML/AI-идеи от стадии прототипа до продакшна. Он позволяет им уделять внимание не решению рутинных задач, а созданию современнейших систем, которые дарят радость людям по всему миру и развлекают их.

Metaflow даёт разработчикам следующие возможности:
Он минимизирует затраты времени, необходимые на решение вспомогательных задач, позволяя быстро проходить по шагам итеративного процесса разработки программ и добираться до релизных версий продуктов.
Он позволяет, в масштабах Netflix, надёжно и с минимальными накладными расходами эксплуатировать системы, выведенные в продакшн.
Metaflow, обеспечивая вторую из перечисленных возможностей, способен взаимодействовать со множеством наборов инструментов, проверенных, так сказать, в боевых условиях. Среди них можно отметить Maestro — наш оркестратор рабочих процессов. Мы недавно открыли его код. Он лежит в основе почти каждой ML/AI- системы Netflix и сам играет роль базовой платформы, в которой работает Metaflow.
В этом материале мы сосредоточимся на первом пункте вышеприведённого списка и расскажем о новом функционале Metaflow — о команде spin, которая помогает программистам ускорять итеративную разработку продуктов. Вы, когда дочитаете эту статью, будете хорошо ориентироваться в возможностях spin и узнаете о том, как самостоятельно испытать эту команду в Metaflow 2.19.
Итеративная разработка в сферах ML и AI

Для того чтобы понять наш подход к совершенствованию опыта разработки ML/AI-систем, полезно разобраться в том, чем соответствующие рабочие процессы отличаются от традиционного программирования.
ML/AI-разработка, фигурально выражаясь, крутится не только вокруг кода, но и вокруг данных, и вокруг моделей. Модели — это большие программные системы, которые подвержены изменениям, на обработку которых уходит много дорогостоящих вычислительных ресурсов. Циклы итеративной разработки могут включать в себя длительные преобразования данных, обучение моделей, для них характерны стохастические процессы, которые, от запуска к запуску, дают слегка отличающиеся результаты. Эти особенности итеративной разработки делают быстрое проведение итераций с запоминанием состояния системы важнейшей составной частью среды, способствующей продуктивной работе над проектами.
Именно в таких условиях великолепно показывают себя различные «блокнотные» среды — вроде Jupyter, Observable или Marimo. То, что они умеют сохранять состояние системы в памяти, позволяет разработчикам, единожды загрузив набор данных, итеративно его исследовать, преобразовывать, визуализировать. И всё это — без необходимости на каждом шаге работы всё перезагружать и пересчитывать. Такие вот интерактивные среды, хранящие состояние производимых в них вычислений, делают решение задач гибким, позволяют разработчикам заниматься исследованиями систем и данных. Это сильно отличается от подхода, в основе которого лежат медленные и жёсткие циклы разработки. В результате получается, что «блокноты» идеально подходят тем, кто занимается машинным обучением и искусственным интеллектом.
ML/AI-разработка — это сфера деятельности, где никого не удивишь «тяжёлыми» вычислениями и стохастическим поведением систем. Центральная роль здесь принадлежит данным и моделям. Поэтому инструменты, которые нацелены на оптимизацию скорости итераций, должны ставить во главу угла управление состоянием проектов. Получается, что любая система, которая нацелена на улучшение опыта разработки в этой сфере, должна поддерживать быстрое и инкрементальное проведение экспериментов, сохраняя при этом связь между итерациями, не теряя состояния системы.
Новшество: быстрая итеративная разработка с использованием spin
На первый взгляд код Metaflow выглядит как описание рабочего процесса (workflow) — это похоже на Airflow. Но есть и ещё одна точка зрения, с которой его можно рассматривать. Каждый фрагмент кода, при оформлении которого использован декоратор Metaflow @step, играет роль границы контрольной точки. В конце каждого шага фрагмента @step Metaflow автоматически сохраняет все переменные экземпляра в виде артефактов, позволяя, без дополнительных усилий, возобновить выполнение программы с этой точки. Нижеприведённая анимация иллюстрирует это поведение.

В некотором смысле декоратор @step можно сравнить с ячейкой «блокнота». Это — наименьшая единица выполнения программы, которая обновляет состояние системы после завершения выполнения. Правда, у этой сущности имеется несколько особенностей, направленных на то, чтобы избавиться от проблем, характерных для «блокнотных» ячеек:
Явный и детерминированный порядок выполнения команд: разработчика не будут ждать неприятные сюрпризы, вызванные выполнением ячеек не в том порядке, в котором он ожидает.
Состояние программы не скрыто: состояние явным образом сохраняется в переменных
self. в виде общего состояния, которое можно найти и исследовать.Состояние версионируется и хранится постоянно: это позволяет повысить воспроизводимость результатов.
Хотя применение команды resume в Metaflow и может напоминать инкрементальный итеративный подход, характерный для «блокнотов», надо отметить, что она возобновляет выполнение кода с выбранного фрагмента @step. Это приводит к росту задержек между итерациями. А вот «блокноты», в отличие от такого подхода, позволяют практически мгновенно увидеть результаты, позволяя пользователям подстраивать и перезапускать отдельные ячейки и тут же повторно используя данные из ячеек, расположенных до них.
Новая команда spin, которая появилась в Metaflow 2.19, нацелена на устранение именно этого недостатка. Так же, как выполняют отдельные ячейки «блокнотов», она позволяет быстро перезапустить отдельный фрагмент @step в Metaflow. При этом она использует данные из состояния программы, относящиеся к родительским фрагментам @step. В результате пользователи могут заниматься разработкой и отладкой @step-фрагментов кода Metaflow, работая с ними так же легко и удобно, как я ячейками «блокнотов».
Полезный эффект этого новшества совершенно очевиден в том случае, если рассмотреть три взаимодополняющих режима выполнения кода — run, resume и spin, сопоставив их поведение с поведением, характерным для «блокнотов».

Ещё одно важное отличие между spin и другими командами заключается не только в том, что именно выполняется, а в том, что именно система сохраняет. И команда run, и команда resume создают полный, версионированный сеанс запуска кода, сохраняя все метаданные и артефакты. А вот spin вообще ничего не отслеживает. Эта команда создана для быстрого запуска кода в ходе разработки без сохранения каких-либо результатов запуска этого кода.
Следующий короткий клип иллюстрирует типичный итеративный процесс разработки, когда программист использует то run, то spin. В этом примере мы создаём рабочий процесс, который читает набор данных из файла Parquet и обучает отдельные модели для каждой товарной категории, обращая особое внимание на категории, связанные с компьютерами.
↓ Ссылка на YoTube: Процесс разработки в Metaflow с использованием spin
Тут видно, что мы начинаем с создания нового рабочего процесса и запускаем его минимальную версию, чтобы сохранить на постоянной основе артефакты, нужные при тестировании. В данном случае это — набор данных из файла Parquet. Начиная с этого момента мы можем использовать spin для того чтобы работать над одним @step-фрагментом, перезапуская его тогда, когда нужно, постепенно наращивая функционал рабочего процесса. Например, как показано в видео, за счёт добавления параллельных шагов обучения модели.
После того, как со @step-фрагментом поработали на локальной машине, его можно без лишних усилий передать продуктовой системе оркестрации кода, вроде Maestro или Argo. Этот фрагмент кода можно запустить в масштабируемой среде различных вычислительных платформ вроде AWS Batch, Titus, Kubernetes и так далее. В результате Metaflow даёт те же удобства, что и «блокнотные» среды, но при этом получающиеся рабочие процессы готовы к продакшну и к запуску на масштабируемых вычислительных мощностях. А выглядит это всё как вполне привычный Python-проект!
Организация удобного процесса разработки в VSCode/Cursor
Вместо того, чтобы вручную вводить команды run и spin в терминале, их можно привязать к сочетаниям клавиш. Например, простое расширение metaflow-dev-vscode для VSCode (оно работает и в Cursor) связывает команду run с сочетанием клавиш Ctrl+Opt+R, а команду spin — с сочетанием Ctrl+Opt+S. В процессе работы достаточно периодически нажимать Ctrl+Opt+S и расширение будет сохранять файл и запускать команду spin в применении к тому @spin-фрагменту, который редактирует программист.
А вот — одна из задач, в которой spin раскрывается во всей красе. Это — создание небольших информационных панелей и отчётов с помощью системы визуализации данных Metaflow Cards. Визуализация данных — это ещё одна сильная возможность «блокнотов», но комбинация spin и системы Metaflow Cards — это весьма достойная альтернатива в деле создания визуализаций, работающих в реальном времени и выводящих данные после выполнения кода. Разработка графических систем с помощью Metaflow Cards — это процесс, который, по своей природе, отличается итеративностью и мгновенным откликом визуальной составляющей проекта на изменения кода. Это очень похоже на создание веб-страниц, когда разработчик рассчитывает на то, что изменения кода сразу же приводят к видимым результатам. Такой подход к работе полностью поддерживается благодаря связке VSCode/Cursor, где имеется встроенный просмотрщик веб-материалов, локального средства просмотра сущностей Metaflow Cards и команды spin.
Для того чтобы продемонстрировать это трио инструментов в действии — вместе с соответствующим расширением VSCode — мы подготовили короткий видеоклип, где разработчик визуализирует данные шага обучения модели, созданного в одном из предыдущих примеров.
↓ Ссылка на YoTube: Использование команды spin для разработки системы визуализации данных с помощью Metaflow Cards
Главная сильная сторона Metaflow Cards заключается в том, что для визуализации данных и для наблюдения за ними не нужно развёртывать дополнительные службы и базы данных, не нужно организовывать особые потоки данных. Для этого достаточно, как показано выше, описать визуальную составляющую проекта, разработать рабочий процесс и получить на выходе самодостаточную систему продакшн-уровня, в состав которой, кроме прочего, входит подсистема создания отчётов и визуализации данных.
Продвинутое использование команды spin: внедрение входных данных и исследование выходных данных
Выполнение кода — это не единственная возможность команды spin. Она, кроме прочего, позволяет нам обрести полный контроль над входными и выходными данными запущенного ей @step-фрагмента. Это открывает путь ко множеству продвинутых подходов к разработке.
Мы, в отличие от того, что позволяют «блокноты», можем запустить с помощью spin любой произвольно выбранный @step-фрагмент в рабочем процессе, используя состояние проекта, оставшееся после любых предыдущих сеансов его запуска. Это упрощает тестирование функций с различными входными данными. Например, если имеется множество моделей, полученных после нескольких предыдущих запусков кода, можно несколько раз запустить командой spin тот фрагмент, который отвечает за формирование вывода модели, каждый раз передавая ему новую модель.
Ещё с помощью spin можно переопределять значения артефактов или внедрять в код произвольные Python-объекты. Это похоже на то, что позволяют «блокноты». Для этого достаточно объявить Python-модуль со словарём ARTIFACTS:
ARTIFACTS = {
"model": "kmeans",
"k": 15
}Затем надо передать этот модуль spin:
spin train --artifacts-module artifacts.pyКоманда spin, по умолчанию, не хранит артефакты. Но это поведение несложно изменить, добавив при её запуске ключ --persist. Но даже при таком подходе система не сохраняет артефакты в обычном хранилище данных Metaflow. Они попадают в место, зависящее от директории проекта, что позволяет легко удалить ненужные данные после тестирования кода. Доступ к данным можно получить, как обычно, через API Client — достаточно, с помощью функции inspect_spin, указать директорию, содержимое которой нужно изучить:
from metaflow import inspect_spin
inspect_spin(".")
Flow("TrainingFlow").latest_run["train"].task["model"].dataИмея возможность быстро и удобно исследовать и модифицировать входные и выходные данные @step-фрагмента кода, программист получает в своё распоряжение удобный и мощный инструмент: систему модульного тестирования отдельных фрагментов кода, декорированных с помощью @step. Команду spin можно использовать программно, посредством API Runner, и проверять результаты с помощью утверждений:
from metaflow import Runner
with Runner("flow.py").spin("train", persist=True) as spin:
assert spin.task["model"].data == "kmeans"Использование spin AI-агентами, пишущими код
Команда spin способна помочь не только программистам-людям. Она оказалась удивительно полезной в среде AI-агентов, пишущих код. У того, чтобы научить агента тому, как пользоваться командой spin, есть два основных плюса:
Это ускоряет цикл разработки. Агенты, по своей природе, не знают о том, что такое «медленно», или о том, почему скорость разработки имеет значение. Поэтому им нужно давать подсказки, в соответствии с которыми они отдавали бы предпочтение более быстрым инструментам, отказываясь от инструментов медленных.
Это помогает быстрее находить ошибки и связывать их с конкретными участками кода, увеличивая шансы того, что агент сможет исправлять ошибки самостоятельно.
Пользователи Metaflow уже применяют Claude Code, а spin значительно облегчает им жизнь. В следующем примере мы добавили в файл CLAUDE.md следующий раздел:
## Developing Metaflow code
Follow this incremental development workflow that ensures quick iterations
and correct results. You must create a flow incrementally, step by step
following this process:
1. Create a flow skeleton with empty `@step`s.
2. Add a data loading step.
3. `run` the flow.
4. Populate the next step and use `spin` to test it with the correct inputs.
5. `run` the flow to record outputs from the new step.
5. Iterate on (4–5) until all steps have been implemented and work correctly.
6. `run` the whole flow to ensure final correctness.
To test a flow, run the flow as follows
```
python flow.py - environment=pypi run
```
Do this once before running `spin`.
As you are building the flow, you `spin` to test steps quickly.
For instance
```
python flow.py - environment=pypi spin train
```Этих коротких инструкций достаточно для того, чтобы агент начал бы эффективно применять spin. Взгляните на следующий пример, выглядящий довольно-таки вдохновляюще. Здесь Claude, без дополнительных вопросов, создаёт рабочий процесс (в духе предыдущих примеров), где осуществляется обучение классификатора, который должен прогнозировать товарные категории.
↓ Ссылка на YoTube: Агент Claude тоже может пользоваться spin
Здесь, примерно на 45-й секунде записи, можно видеть, как Claude вызывает spin для тестирования @step-фрагмента preprocess. Этот фрагмент сразу тест не проходит — система сталкивается с классической data science-проблемой: в ходе тестирования Claude берёт образцы лишь из небольшого подмножества данных, в результате чего некоторые классы оказываются недостаточно представленными в итоговой выборке. Первый запуск spin выявляет проблему, которую Claude решает, переключаясь на стратифицированную выборку. Далее — агент снова запускает spin, чтобы, перед продолжением решения задачи, проверить правильность изменений.
Полный цикл ML- AI-разработки
Возвращаясь к тому, с чего мы начали, напомним, что причина, по которой мы добавили в Metaflow команду spin, и, в целом — причина создания Metaflow — это ускорение циклов разработки программного обеспечения. А нужно это для того, чтобы приносить нашим клиентам больше положительных эмоций. В конечном итоге мы уверены в том, что не существует некой единственной «волшебной палочки», по мановению которой всё вдруг получится. Вклад в совершенствование наших процессов разработки вносит согласованная работа всех частей нашей ML/AI-платформы, в число которых входит и spin.
С этой точки зрения полезно, рассматривая spin, поместить этот инструмент в среду других средств Metaflow, представленную на следующей схеме. Команда spin предназначена для того цикла разработки моделей и бизнес-логики, который глубже всех остальных скрыт в недрах компании. Здесь же отражены возможности spin по модульному тестированию кода в процессе разработки.

Здесь прямоугольники, закрашенные синим, представляют различные команды Metaflow, а синим текстом выделены имена декораторов и других подобных объектов. В частности — обратите внимание на блок Shared Functionality. В последний год мы много внимания уделяли тому, что в нём находится. В него входят инструменты для управления конфигурациями и пользовательские декораторы. Эти возможности позволяют командам, решающим собственные задачи, а так же — компаниям, поддерживающим работу вычислительных платформ, подгонять Metaflow под собственные нужды. Всё это, в соответствии с нашими принципами, касающимися компонуемости сущностей, тоже отлично интегрируется со spin.
Ещё один важный аспект философии Metaflow заключается в том, чтобы позволить разработчикам начинать с малого, усложняя свои проекты только тогда, когда это будет нужно. Поэтому не надо пугаться вышеприведённой схемы. Для того чтобы начать работать с Metaflow — установите его такой вот командой:
pip install metaflowА потом создайте свой первый маленький фрагмент кода с декоратором @step и запустите его с помощью spin! Загляните в документацию, а если будут вопросы — присоединяйтесь к дружелюбному Slack-сообществу Metaflow.
О, а приходите к нам работать? 🤗 💰
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.
