Перейти к содержимому
Ступень 1111.2 Проектирование ML-систем

Как проектировать ML-систему: схема на 45 минут

Девять шагов проектирования ML-системы — от уточнения задачи до мониторинга — с таймингом для собеседования, оценками «на салфетке» (QPS, память весов и KV-кэша, GPU-секунды, число карт, деньги), схемой системы, компромиссами и типичными ошибками кандидатов.

УРОКstage-11/11-2-system-design/01-design-framework.mdx2 чУрок 1 из 5
После урока вы сможете
  • Пройти задачу проектирования ML-системы по схеме из девяти шагов и уложить разговор в 45 минут
  • Связать бизнес-метрику с онлайн- и офлайн-метриками и назвать бейзлайн без ML
  • Посчитать «на салфетке» нагрузку, память весов и KV-кэша, GPU-секунды на запрос, число карт и стоимость
  • Нарисовать схему системы, проговорить компромиссы и избежать типичных ошибок кандидатов

За курс вы собрали все детали ML-системы по отдельности: данные и их чистку (модуль 11.1), модели от логистической регрессии до своей LLM, RAG и агентов (ступень 8), оценку (7.3, 8.4.2), сервер с лимитами и кэшем (8.4.3), деньги (урок 11.1.5). На работе задачу приносят не по частям. Руководитель говорит: «Продавцы жалуются, что карточки переводятся плохо. Сделайте нормально. Сколько это будет стоить?»

Проектирование ML-системпроектирование ML-системEN ML system designПроектирование всей системы, в которой модель — лишь одна часть: требования, метрики, данные, бейзлайн, модель, оценка, сервинг, мониторинг и цикл обратной связи. Отдельная секция собеседований на ML-инженера. (ML system design) — умение превратить такую фразу в план: что именно улучшаем, как поймём, что стало лучше, из каких данных, какой моделью, на каком железе, за какие деньги и как узнаем, что всё сломалось. На работе результат — дизайн-документдизайн-документEN design documentДокумент на несколько страниц до начала разработки: задача, ограничения, метрики, варианты решения, оценки нагрузки и стоимости, риски. Его обсуждают с командой и по нему потом проверяют, что построили. на несколько страниц до первой строчки кода. На собеседовании — отдельная секция на 45–60 минут; на позиции ML-инженера уровня middle и выше её дают очень часто (из каких ещё этапов состоит собеседование — в уроке 11.3.1).

В этом уроке — схема из девяти шагов, по которой можно пройти любую такую задачу. Разборы 11.2.2–11.2.5 идут по этим же шагам и ссылаются на них по номерам: «шаг 2 — метрики», «шаг 8 — сервинг».

Правильного ответа в такой задаче нет: у сильных инженеров получаются разные системы. Интервьюер смотрит, как вы думаете:

Что видит интервьюерСильный сигналСлабый сигнал
Работа с неопределённостью3–5 уточняющих вопросов, явные допущениясразу рисует модель
Метрикицепочка «бизнес → онлайн → офлайн», защитные метрики«будем мерить accuracy»
Данныеоткуда берутся метки, утечки, разметка«возьмём датасет»
Инженериячисла: нагрузка, память, задержка, деньги«нужно много GPU»
Компромиссы«выбираю X ценой Y; при Z переключусь»одно решение без альтернатив
Эксплуатациямониторинг, откат, цикл данныхсистема заканчивается на деплое
Глубина по запросуспускается в детали любого блоказнает только верхний уровень

Последняя строка важна: интервьюер почти всегда выберет один блок и попросит «копнуть». Поэтому схема не заменяет знаний — она помогает не забыть ни один блок и оставить время на углубление.

