Разбор: LLM-платформа внутри компании
Проектируем по схеме из 11.2.1 внутреннюю LLM-платформу для десятков команд — шлюз с OpenAI-совместимым API, маршрутизация между своими моделями и внешними API, квоты и учёт расходов, кэш, пул vLLM, выкатка через эвал-гейт, guardrails и логи без персональных данных — и считаем, сколько пользователей выдержит одна машина 4× RTX 4080.
Зачем это нужно
Заголовок раздела «Зачем это нужно»Через год после первых экспериментов с LLM в средней компании картина похожа: сорок команд, у каждой свой ключ внешнего API прямо в коде, свои повторы, свой кэш и свой способ логировать. Никто не знает, сколько компания тратит на токены и какая команда отправляет наружу паспортные данные клиентов. Провайдер снимает модель с поддержки — и половина сервисов ломается в один день. А ещё каждая команда просит себе отдельную видеокарту.
Ответ — внутренняя LLM-платформа: один вход ко всем моделям, свои и внешние, с контролем качества, денег и безопасности. Это продукт, пользователи которого — инженеры. Задача частая и на собеседовании: на ней видно, понимает ли кандидат инференс (ступень 7) и продакшен (модуль 8.4) одновременно. Пройдём её по девяти шагам из урока 11.2.1, а на шаге 8 посчитаем, сколько пользователей выдержит одна машина 4× RTX 4080.
Шаг 1. Задача и ограничения
Заголовок раздела «Шаг 1. Задача и ограничения»Уточняющие вопросы: сколько команд и сценариев; какие модели нужны (свои, внешние); есть ли в запросах персональные данные и коммерческая тайна; какие требования к задержке; какое железо есть сейчас; кто платит за токены. Допущения, которые фиксируем вслух:
| Параметр | Допущение |
|---|---|
| Команды | 40 сейчас, около 100 через год |
| Сценарии | чат-ассистенты, RAG по документам, суммаризация и классификация обращений, помощь с кодом, ночные пакетные задачи |
| Модели | свои открытые (Qwen3-8B, Qwen3-32B, эмбеддинги BGE-M3) и 2–3 внешних API |
| Пользователи | до 10 000 сотрудников через приложения команд |
| SLO интерактива | p95 TTFT ≤ 2 с, TPOT ≤ 50 мс; доступность шлюза 99.9% |
| Данные | часть запросов содержит персональные данные (ПДн) и коммерческую тайну |
| Железо | три машины 4× RTX 4080 32 ГБ, бюджет на рост |
Чего платформа не делает: не обучает свои базовые модели и не строит продукты за команды. Это ограничение масштаба, и его стоит проговорить: иначе разговор уйдёт в претрейн.
Шаг 2. Метрики
Заголовок раздела «Шаг 2. Метрики»У платформы нет «своей» выручки: её ценность — скорость команд и контроль рисков. Поэтому цепочка метрик выглядит так:
| Уровень | Метрика | Зачем |
|---|---|---|
| Бизнесбизнес-метрикаEN business metricТо, ради чего строят систему: выручка, конверсия, удержание, доля вопросов, решённых без оператора. ML-метрики (точность, recall@k) полезны, только если связаны с ней. | время от заявки команды до первого вызова в продакшене; число сценариев в продакшене | платформа ускоряет, а не тормозит |
| Принятие | доля LLM-трафика компании, идущего через платформу | если команды ходят в обход — платформа неудобна |
| Деньги | стоимость 1 млн токенов по моделям; расходы команд против бюджета; экономия от кэша и маршрутизации | главный аргумент для руководства |
| Надёжность | доступность; p95 TTFT и TPOT по классам; доля ответов 429 и 5xx | целевой уровень сервисацелевой уровень сервиса (SLO)EN service level objectiveИзмеримая цель, например «p95 TTFT меньше 2 с при 8 пользователях». По ней планируют железо и поднимают тревоги. |
| Качество | доля сценариев с эвал-набором; результаты эвал-гейта | платформа не может мерить качество за команды, но может требовать эвалы |
| Защитные | утечки ПДн во внешние API (цель — ноль), инциденты инъекций | защитные метрикизащитная метрикаEN guardrail metricМетрика, которая не должна ухудшиться при выкатке новой версии, даже если главная растёт: задержка, доля жалоб, утечки персональных данных, стоимость запроса. |
Связь: чем быстрее и безопаснее подключение, тем больше команд приходит на платформу, тем больше трафика под контролем и тем выше загрузка своих GPU — а значит, ниже цена токена.
Шаг 3. Данные
Заголовок раздела «Шаг 3. Данные»У платформы три вида данных. Логи запросов — с маскированием ПДн, сроком хранения и доступом по ролям; из них же команды собирают эвал-наборы. Статистика потребления — токены по командам, моделям и часам: по ней видно пиковый коэффициент и рост, это вход для планирования мощности. Эвал-наборы сценариев — версионированные золотые наборызолотой набор (тест-набор)EN golden datasetВерсионированный набор входов с эталонными ответами или способом проверки, на котором прогоняют каждую версию промпта или модели., которые команда приносит при подключении; без них платформа не сможет проверить, не сломает ли новая модель чужой сценарий.
Ещё одна вещь — класс данных у каждого ключа: при подключении команда указывает, что уходит в запросах (публичное, внутреннее, ПДн). От класса зависит маршрутизация на шаге 5.
Шаг 4. Бейзлайн
Заголовок раздела «Шаг 4. Бейзлайн»Бейзлайн — текущее положение: команды ходят во внешние API напрямую. Измерьте его: сколько ключей, сколько денег в месяц, сколько инцидентов. Платформа v0 — готовый открытый LLM-шлюзLLM-шлюзEN LLM gateway (AI gateway)Единая точка входа ко всем моделям компании с API, совместимым с OpenAI: ключи и квоты команд, маршрутизация, кэш, учёт токенов и денег, логи, guardrails. Примеры с открытым кодом — LiteLLM, Higress, One API. (например, LiteLLM) перед внешними API и одним сервером vLLM, за две недели: ключи команд, логи, учёт расходов. Всё остальное — приращения к работающей системе, и каждое должно улучшать метрики шага 2. Решение «строить шлюз самим или взять готовый» — первый компромисс разговора; разумный ответ — взять готовый и дописывать своё только там, где его не хватает.
Шаг 5. Архитектура платформы
Заголовок раздела «Шаг 5. Архитектура платформы»flowchart LR
T["Команды:<br/>SDK openai, свой base_url"] --> GW["Шлюз: ключи, лимиты,<br/>OpenAI-совместимый API"]
GW --> GR["Guardrails:<br/>ПДн, инъекции"]
GR --> R{"Маршрутизатор:<br/>алиас, класс данных,<br/>цена, доступность"}
R --> C[("Кэш")]
R --> POOL["Пул vLLM:<br/>fast, smart, embed,<br/>LoRA команд"]
R --> EXT["Внешние API<br/>(без ПДн)"]
GW -.-> OBS["Наблюдаемость:<br/>метрики, трейсы,<br/>расходы команд"]
GATE["Эвал-гейт:<br/>новые модели"] --> POOLШлюз с единым API
Заголовок раздела «Шлюз с единым API»Команды уже умеют работать с SDK openai (урок 8.1.1), поэтому
шлюз говорит на OpenAI-совместимом APIOpenAI-совместимый APIEN OpenAI-compatible APIHTTP-интерфейс в формате OpenAI Chat Completions (/v1/chat/completions). Его отдают Ollama, llama-server, vLLM, SGLang, а также DeepSeek и Qwen в облаке — код клиента не меняется.: /v1/chat/completions,
/v1/embeddings, стриминг. Переход на платформу — заменить base_url и ключ. Платформа устроена по принципу
мультиарендностимультиарендностьEN multi-tenancyОдна система обслуживает многих независимых потребителей (команды, клиентов) с раздельными ключами, квотами, данными и логами, чтобы один арендатор не мешал другим и не видел их данных.: у каждой команды свои ключи на окружение (dev, prod) с владельцем, свои квоты и свои логи,
и одна команда не видит запросов другой; лимиты — «ведро токенов»«ведро токенов» (token bucket)EN token bucketАлгоритм лимитов. В ведре до C жетонов, оно пополняется со скоростью r в секунду, запрос забирает жетоны. Допускает короткие всплески и держит среднюю скорость. не только по запросам, но и по токенам в минуту
(урок 8.4.3); таймауты и повторы — только до первого токена.
Шлюз не хранит состояния и работает минимум в двух экземплярах за балансировщиком: иначе он единая точка отказа для
всей компании.
Маршрутизация между моделями
Заголовок раздела «Маршрутизация между моделями»Команды вызывают не модели, а алиасы: fast (Qwen3-8B), smart (Qwen3-32B или внешняя модель), embed,
code. За алиасом платформа может сменить модель после эвал-гейта — команды не правят код. Кому нужна стабильность,
закрепляет конкретную версию на срок поддержки (например, полгода). маршрутизация между моделямимаршрутизация между моделямиEN model routingВыбор модели для каждого запроса по задаче, сложности, цене и доступности: простое — маленькой своей модели, сложное — большой или внешней; при отказе — запасная модель (fallback). решает по правилам:
| Правило | Пример |
|---|---|
| Класс данных | ключ с ПДн или коммерческой тайной — только свои модели |
| Цена и сложность | каскад: сначала fast, при низкой уверенности или провале валидатора — smart (урок 11.1.5) |
| Длина контекста | длинный документ — модель и реплика с большим контекстом |
| Доступность | провайдер отвечает ошибками — запасной провайдер или своя модель (fallback) |
Квоты и учёт расходов
Заголовок раздела «Квоты и учёт расходов»У каждой команды бюджет: мягкий порог (уведомление на 80%) и жёсткий (429 с понятным сообщением). Классы приоритета: интерактив важнее пакетных задач; пакетные идут ночью на простаивающих картах. Учёт расходов по командамучёт расходов по командамEN chargeback (cost allocation)Распределение затрат общей платформы между командами-потребителями по их токенам или GPU-часам. Без него общий ресурс выглядит бесплатным и расходуется без меры. нужен и для своих GPU: общий ресурс без цены кажется бесплатным. Внутренняя цена токена — стоимость GPU-часов, делённая на токены. Пример с условной ценой 0.5 долл. за час карты: машина из четырёх карт стоит 2 долл. в час; при полной загрузке RAG-сценарием (1 405 выходных токенов в секунду, расчёт на шаге 8) это 0.40 долл. за миллион выходных токенов, при средней загрузке 30% — 1.32 долл. Так команды видят, во что обходится их сценарий, а платформа — когда пора покупать следующую машину.
Кэширование
Заголовок раздела «Кэширование»Три уровня. Точный кэш ответов в шлюзе — для детерминированных запросов (temperature=0); ключ включает модель,
её версию, сообщения и параметры. Префикс-кэш в vLLM (урок 7.1.2) —
общий системный промпт сценария считается один раз; чтобы он срабатывал, запросы с одинаковым началом выгодно
направлять на одну реплику. Семантический кэшсемантический кэшEN semantic cacheВозвращает сохранённый ответ на запрос, близкий по смыслу (косинус эмбеддингов выше порога). Опасен ложными попаданиями — «включить» и «отключить» очень похожи. — только по запросу команды и после
проверки порога на размеченных парах: в уроке 8.4.3 вы видели, как «включить» и «отключить» оказываются «похожими».
Пул инференса
Заголовок раздела «Пул инференса»Модели крутятся в vLLM с непрерывным батчингомнепрерывный батчингEN continuous batching (iteration-level scheduling)Состав батча пересматривается после каждого шага decode — закончившиеся запросы уходят, новые встают на их место. Идея системы Orca (2022), стандарт всех современных серверов. и PagedAttention. Модель, которая
помещается в одну карту, запускаем репликами (параллелизм по данным); тензорный параллелизмтензорный параллелизмEN tensor parallelism — только когда
модель не влезает или не укладывается в TTFT: на PCIe без NVLink связь между картами съедает часть выигрыша
(урок 7.1.2). Дообученные адаптеры команд обслуживаются поверх одной базовой модели: vllm serve Qwen/Qwen3-8B --enable-lora --lora-modules support=./adapters/support .... LoRALoRA (низкоранговая адаптация)EN low-rank adaptation (LoRA) с рангом 16 на всех проекциях
Qwen3-8B — около 44 млн параметров, примерно 90 МБ против 16 ГБ базы, так что десять команд с адаптерами стоят почти
как одна модель. Эмбеддинги и реранкер — на отдельной карте, чтобы длинные генерации не задерживали поиск.
Guardrails и логи без персональных данных
Заголовок раздела «Guardrails и логи без персональных данных»На входе — поиск ПДн (регулярные выражения для телефонов, почты, номеров карт с проверкой Луна; распознавание имён) и решение по классу данных: для внешнего API — замаскировать (заменить на метки и вернуть значения в ответ) или заблокировать; для своих моделей — пропустить, но в логах хранить замаскированный текст. Для RAG и агентов — проверка промпт-инъекцийпромпт-инъекцияEN prompt injectionАтака, при которой инструкции злоумышленника попадают в контекст модели (напрямую или через веб-страницу, письмо, файл) и перехватывают управление. (урок 8.3.4). На выходе — ПДн и запрещённый контент. Сырые тексты, если они вообще нужны, лежат отдельно, с коротким сроком хранения и журналом доступа. Требования к персональным данным задаёт закон (в России — 152-ФЗ); платформа делает соблюдение возможным, а юридические выводы — работа юристов. Подробно — раздел «Guardrails и персональные данные» урока 8.4.3.
Наблюдаемость
Заголовок раздела «Наблюдаемость»Метрики в разрезе «команда × модель»: запросы, входные и выходные токены, p50/p95/p99 TTFT и TPOT, ошибки по кодам,
доля попаданий в кэш, деньги. Со стороны GPU — загрузка, заполненность KV-кэша, длина очереди: vLLM отдаёт их на
эндпоинте /metrics в формате Prometheus. Идентификатор запроса проходит через шлюз до модели, так что трейс
(урок 8.4.2) показывает, где ушло время.
Шаги 6–7. Выкатка новой модели через эвал-гейт
Заголовок раздела «Шаги 6–7. Выкатка новой модели через эвал-гейт»Офлайн- и онлайн-оценка у платформы сливаются в один конвейер выкатки:
flowchart LR
N["Новая модель<br/>или версия"] --> G{"Эвал-гейт"}
G -->|"провал"| X["Не выходит,<br/>отчёт командам"]
G -->|"прошла"| SH["Теневой запуск:<br/>копия трафика"]
SH --> CA["Канарейка: 5%<br/>трафика алиаса"]
CA --> FULL["Алиас переключён<br/>на 100%"]
FULL -.->|"тревога"| RB["Откат: алиас назад"]Эвал-гейтэвал-гейтEN evaluation gate (quality gate)Автоматическое условие выкатки новой модели или промпта: прогон эвал-набора и порогов качества, безопасности, задержки и цены. Не прошла — в продакшен не попадает. — набор автоматических условий, записанных заранее: на эвал-наборе каждой команды, подписанной на алиас, качество не хуже текущей версии в пределах доверительного интервала (парный бутстрэп, урок 7.3.2); набор безопасности пройден; p95 задержки при плановой нагрузке укладывается в SLO (нагрузочный тест); цена токена не выросла сверх оговорённого. Потом теневой запусктеневой запускEN shadow deploymentКопия реальных запросов отправляется новой версии, но её ответы пользователю не показывают — только записывают и сравнивают. — копия реальных запросов идёт новой модели, ответы только записываются и сравниваются; затем канарейкаканареечный выпускEN canary releaseНовая версия сначала получает малую долю трафика (например, 5%); её онлайн-метрики сравнивают со старой, и только потом трафик переключают целиком. на 5% и полное переключение. Откат — вернуть алиас, это секунды. Команды заранее получают отчёт гейта по своим наборам: смена модели — изменение и для них.
Шаг 8. Сервинг: сколько пользователей выдержит одна машина
Заголовок раздела «Шаг 8. Сервинг: сколько пользователей выдержит одна машина»Считаем по схеме из урока 11.2.1 и домашней работы s11-hw04-capacity. Интерактивный RAG-сценарий: промпт 2000
токенов, ответ 400, SLO TTFT ≤ 2 с и TPOT ≤ 50 мс, Qwen3-8B в INT8 на одной RTX 4080 32 ГБ (716.8 ГБ/с, 97.5 TFLOPS —
паспорт штатной карты, урок 5.7.1).
- Память. Веса — 8.2 ГБ, KV-кэш запроса — 144 КиБ на токен × 2 400 токенов ≈ 354 МБ. Под кэш остаётся ГБ: помещается 55 запросов одновременно.
- TTFT. Prefill: с — в SLO.
- TPOT и батч. Шаг decode при батче — чтение весов и кэшей. Но пока реплика ведёт ответов, она успевает сделать prefill каждого из них, и эти паузы ложатся на те же 400 токенов: При шаг — 19.8 мс, паузы — 28.6 мс, итого 48.4 мс; при уже больше 50 мс. Батч ограничивает не память (55), а TPOT (17), и больше половины TPOT — чужие prefill.
- Пропускная способность реплики. Запрос живёт в реплике с; по закону Литтлазакон ЛиттлаEN Little's lawL = λ·W — среднее число запросов в системе равно интенсивности их поступления, умноженной на среднее время в системе. при 17 одновременных запросах реплика обслуживает запроса в секунду.
- Машина. Четыре реплики — 3.5 запроса в секунду, с запасом 0.7 — 2.46 запроса в секунду в пик.
- Пользователи. Пусть активный сотрудник задаёт 20 вопросов в рабочий день, а пиковый коэффициент к среднему за сутки — 4. Машина выдерживает запросов в сутки, то есть около 2 650 активных пользователей.
Те же формулы для других сценариев (одна машина, 20 запросов на пользователя в день, пик ×4, налог на связь при tp > 1 — 30%):
| Сценарий | Промпт / ответ | Модель, формат, tp | Батч | Запросов/с в пик | Пользователей |
|---|---|---|---|---|---|
| Чат | 500 / 300 | Qwen3-8B INT8, tp = 1 | 53 | 9.9 | ≈ 10 700 |
| RAG | 2000 / 400 | Qwen3-8B INT8, tp = 1 | 17 | 2.46 | ≈ 2 650 |
| RAG | 2000 / 400 | Qwen3-8B BF16, tp = 1 | 12 | 1.72 | ≈ 1 850 |
| Длинные документы | 8000 / 500 | Qwen3-8B INT8, tp = 2 | 9 | 0.51 | ≈ 550 |
| RAG | 2000 / 400 | Qwen3-32B INT4, tp = 2 | 7 | 0.50 | ≈ 540 |
Выводы, которые стоит сказать вслух. Длина промпта — главный рычаг: вчетверо длиннее промпт — вчетверо меньше
пользователей, а на 8 000 токенах одна карта уже не укладывается в TTFT (prefill 2.7 с) и нужен tp = 2. Квантование
весов в INT8 даёт +40% пользователей. Модель 32B обходится примерно впятеро дороже 8B на запрос — значит, smart
нужен с квотами и каскадом. Все числа — потолок на салфетке; реальные движки дают 50–85% от него, поэтому до запуска
делаем нагрузочный тест и калибруем коэффициенты.
Кластер из трёх машин на старте:
| Машина | Что на ней | Зачем |
|---|---|---|
| 1 | 4 реплики Qwen3-8B INT8 (fast) с LoRA-адаптерами команд | основной интерактив: ≈ 2 650 пользователей RAG или ≈ 10 700 чата |
| 2 | Qwen3-32B INT4, tp = 2, две реплики (smart) | сложные задачи, ≈ 0.5 запроса в секунду в пик — только по квотам |
| 3 | 2 реплики fast, эмбеддинги и реранкер, 1 карта под эвалы и канарейку | рост, запас на отказ машины, выкатка |
Если все 10 000 сотрудников станут активными пользователями RAG, для fast понадобится около четырёх машин — это план
роста, и подтверждать его будет статистика потребления, а не прогноз. Ночью интерактив почти стоит — пакетные задачи команд (разметка, суммаризация архивов) получают освободившиеся карты.
Внешние API — для задач, где своих моделей не хватает, и как переливной клапан в пик, но только для запросов без ПДн.
Шаг 9. Мониторинг и итерации
Заголовок раздела «Шаг 9. Мониторинг и итерации»Тревоги: ошибки шлюза выше 1%, p95 TTFT выше SLO дольше 10 минут, заполненность KV-кэша выше 90% (движок начнёт вытеснять запросы), бюджет команды на 80%. Раз в месяц — планирование мощности: рост токенов по командам и пиковый коэффициент из статистики потребления. Раз в квартал — обновление моделей за алиасами через гейт. Отдельно — опрос команд: что мешает подключиться. Если доля трафика в обход платформы растёт, проблема не в командах, а в платформе.
Компромиссы и ответ за 45 минут
Заголовок раздела «Компромиссы и ответ за 45 минут»| Развилка | Выбор | Цена | Передумаю, если… |
|---|---|---|---|
| Свой шлюз или готовый | готовый открытый (LiteLLM, Higress) | зависимость от чужого кода | нужны функции, которых нет и не будет |
| Алиасы или конкретные модели | алиасы плюс закрепление версий | платформа отвечает за совместимость | команды массово закрепляют версии — гейт плохо ловит регрессии |
| Реплики или tp | реплики, tp только по необходимости | меньше память и медленнее prefill на реплику | TTFT не укладывается или модель не влезает |
| Строгие или мягкие квоты | мягкие с уведомлением, жёсткие для пакетных задач | риск перерасхода | бюджет компании урезан |
| Полные логи или минимум | маскированные логи, сырые — коротко и под замком | сложнее отладка | регулятор или служба безопасности требует иного |
На собеседовании держите тайминг из 11.2.1: 5 минут на вопросы (команды, сценарии, ПДн, железо), 5 — на метрики платформы, 3–4 — на данные и бейзлайн, 10 — на архитектуру с диаграммой, 5 — на эвал-гейт и выкатку, 8 — на расчёт мощности, 3 — на мониторинг, остаток — на компромиссы. Самый сильный момент — фраза вида «одна машина держит около 2 650 пользователей RAG, а длинные документы впятеро дороже — поэтому ввожу квоты и tp = 2 только для них».
Проверь себя
Заголовок раздела «Проверь себя»- LLM-платформа — продукт для инженеров: шлюз с OpenAI-совместимым API, маршрутизация по алиасам, классу данных, цене и доступности, квоты и учёт расходов, кэш, пул vLLM с репликами и LoRA команд, guardrails и логи без ПДн, наблюдаемость.
- Новая модель выходит через эвал-гейт на наборах всех команд, тень и канарейку; откат — переключение алиаса.
- Одна машина 4× RTX 4080 с Qwen3-8B INT8 держит около 2 650 активных пользователей RAG (промпт 2000, ответ 400, TPOT ≤ 50 мс) или около 10 700 пользователей короткого чата; главные рычаги — длина промпта, квантование, размер модели.
- Готовые шлюзы (LiteLLM, Higress, One API) закрывают половину работы; эвал-гейт, guardrails под ваши данные и расчёт мощности — ваша часть.
Дальше: «Как устроен найм в ML» — роли, уровни и этапы собеседований, на одном из которых вам и предложат спроектировать такую систему.