Искусственный интеллект и машинное обучение

Локальная LLM для 100 сотрудников: Как рассчитать нагрузку на сервер

~14 минут15 сентября 2026 г.

Фраза «локальная LLM для 100 сотрудников» ещё не определяет сервер.

Сто сотрудников не означают сто одновременных inference-запросов. Но и попытка заменить их условными «10 concurrent users» проблему не решает: два одинаковых по числу пользователей сервиса могут сильно различаться по частоте запросов, длине prompt, истории диалога, RAG-контексту, длине ответа и требованиям к задержке.

Правильная последовательность другая:

сотрудники

    ↓

кто имеет доступ

    ↓

фактическое использование

    ↓

временной поток requests

    ↓

request mix

    ↓

ISL / OSL distributions

    ↓

Typical / Peak / Burst workload


       +


capacity curve сервера

    ↓

queue / TTFT / ITL / E2E

    ↓

SLA gate


       ↓

максимальная нагрузка,

проходящая SLA

Главный принцип:

У Start Server production LLM inference уже выделен как отдельный коммерческий сценарий; на текущей странице при подборе отдельно перечисляются модель, квантизация, контекст, одновременные запросы, latency, throughput, KV cache и особенности RAG/agent workload.

Почему 100 сотрудников не равны 100 concurrent requests

1
Почему 100 сотрудников не равны 100 concurrent requests

Для начала разделите несколько величин:

TOTAL EMPLOYEES

        ↓

ELIGIBLE USERS

        ↓

ACTIVE USERS

        ↓

ACTIVE SESSIONS

        ↓

USER TASKS

        ↓

MODEL REQUESTS

Между ними нет универсальных коэффициентов.

Один сотрудник может иметь доступ к сервису, но почти им не пользоваться. Другой отправляет десятки запросов в день. В agentic application одна пользовательская задача может породить несколько вызовов модели.

Поэтому таблица проекта начинается так:

Параметр

Значение

Статус

Total employees

MEASURED

Eligible users

MEASURED / FORECAST

DAU

MEASURED / FORECAST

Peak-window active users

MEASURED / FORECAST

User tasks

MEASURED / FORECAST

Model calls/task

MEASURED / ARCHITECTURE

Для каждого значения полезно использовать один из статусов:

MEASURED

FORECAST

ASSUMPTION

UNKNOWN

Так сценарный расчёт не превращается незаметно в «факт».

Для сервера важнее request trace, чем DAU

Число активных пользователей полезно для product analytics.

Но inference capacity непосредственно нагружают запросы.

Минимально полезная обезличенная запись:

timestamp


model / version


input tokens

output tokens


request class


session ID

если нужен multi-turn анализ


completed

cancelled

error

Если реальный traffic уже существует, workload benchmark лучше строить по его характеристикам. NVIDIA рекомендует подбирать input/output sequence lengths по реальному use case и при наличии production traffic использовать representative prompts. Длина input влияет прежде всего на prefill, память и TTFT, а длина output — на generation workload и ITL.

Как получить request rate

Для окна продолжительностью T секунд и N поступивших запросов:

λ=NT\lambda=\frac{N}{T}

где λ — средняя частота прихода requests за это окно.

В worksheet:

Observation window:

...


Requests:

...


Window duration:

...


Average arrival rate:

... req/s

Но это только первый слой.

Одинаковые 10 req/s могут описывать совершенно разную нагрузку.

PROFILE A


запросы идут

почти равномерно

PROFILE B


большинство запросов

приходит короткими всплесками

Поэтому фиксируйте peak и burst отдельно

Минимальная модель:

Параметр

Значение

Typical RPS

Peak RPS

Peak window

Burst rate

Burst duration

Timestamp trace

YES / NO

Современные benchmark tools специально разделяют request rate, характер межприходных интервалов и concurrency. Текущий vllm bench serve, например, позволяет задавать request rate, Gamma/Poisson-подобную burstiness и отдельный maximum concurrency.

AIPerf аналогично разделяет rate-based scheduling, timestamp replay, user-centric timing и concurrency-driven saturation.