flowchart LR
S1["1. Задача и<br/>ограничения"] --> S2["2. Метрики"] --> S3["3. Данные<br/>и разметка"]
S3 --> S4["4. Бейзлайн<br/>без ML"] --> S5["5. Модель"] --> S6["6. Офлайн-<br/>оценка"]
S6 --> S7["7. Онлайн-<br/>эксперимент"] --> S8["8. Сервинг и оценки<br/>на салфетке"] --> S9["9. Мониторинг<br/>и итерации"]
S9 -.->|"ошибки, жалобы,<br/>новые метки"| S3
Девять шагов проектирования; пунктир — цикл данных: продакшен поставляет новые примеры и ошибки
ШагГлавный вопросМинут из 45Где в курсе
1. Задача и ограничениячто именно решаем, для кого, при каких ограничениях511.1.5
2. Метрикикак поймём, что стало лучше для бизнеса и для модели51.3.4, 7.3
3. Данные и разметкаоткуда входы и метки, как избежать утечек52.4, 11.1.1
4. Бейзлайн без MLчто работает без модели и какое число даёт32.1
5. Моделькакой класс моделей и почему, что не выбрали7ступени 2–8
6. Офлайн-оценкана чём и чем мерим до выкатки47.3, 8.4.2
7. Онлайн-эксперименткак сравниваем на живом трафике31.3.4, 11.1.4
8. Сервинг и оценки на салфеткегде и как работает, сколько железа и денег87.1, 8.4.3
9. Мониторинг и итерациикак узнаем о деградации и как улучшаем38.4.2, 11.1.4

Остаются 2 минуты на вопросы и запас. На работе шаги те же, только вместо минут — дни, а вместо доски — дизайн-документ.

Дальше — каждый шаг на сквозном примере. Маркетплейс: продавцы из Китая загружают карточки товаров на китайском, покупателям нужен русский. Задача — автоматический перевод карточек.

Сначала вопросы, потом решения. Что хорошо спросить: сколько карточек в сутки (допустим, 500 000 новых и изменённых); что в карточке (название, характеристики, описание — около 300 токенов на китайском); нужен ли перевод мгновенно или «в течение часа» (второе — значит, можно обрабатывать пачками); что страшнее всего (исказить размер, материал или количество в упаковке); есть ли готовые переводы людей; какое железо и бюджет (одна машина 4× RTX 4080 уже есть).

Вслух фиксируйте допущения: «Считаю, что перевод нужен в течение часа, а не за секунду. Если нужна мгновенная подсказка продавцу при загрузке, архитектура изменится — скажу как». Это не трата времени: от ответа «час или секунда» зависит половина системы.

Метрики выстраиваются в цепочку. Бизнес-метрикабизнес-метрикаEN business metricТо, ради чего строят систему: выручка, конверсия, удержание, доля вопросов, решённых без оператора. ML-метрики (точность, recall@k) полезны, только если связаны с ней. — то, ради чего всё затевается: конверсия переведённых карточек в покупку и доля возвратов с причиной «не соответствует описанию». Онлайн-метрика модели — то, что быстро меряется на живом трафике: добавления в корзину, жалобы на перевод. Офлайн-метрики — то, что меряется на отложенном наборе до выкатки: близость к переводу человека (chrF, BLEUBLEUEN BLEU (bilingual evaluation understudy)Метрика машинного перевода (Papineni и соавт., 2002): среднее геометрическое обрезанных точностей n-грамм (n = 1…4), умноженное на штраф за краткость. От 0 до 1, в статьях — от 0 до 100.), оценка LLM-судьиLLM-судья (LLM-as-a-judge)EN LLM-as-a-judgeСильная модель оценивает ответы другой модели по рубрике или сравнивает пару ответов. Дёшево и быстро, но со смещениями. по рубрике, а главное — доля карточек, где все числа и единицы сохранены: её можно проверить автоматически, сравнив числа в оригинале и переводе.

Плюс защитные метрикизащитная метрикаEN guardrail metricМетрика, которая не должна ухудшиться при выкатке новой версии, даже если главная растёт: задержка, доля жалоб, утечки персональных данных, стоимость запроса. — то, что не должно ухудшиться: задержка публикации, стоимость карточки, доля пустых или обрезанных переводов. Проговорите связь: «Если в переводе исказить размер, покупатель вернёт товар. Поэтому сохранность чисел — офлайн-прокси для возвратов, и порог по ней жёсткий».

Откуда входы: поток карточек от продавцов. Откуда метки: карточки, которые раньше переводили люди, — параллельные пары для оценки и дообучения; словарь брендов и терминов категорий. Частая ловушка — утечка данныхутечка данныхEN data leakage: у одного продавца сотни почти одинаковых карточек, и случайное разбиение по строкам положит их и в обучение, и в тест. Делите по продавцам или по времени.