Если есть timestamps, сохраните trace

Допустим, реальная нагрузка выглядит так:

09:00:00.120

09:00:00.195

09:00:00.208

09:00:02.970

...

Сведение её к:

average = 1 request/s

уничтожает часть информации.

Для зрелого production profile приоритет лучше задать так:

REAL TIMESTAMP TRACE

        ↓

DISTRIBUTION FITTED TO TRACE

        ↓

PILOT-DERIVED PROFILE

        ↓

BUSINESS FORECAST

        ↓

EXPLICIT ASSUMPTION

Но benchmark client не должен незаметно менять workload

Это важная техническая проверка.

Допустим, production trace предполагает, что в определённую секунду должно поступить много запросов.

Если load generator дополнительно настроен:

max concurrency = 10

часть запросов может ждать свободного client-side слота ещё до отправки на сервер.

Тогда benchmark фактически проверяет:

original demand

+

client-side throttling

а не исходный offered load.

В AIPerf при совместном использовании rate и concurrency частота определяет schedule, а concurrency является ceiling; при занятом semaphore запрос ждёт возможности отправки.

Поэтому в отчёте нужны две отдельные строки:

Client/gateway concurrency limit:

...


Server queue:

...

Если client limit отсутствует в production, его не следует незаметно добавлять в workload model.

Один пользователь — не один тип запроса

Корпоративная LLM может одновременно обслуживать:

Request class

Share

ISL p50

ISL p95

OSL p50

OSL p95

Short Q&A

Drafting

Summarization

Long-document

RAG-assisted

Это шаблон, а не обязательная taxonomy.

В реальном проекте request classes формируются по фактическим use cases.

Главное — не превращать всё в один:

average request

Что входит в input sequence length

Для чат-системы effective ISL может включать:

system instructions


+


conversation history


+


current user turn


+


RAG context


+


application/tool context

Поэтому:

сотрудник ввёл 30 tokens

не означает:

ISL = 30

В актуальном NVIDIA NIM guide ISL также определяется как весь input model, включая system instructions, chat history и RAG context.

Output length также нужна как distribution

Запрос:

«Когда заканчивается договор?»

и задача:

«Подготовь аналитический отчёт»

создают разную decode-нагрузку.

Поэтому вместо одной строки:

Average output:

...

лучше хранить:

OSL p50:

OSL p95:


Policy maximum:

если есть

При наличии полной telemetry можно хранить distribution целиком.

vLLM уже предоставляет histograms количества prompt и generation tokens на request, поэтому такие distributions можно получать с inference layer.

Почему p50/p95 лучше одной средней

Предположим:

90% prompts:

короткие


10% prompts:

очень длинные

Средний input может выглядеть относительно небольшим.

Но тяжёлый хвост способен заметно влиять на:

prefill load

KV-cache demand

queue

TTFT

Поэтому статья использует p50/p95 как удобный шаблон представления distribution, но не объявляет именно p95 обязательным percentile для любого проекта.

Если product SLA построен по p90 или p99, используйте его.

RAG context входит в LLM workload

SS-021 отвечает за retrieval pipeline:

ingestion

vector DB

retrieval

reranking

SS-022 интересует уже то, что попало в model input:

base prompt

+

chat history

+

retrieved context

=

effective ISL

Поэтому worksheet содержит:

RAG:

YES / NO


Retrieved-context tokens:

distribution / p50 / p95

Одна пользовательская задача может создать несколько model requests

Для обычного помощника:

1 user turn

→ 1 model request

может быть корректной моделью.

Для agent workflow:

1 user task

        ↓

planning

        ↓

tool interaction

        ↓

follow-up inference

        ↓

final generation

уже нет.

Поэтому обязательно поле:

Model calls per user task:


SINGLE

или

MULTI-CALL

Если multi-call workload существенен, дальнейшая decomposition относится к SS-032.

Retries, errors и cancellations тоже влияют на traffic

Endpoint может получить больше requests, чем инициировал пользователь, например из-за retry policy.

Поэтому telemetry желательно различать:

Initial requests:

Retries:


Completed:

Cancelled:

Errors:

Можно ли вычислить concurrency через RPS

Для устойчивой системы полезен sanity check:

L=λWL=\lambda W

где L — среднее число requests в системе, λ — средний arrival rate, W — среднее время request в системе.

То есть:

mean request arrival

×

mean residence time

≈

mean requests in system

Но ключевое слово — mean.

Это не:

peak concurrency

не:

p95 concurrency

и не:

maximum queue depth

Поэтому формула:

Peak concurrency =

Peak RPS × latency

не используется как sizing rule.

Время request тоже зависит от нагрузки

Особенно опасно взять:

W = latency

при concurrency = 1

и использовать его для расчёта peak production load.

По мере приближения к saturation:

queue time ↑

TTFT ↑

E2E ↑

и сама W меняется.

Demand и capacity проверяются двумя разными режимами

Demand replay

Отвечает:

Что случится, если пользователи будут отправлять запросы в production-like режиме?

Вход:

timestamp trace

или

arrival distribution


+


request mix


+


ISL / OSL

На выходе:

running

waiting

queue


TTFT

ITL

E2E


errors

SLA compliance

Capacity characterization

Отвечает:

Как меняется performance конкретного server/runtime при росте in-flight load?

Concurrency 1

↓

2

↓

4

↓

8

↓

...

AIPerf в concurrency-only режиме поддерживает заданное число in-flight requests, отправляя новый после завершения предыдущего. Rate-based и fixed-schedule workloads работают иначе.

Поэтому:

Для production sizing полезны оба слоя.

Concurrency не равна batch size

Запись:

concurrency = 20

не означает:

batch size = 20

Concurrency говорит, сколько requests одновременно находится в работе/системе согласно принятому определению.

Batching — внутреннее решение scheduler/runtime о том, какие tokens или requests обрабатываются совместно в конкретный момент.

Не нужно выводить batch size из числа сотрудников или requests in flight.

Running и waiting requests нужно разделять

2
Running и waiting requests нужно разделять

но разделять

Например:

20 requests in service

могут означать:

20 running

0 waiting

или:

8 running

12 waiting

Это разные состояния.

vLLM отдельно экспортирует num_requests_running и num_requests_waiting; waiting также может быть разбит по причине ожидания.

Для capacity worksheet:

Running:

Waiting:


Server queue depth:

Не смешивайте client queue и server queue

Это отдельная строка Final именно из-за риска получить ложный вывод.

Client/load-generator queue

Запрос ещё не был отправлен server, потому что benchmark client применяет собственный concurrency limit.

Server queue

Запрос уже поступил serving system, но ждёт scheduling capacity.

vllm bench serve может отдельно учитывать client queue при max-concurrency, тогда как production metric vllm:request_queue_time_seconds относится к ожиданию в serving runtime.

Поэтому:

Client queue:

...


Server queue:

...

а не одно безымянное:

Queue = ...

TTFT, ITL/TPOT и E2E отвечают на разные вопросы

Метрика

Что показывает

Queue time

ожидание capacity

TTFT

задержку до начала ответа

ITL / TPOT

темп выдачи последующих токенов

E2E

полное время request

vLLM экспортирует отдельные histograms TTFT, inter-token latency, E2E latency, queue, prefill и decode time.

Но точную семантику нужно хранить вместе с инструментом.

Например, в текущей vLLM telemetry TTFT считается относительно frontend arrival time, а отдельная per-request telemetry также имеет queue и generation intervals.

AIPerf использует собственные client-observed definitions.

Поэтому benchmark record обязательно содержит:

Tool:

Version:


Metric:

Definition:

Высокий TTFT не означает автоматически медленную GPU

TTFT может включать влияние:

queueing


long prefill


large ISL


scheduler load


first-token generation

Поэтому диагностика должна смотреть вместе:

ISL

queue

running/waiting

prefill

TTFT

а не делать вывод только по одному показателю.

Total TPS и пользовательская скорость — разные показатели