Разметка для оценки: переводчики размечают 500 карточек по инструкции (точность характеристик, грамматика, стиль), две разметки на часть примеров и каппа Коэнакаппа КоэнаEN Cohen's kappaСогласие двух разметчиков с поправкой на случайное совпадение. 0 — как наугад, 1 — полное согласие. для проверки согласия (урок 11.1.1). Из них собирается золотой наборзолотой набор (тест-набор)EN golden datasetВерсионированный набор входов с эталонными ответами или способом проверки, на котором прогоняют каждую версию промпта или модели..

Бейзлайнбазовое решение, бейзлайнEN baselineПростейшая модель (среднее, самый частый класс), с которой сравнивают всё остальное. — самое простое решение, с которым сравнивают модель. Здесь: словарь шаблонов для характеристик (китайская пара «цвет: чёрный» по таблице превращается в русскую «Цвет: чёрный»), а описание — без перевода, и ручной перевод для самых продаваемых товаров. Второй уровень — готовый машинный переводчик. Первое правило из Google «Rules of Machine Learning»: не бойтесь запустить продукт без ML. Бейзлайн даёт число на шаге 2 и запасной режим на случай аварии. Если модель его не обгоняет, она не нужна.

Назовите 2–3 варианта и выберите с объяснением. Отдельная модель машинного перевода — быстрая, но плохо держит формат и терминологию. Внешний API большой LLM — хорошее качество сразу, но цена на 500 тысяч карточек в сутки и зависимость от провайдера. Открытая LLM, сильная в китайском и русском (например, Qwen3-8B), с LoRALoRA (низкоранговая адаптация)EN low-rank adaptation (LoRA) на параллельных парах (урок 6.2.1) и словарём терминов в промпте — дешевле на объёме и управляемее. Выбор: третий вариант, первый и второй остаются бейзлайнами. Вывод — строгий JSON по полям карточки, чтобы проверять его кодом.

Замороженный золотой набор с разбивкой по категориям; автоматические проверки (числа, формат) — на каждый прогон; LLM-судья, сверенный с людьми (урок 7.3.2); сравнение версий парным бутстрэпом, а не «на глаз». Порог выкатки записывается заранее: «сохранность чисел не ниже 99.5%, судья — не хуже текущей версии в пределах доверительного интервала».

Офлайн-метрика — прокси; правду скажет живой трафик. A/B-тест: случайно делим товары (не показы — иначе один товар покажут в двух переводах) на старую и новую версию, сравниваем конверсию и возвраты с доверительным интервалом (урок 1.3.4). Перед этим — канареечный выпускканареечный выпускEN canary releaseНовая версия сначала получает малую долю трафика (например, 5%); её онлайн-метрики сравнивают со старой, и только потом трафик переключают целиком. на малой доле. Возвраты приходят через недели — заранее скажите, сколько будет длиться тест и по какой метрике решаете раньше.

Где работает модель, в каком режиме, сколько нужно железа и денег. Это шаг, где кандидаты чаще всего говорят общие слова; цифры здесь — сильнейший сигнал. Ему посвящён весь следующий раздел.

Что смотрим каждый день: долю переводов, не прошедших проверку чисел и формата, задержку публикации, загрузку GPU, жалобы продавцов и покупателей, дрейфдрейф данныхEN data driftИзменение распределения входов со временем — новый язык, новые темы, сезонность. Эвал-набор при этом перестаёт отражать реальный трафик. категорий (пришли новые продавцы с электроникой — словарь терминов устарел). Выборочно 50 карточек в день — на проверку судье и раз в неделю людям. Ошибки и жалобы возвращаются в данные (пунктир на схеме), раз в месяц — новая версия через тот же офлайн-гейт и A/B. Инциденты и постмортемы — урок 11.1.4.

Оценка на салфеткеоценка «на салфетке»EN back-of-the-envelope estimateБыстрый расчёт порядка величины по нескольким формулам и округлённым числам: нагрузка, память, скорость, число GPU, деньги. Точность — в пределах 1.5–2 раз; уточняется замером. — расчёт порядка величины за 3–5 минут по нескольким формулам. Цель — не точность до процента, а ответы на вопросы «влезет ли в одну машину», «десятки долларов в день или тысячи» и «что здесь узкое место». Порядок всегда один: нагрузка → токены → память → время на запрос → карты → деньги.

1. Нагрузка. QPSзапросов в секунду (QPS)EN queries per secondМера нагрузки на сервис. Средний QPS = запросы в сутки / 86 400; под железо планируют пиковый — средний, умноженный на пиковый коэффициент. (запросов в секунду) из суточного объёма:

QPSпик=запросов в сутки86 400⋅kпик.\text{QPS}_{\text{пик}} = \frac{\text{запросов в сутки}}{86\,400} \cdot k_{\text{пик}}.

В сутках 86 400 секунд — для прикидки «примерно 10510^5». 500 000 карточек в сутки — это 5.8 в секунду в среднем. Пиковый коэффициент kk показывает, во сколько раз самый нагруженный час выше среднего. У чата сотрудников, которые работают днём, kk = 3–5; у нашей пакетной обработки очередь сглаживает пики, возьмём k=1.5k = 1.5: 8.7 карточки в секунду.

2. Токены. Вход 300, выход 400 токенов: в пик 8.7⋅400≈3 5008.7 \cdot 400 \approx 3\,500 выходных токенов в секунду.

3. Память. Веса Qwen3-8B в BF16 — 8.19⋅109⋅2≈16.48.19 \cdot 10^9 \cdot 2 \approx 16.4 ГБ. KV-кэшKV-кэшEN KV cache одного запроса (уроки 4.6.4 и 5.2.1):

KV=2⋅L⋅G⋅dh⋅b⋅T=2⋅36⋅8⋅128⋅2⋅700≈103 МБ.\text{KV} = 2 \cdot L \cdot G \cdot d_h \cdot b \cdot T = 2 \cdot 36 \cdot 8 \cdot 128 \cdot 2 \cdot 700 \approx 103\ \text{МБ}.

Двойка — K и V, L=36L = 36 слоёв, G=8G = 8 KV-голов, dh=128d_h = 128, b=2b = 2 байта, T=300+400T = 300 + 400 токенов. На карте 32 ГБ движку отдаём 90%, гигабайт оставляем на служебное: (28.8−1−16.4)/0.103≈110(28.8 - 1 - 16.4) / 0.103 \approx 110 карточек одновременно.

4. Время карты на запрос. Prefill упирается в вычисления: 2N2N операций на токен (урок 7.1.1), при 97.5 TFLOPS RTX 4080 и MFUутилизация FLOPs модели (MFU)EN model FLOPs utilization (MFU)Доля пиковой производительности железа, которая уходит на полезные вычисления модели. Для больших распределённых обучений типичны 30–50 %. 0.5 это 2⋅8.19⋅109⋅300/(48.75⋅1012)≈0.102 \cdot 8.19 \cdot 10^9 \cdot 300 / (48.75 \cdot 10^{12}) \approx 0.10 с. Decode упирается в память: каждый шаг читает веса и KV-кэш всех последовательностей батча. При батче 64 по rooflineмодель roofline («крыша»)EN roofline modelДостижимая производительность = min(пик FLOP/с, интенсивность × пропускная способность памяти). Точка перегиба (ridge point) = пик / пропускная способность; у H100 около 295 FLOP/байт.:

tшаг=max⁡(16.4+64⋅0.103716.8, 2⋅8.19⋅109⋅6497.5⋅1012)=max⁡(32.1 мс, 10.8 мс)=32.1 мс.t_{\text{шаг}} = \max\left(\frac{16.4 + 64 \cdot 0.103}{716.8},\ \frac{2 \cdot 8.19 \cdot 10^9 \cdot 64}{97.5 \cdot 10^{12}}\right) = \max(32.1\ \text{мс},\ 10.8\ \text{мс}) = 32.1\ \text{мс}.

Шаг даёт по токену всем 64 карточкам, так что на одну приходится 400⋅32.1/64≈200400 \cdot 32.1 / 64 \approx 200 мс. Итого 0.30 GPU-секунды на карточку. Без батча (по одной карточке) вышло бы 9.3 GPU-секунды — в 31 раз дороже: вот зачем нужен непрерывный батчинг (урок 7.1.2).