С увеличением concurrency aggregate system throughput способен расти до saturation.

Но одновременно latency каждого request может ухудшаться.

NVIDIA NIM benchmarking отдельно различает total system TPS и TPS per user и прямо отмечает, что при росте concurrency total TPS может увеличиваться, тогда как per-user throughput снижается из-за роста latency.

Поэтому нельзя выбирать сервер только по:

MAX TOTAL TPS

Production capacity должна быть ограничена SLA

Рабочее определение SS-022:

CapacitySLA=max⁡LoadCapacity_{SLA} = \max Load

при котором выполняются согласованные требования:

TTFT


ITL / TPOT


E2E


queue


error/reject policy


required SLA attainment

Это позволяет отличить:

raw throughput

от:

useful production capacity

SLA-compliant rate полезнее raw request throughput

AIPerf использует термин goodput для количества завершённых requests в секунду, удовлетворивших заданным SLO constraints. Он также рассчитывает долю запросов, прошедших все SLO; ошибки входят в denominator, чтобы система не выглядела успешной только потому, что под перегрузкой отбросила часть запросов.

В vendor-neutral статье лучше использовать термин:

а goodput приводить как конкретную реализацию этой идеи в AIPerf.

Ошибки и rejections входят в результат

Представим две системы.

Первая обслуживает весь workload, но часть requests нарушает latency SLA.

Вторая сохраняет хорошую latency, потому что часть demand вообще отклоняет.

Одна цифра TTFT не позволяет решить, какая прошла acceptance.

Нужен record:

Attempted:


Completed:


SLA-compliant:


Errors:


Rejected:


Cancelled:

Именно поэтому capacity — это не максимальное число успешно завершившихся requests без учёта того, что происходило со всем offered load.

Типичная, пиковая и burst-нагрузка — разные сценарии

Сценарий

Назначение

Typical

обычный рабочий режим

Peak

наиболее загруженное устойчивое окно

Burst

кратковременный всплеск

Heavy mix

повышенная доля длинных requests

Future adoption

ожидаемый рост использования

Не нужен универсальный:

hardware reserve = 30%

Вместо этого задайте будущий workload напрямую.

Growth тоже должен быть выражен через demand

Корректно:

CURRENT


Peak RPS:

...


Request mix:

...


ISL/OSL:

...



TARGET ADOPTION


Peak RPS:

...


Request mix:

...



FUTURE


...

Это даёт понятную причину дополнительной capacity.

Гораздо хуже:

GPU × 1.3

без workload justification.

Employees → Offered Load → SLA Capacity Worksheet

Основной самостоятельный инструмент статьи:

POPULATION


Total employees:


Eligible users:


DAU:

Value:

MEASURED / FORECAST


Peak-window users:

Value:

MEASURED / FORECAST



APPLICATION


Use cases:


Single-turn / multi-turn:


Model calls per task:

SINGLE / MULTI-CALL


RAG:

YES / NO


Streaming:

YES / NO



TRACE


Observation period:


Requests:


Timestamp trace:

YES / NO


Retries:

Cancellations:

Errors:



ARRIVAL PROFILE


Typical RPS:


Peak RPS:


Peak window:


Burst rate:

Burst duration:


Arrival source:

TRACE /

MODELED DISTRIBUTION /

FORECAST



REQUEST MIX


CLASS A


Name:

Share:


ISL p50:

ISL p95:


OSL p50:

OSL p95:



CLASS B


Name:

Share:


ISL p50:

ISL p95:


OSL p50:

OSL p95:



INPUT COMPOSITION


System prompt:


Conversation history:


RAG context:


Other:



SANITY CHECK


Mean arrival λ:


Mean residence W:


L = λ × W


Interpretation:

MEAN REQUESTS IN SYSTEM


NOT:

PEAK CONCURRENCY



SLA


Target percentile:


TTFT:


ITL / TPOT:


E2E:


Server queue:


Allowed errors/rejections:


Required attainment:



SERVER CONFIGURATION


Model/version:


Precision:


Runtime/version:


Hardware:


Prefix cache:

ENABLED / DISABLED


Cache state:

COLD / WARM / MIXED



CAPACITY CHARACTERIZATION


Concurrency sweep:


For each point:


Request throughput:


Aggregate TPS:


Per-request/per-user throughput:


TTFT:


ITL / TPOT:


E2E:


Running:


Waiting:


Server queue:


Errors/rejections:


SLA-compliant rate:



DEMAND REPLAY


Typical:

PASS / FAIL


Peak:

PASS / FAIL


Burst:

PASS / FAIL


Heavy mix:

PASS / FAIL


Future adoption:

PASS / FAIL



RESULT


Maximum offered load

meeting SLA:


Primary bottleneck:


Capacity status:


SIZED /

CANDIDATE /

FAIL /

INSUFFICIENT DATA

Demand vs Capacity Matrix

Уровень

Метрика

Источник

Population

eligible users

IAM / project

Adoption

DAU / peak-window users

analytics

Demand

request timestamps

gateway / API

Arrival

typical / peak RPS

trace

Burst

rate + duration

trace

Request mix

доли use cases

application logs

Token profile

ISL / OSL

inference telemetry

Server state

running / waiting

runtime

Queue

client + server отдельно

benchmark/runtime

UX

TTFT / ITL / E2E

metrics

Reliability

error / reject / cancel

runtime/gateway

Capacity

SLA-compliant load

benchmark

Главная идея этой таблицы:

100 EMPLOYEES

и:

SERVER CAPACITY

не соединяются одной арифметической операцией.

Benchmark Handoff Contract

3
Benchmark Handoff Contract

SS-022 должна закончиться workload specification, которую можно отдать инженеру для SS-038.

WORKLOAD ID:


MODEL:

VERSION:


PRECISION:


SERVING STACK:

VERSION:


HARDWARE:

...



REQUEST SOURCE


TRACE /

SYNTHETIC



ARRIVAL PROFILE


Typical RPS:


Peak RPS:


Burst:

rate:

duration:


Arrival distribution / trace:



CLIENT LIMITS


Client max concurrency:


Gateway limit:


Are these production constraints?

YES / NO



REQUEST MIX


Class A:

Share:


Class B:

Share:



ISL


p50:

p95:


Distribution/source:



OSL


p50:

p95:


Distribution/source:



MULTI-TURN


YES / NO


History behavior:



RAG


YES / NO


Retrieved-context profile:



CACHE


Prefix caching:


Expected cache state:

COLD / WARM / MIXED



SLA


Target percentile:


TTFT:


ITL / TPOT:


E2E:


Server queue:


Error/reject policy:


Required attainment:



REQUIRED OUTPUT


Actual workload validation:


Concurrency/latency curve:


Maximum SLA-compliant

offered load:


Client queue:


Server queue:


Running/waiting:


Errors/rejections:


Primary bottleneck:

Как читать результат

Используем четыре статуса.

Статус

Значение

SIZED

workload воспроизведён, configuration прошла требуемые SLA

CANDIDATE

sizing рассчитан, validation ещё не выполнена

FAIL

целевой workload не проходит acceptance

INSUFFICIENT DATA

отсутствуют критические inputs

Если тест использует другую модель, другую precision, существенно другой ISL/OSL profile или другую arrival model:

NOT COMPARABLE

Это не FAIL и не PASS.

Это другой workload.

Какие данные нужны для подбора локального LLM-сервера

Для первичного sizing достаточно передать:

MODEL


model/version

precision



USERS


eligible users


pilot/production telemetry,

если есть



DEMAND


typical RPS

peak RPS


burst profile



REQUEST PROFILE


ISL p50/p95


OSL p50/p95


multi-turn:

YES / NO


RAG:

YES / NO


model calls/task:

SINGLE / MULTI-CALL



SLA


TTFT


ITL / TPOT


E2E


queue tolerance


error/reject policy



GROWTH


current workload


target-adoption workload

Если этих данных ещё нет, допустим scenario model. Но assumptions должны быть явно подписаны.