5. Карты. Каждую секунду приходит 8.7 карточки по 0.30 GPU-секунды — нужно 2.6 карты, занятых на 100%. Ниже 100% держим запас (здесь 0.7), чтобы очередь не росла в пиковые часы:

карт=⌈QPS⋅GPU-с на запрос0.7⌉=⌈3.74⌉=4.\text{карт} = \left\lceil \frac{\text{QPS} \cdot \text{GPU-с на запрос}}{0.7} \right\rceil = \lceil 3.74 \rceil = 4.

Ответ: одна машина 4× RTX 4080, впритык. При миллионе карточек в сутки — восемь карт.

6. Деньги. Допустим, час работы своей карты стоит 0.5 долл. (амортизация и электричество; условная цена). Четыре карты — 48 долл. в сутки, около 0.1 долл. за тысячу карточек. Для сравнения, если API берёт 0.30 долл. за миллион входных и 1.20 долл. за миллион выходных токенов (тоже условные цены — проверяйте актуальные), карточка стоит (300⋅0.3+400⋅1.2)/106=0.00057(300 \cdot 0.3 + 400 \cdot 1.2) / 10^6 = 0.00057 долл., а сутки — 285 долл. Как сравнивать честно, с людьми и простоем, — в уроке 11.1.5.

Числа, которые стоит помнить:

ЧтоЗначениеОткуда
Секунд в сутках86 400 ≈ 10510^5
Операций на токен (прямой проход)2N2N7.1.1
Байт на параметрBF16 — 2, INT8 — 1, INT4 — 0.5–0.67.2.1
KV-кэш на токенLlama 3 8B — 128 КиБ, Qwen3-8B — 144 КиБ5.2.1
RTX 4080717 ГБ/с, 97.5 TFLOPS BF16 (паспорт штатной карты; для 32-гигабайтной — допущение)5.7.1
H100 SXM3 350 ГБ/с, 989 TFLOPS BF167.1.1
Потолок decode при батче 1ГБ/с ÷ ГБ весов (8B BF16 на 4080 — 44 токена/с)7.1.1
Реальность против потолка50–85%7.1.1

Как рисовать схему и говорить о компромиссах

Заголовок раздела «Как рисовать схему и говорить о компромиссах»

Схема на доске — 6–10 прямоугольников и стрелок. Рисуйте два контура: онлайн (что происходит с одним запросом) и офлайн (как появляются и обновляются данные и модели). Подписывайте на стрелках числа: QPS, размер, задержку.

flowchart LR
subgraph ON["Онлайн-контур"]
  P["Продавец<br/>загружает карточку"] --> Q["Очередь<br/>8.7 карточки/с в пик"]
  Q --> M["vLLM: Qwen3-8B + LoRA<br/>4× RTX 4080, батч 64"]
  M --> V{"Проверки:<br/>числа, JSON"}
  V -->|"ок"| PUB["Публикация"]
  V -->|"ошибка"| FB["Бейзлайн:<br/>шаблоны + ручная очередь"]
end
subgraph OFF["Офлайн-контур"]
  D["Пары переводов,<br/>словарь терминов"] --> T["Дообучение LoRA"] --> E["Эвал-набор:<br/>гейт выкатки"]
end
E --> M
PUB -.->|"жалобы, возвраты,<br/>выборка на проверку"| D
Схема системы перевода карточек: онлайн-контур с запасным путём и офлайн-контур с эвал-гейтом

Компромисс проговаривайте по формуле «выбираю — плачу — передумаю, если». Примеры:

РазвилкаВыборЦенаПередумаю, если…
Своя модель или APIсвоя Qwen3-8Bнужны люди и железообъём упадёт ниже точки безубыточноститочка безубыточностиEN break-even pointОбъём нагрузки, при котором два варианта стоят одинаково, например свои GPU (постоянный расход) и API (плата за токены). Ниже точки дешевле API, выше — свои карты, пока им хватает мощности.
BF16 или INT8BF16 на стартебольше памяти, меньше батчнагрузка вырастет — INT8 после проверки на эвале
Пакетно или мгновенноочередь, до часапродавец ждётнужна подсказка при загрузке — отдельный быстрый путь
Одна большая модель или каскадодна 8Bдорого для простых карточектреть карточек — короткие шаблонные: их шаблонам

Фраза целиком: «Беру свою 8B-модель, а не API: на 500 тысячах карточек в сутки она в разы дешевле, данные не уходят наружу. Плачу тем, что поддерживаем железо сами. Если объём упадёт в 20–30 раз, даже одна своя карта будет дороже API — пересчитаю».

ОшибкаКак звучитПочему плохоКак правильно
Сразу к модели«Возьмём Qwen3-32B и дообучим» на первой минутенеизвестно, что оптимизируем и при каких ограничениях5 минут на вопросы и допущения
Нет метрики«Сделаем перевод лучше»«лучше» не измерить, нельзя принять решениецепочка бизнес → онлайн → офлайн
ML-метрика без бизнеса«BLEU вырастет на 2 пункта»бизнес может этого не заметитьобъяснить, как офлайн-метрика двигает бизнес-метрику
Нет бейзлайнасразу нейросетьне с чем сравнить; может, ML не нуженпростое решение и его число
Нет мониторингасистема кончается деплоемдеградация останется незамеченнойчто мониторим, тревоги, цикл данных
Нет чисел«нужно много GPU»неясно, реалистичен ли проектсалфетка за 3–5 минут
Утечка в оценкеслучайное разбиение по строкамофлайн-метрика завышенаразбиение по продавцам или по времени
Монолог40 минут без паузинтервьюер не может направить разговорпауза после каждого шага: «Углубиться здесь?»

Сразу к модели, нет метрики, нет бейзлайна, нет мониторинга — четыре самых частых провала, и ровно от них защищает схема. Против всех помогает одно — пройти девять шагов по порядку, даже если кажется, что «всё и так понятно».

  1. Возьмите задачу из разборов этого модуля, поставьте таймер на 45 минут и проговорите решение вслух. Запишите на диктофон и послушайте: где молчали, где ушли в детали, где не было чисел.
  2. Заполняйте по ходу шаблон DESIGN.md из домашней работы s11-hw04-capacity — его разделы повторяют девять шагов, а оценкам на салфетке и компромиссам отведены отдельные разделы.
  3. Попросите ИИ сыграть интервьюера. Промпт:
Ты — интервьюер на секции ML system design в продуктовой компании. Задача для меня: «<формулировка>».
Правила: не давай решения; отвечай на мои уточняющие вопросы как заказчик (придумывай правдоподобные числа);
после каждого моего шага задавай один углубляющий вопрос; через 45 минут остановись и оцени меня по пунктам:
уточнение задачи, метрики, данные, бейзлайн, модель, оценка, сервинг и числа, мониторинг, компромиссы.
Назови две сильные стороны и три главных пробела.
  1. Ошибки, которые повторяются от задачи к задаче, записывайте в тетрадь ошибок.

Соберите функции оценок на салфетке и проверьте ими пример урока: пиковый QPS, закон Литтла, KV-кэш запроса, GPU-секунды на запрос по roofline и число карт.

Оценки «на салфетке»: от суточной нагрузки до числа карт7 тестов
# Оценки «на салфетке» для ML-сервиса: нагрузка, KV-кэш, GPU-секунды и число карт.
# Единицы: память весов — ГБ (1e9 байт), KV-кэш — МБ (1e6 байт), пропускная способность — ГБ/с,
# пиковая производительность — TFLOPS (1e12 операций в секунду), время — секунды.
# По умолчанию — паспорт RTX 4080 (урок 5.7.1): 716.8 ГБ/с и 97.5 TFLOPS в BF16.
import math


def peak_qps(requests_per_day, peak_factor):
    """Пиковые запросы в секунду: среднее за сутки × пиковый коэффициент.

    В сутках 86 400 секунд. peak_qps(500_000, 1.5) ≈ 8.68;  peak_qps(86_400, 1) == 1.0
    """
    # TODO: ваш код
    ...


def concurrent_requests(qps, seconds_per_request):
    """Закон Литтла (урок 8.4.3): сколько запросов одновременно в системе, L = λ · W.

    concurrent_requests(2, 8) == 16
    """
    # TODO: ваш код
    ...


def kv_cache_mb(n_layers, n_kv_heads, head_dim, tokens, bytes_per_value=2):
    """KV-кэш одной последовательности в МБ (1 МБ = 1e6 байт).

    2 (K и V) · слои · KV-головы · head_dim · токены · байт на число.
    Qwen3-8B (36 слоёв, 8 KV-голов, 128) на 700 токенах в BF16 ≈ 103.2 МБ.
    """
    # TODO: ваш код
    ...


def gpu_seconds_per_request(n_params, prompt_tokens, output_tokens, weights_gb, kv_mb_per_seq, batch,
                            bandwidth_gbs=716.8, peak_tflops=97.5, mfu=0.5):
    """Сколько секунд работы одной GPU уходит на один запрос.

    prefill = 2 · N · T_in / (peak · 1e12 · mfu) — карта занята этим запросом целиком;
    шаг decode по roofline = max((веса + batch · KV) / пропускная способность, 2 · N · batch / (peak · 1e12));
    один шаг даёт по токену всем batch запросам, поэтому на запрос приходится output_tokens · шаг / batch.
    Ответ — prefill + доля decode. Не забудьте перевести ГБ, МБ и TFLOPS в байты и операции.
    """
    # TODO: ваш код
    ...


def gpus_needed(qps, gpu_seconds, max_utilization=0.7):
    """Число карт: каждую секунду нужно qps · gpu_seconds GPU-секунд работы.

    Делим на max_utilization (запас на пики), округляем вверх (math.ceil), минимум одна карта.
    gpus_needed(8.68, 0.3, 0.7) == 4
    """
    # TODO: ваш код
    ...


# Пример из урока: перевод 500 000 карточек товаров в сутки, Qwen3-8B в BF16 на RTX 4080.
qps = peak_qps(500_000, 1.5)
kv = kv_cache_mb(36, 8, 128, 300 + 400)
print("пиковый QPS:", qps, "| KV-кэш, МБ:", kv)
if qps is not None and kv is not None:
    gs = gpu_seconds_per_request(8.19e9, 300, 400, 16.4, kv, 64)
    print("GPU-секунд на запрос:", gs, "| карт:", gpus_needed(qps, gs) if gs is not None else None)
Проверь себя6 вопросов
1 Интервьюер дал задачу «сделайте рекомендации статей в новостном приложении». С чего начать?
2 Сервис получает 2 000 000 запросов в сутки, пиковый коэффициент 3. Каков пиковый QPS? Округлите до десятых.
3 Сколько мегабайт (10610^6 байт) KV-кэша в BF16 займёт один запрос на 4000 токенов у модели с 28 слоями, 4 KV-головами и head_dim = 128 (как у Qwen2.5-7B)? Округлите до целого.
4 На запрос уходит 0.5 GPU-секунды, пиковая нагрузка — 10 запросов в секунду, запас загрузки 0.7. Сколько карт нужно?
5 Какие из утверждений — типичные ошибки на секции ML system design? Выберите все.Можно выбрать несколько ответов
6 Почему в примере урока батч 64 удешевил карточку в 31 раз по сравнению с обработкой по одной?
  • Задача проектирования ML-системы проходится по девяти шагам: задача и ограничения → метрики → данные → бейзлайн → модель → офлайн-оценка → онлайн-эксперимент → сервинг → мониторинг, и цикл данных замыкает систему.
  • Метрики выстраиваются в цепочку от бизнеса к офлайн-прокси, плюс защитные. Бейзлайн без ML — обязательная планка.
  • Салфетка: QPS = сутки / 86 400 × пик; KV = 2LGdhbT2 L G d_h b T; GPU-секунды = prefill + шаг decode × токены / батч; карт = ⌈QPS × GPU-с / запас⌉; деньги — карты × часы × цена. Ответ даём диапазоном и уточняем замером.
  • Компромиссы проговариваем по формуле «выбираю — плачу — передумаю, если», а после каждого шага делаем паузу для вопроса интервьюера.

Для систем со сложными бизнес-правилами к дизайн-документу полезно добавить модель предметной области: какие части бизнеса главные, где границы контекстов, какие правила охраняет код. Этому посвящена программа DDD; описание главной части системы на одну страницу — в уроке DDD.1.3.

Дальше: «Разбор: ассистент поддержки на RAG» — первая задача, пройденная по этой схеме целиком.