
Привет, Хабр! Меня зовут Александра, я Data Scientist в компании Рафт. В этой статье я разберу NVIDIA Dynamo — новый open‑source фреймворк для инференса и проверю, действительно ли его KV‑маршрутизация ускоряет агентные сценарии.
С появлением агентных систем требования к инференсу современных ML‑моделей существенно изменились. Если раньше типичная нагрузка была предсказуемой — один запрос, один ответ и фиксированная цепочка шагов, — то в 2025–2026 годах всё стало по‑другому. Агентные системы теперь выполняют множество последовательных и параллельных вызовов моделей и инструментов в рамках одной задачи.
Triton Inference server, ставший стандартом для инференса различных моделей от компьютерного зрения до LLM, появился ещё до массового распространения агентных систем, поэтому его архитектура проектировалась под классический сценарий. В ответ NVIDIA представила новый open‑source инференс фреймворк Dynamo, заточенный под LLM, рассуждающие модели и агентов.
Навигация
-
Проблемы KV‑кэша в агентных системах
-
Что такое Dynamo
-
Архитектура агентного инференса в Dynamo
-
Frontend — единая точка входа для агентов
-
KV Router — маршрутизация по содержимому кэша
-
KV cache management
-
Agent Hints
-
Практические сценарии использования Dynamo
-
Проверяем Dynamo на практике: даёт ли KV‑роутинг прирост в домашних условиях
-
Выводы
Проблемы KV‑кэша в агентных системах
Triton Inference Server появился в 2018 году и представляет внешний слой для оркестрации, в который подключаются различные фреймворки TensorRT, ONNX, PyTorch, TensorFlow, vLLM. Triton предоставляет автоматический динамический батчинг для всех моделей и позволяет развернуть несколько моделей на одном GPU с его максимальной утилизацией.
Раньше ML‑системы строились вокруг пайплайна: четкой цепочки действий, благодаря которой мы точно знали, сколько шагов нужно сделать прежде, чем получить результат. Классический чат‑запрос — это single‑shot паттерн: для входного запроса на фазе prefill мы заполняем KV‑кэш для всех токенов и дальше при составлении ответа дописываем в KV‑кэш новые токены, когда ответ готов и запрос завершен vLLM, SGLang и любые другие движки освобождают KV‑кэш этого запроса. Так память переиспользуется максимально эффективно.
Агенты же используют паттерн ReAct‑loop, в котором процесс состоит из нескольких шагов:
-
генерация текста LLM
-
вызов внешнего инструмента
-
приём результата
-
продолжение LLM с учётом нового контекста.
Здесь и возникает проблема: многие сталкиваются с растущим контекстом и медленными ответами. Дело в том, что последовательные вызовы инструментов разрывают непрерывность работы LLM и создают паузы. Каждая такая пауза даёт серверу инференса сигнал: «контекст простоит ещё 30 секунд», и стандартные механизмы (например, LRU‑eviction) часто вытесняют весь префикс из GPU‑кэша, как это случалось при завершении диалога в чате с LLM. Теперь нужно снова загружать полностью контекст, то есть совершать полный prefill заново. Это как раз удваивает объем вычислений и увеличивает задержку.
Есть еще одна проблема: KV‑кэш привязан к каждому экземпляру GPU. В многоузловом кластере разные шаги одного и того же агента могут попадать на разные GPU. Поскольку KV‑кэш привязан к конкретному экземпляру GPU, при смене воркера происходит гарантированный cache miss (промах кэша). Пересылка кэша между узлами пока слишком дорогая, поэтому часто дешевле пересчитать префикс заново.
Что такое Dynamo
Dynamo — это open‑source система оркестрации распределенного инференса, пришедшая на смену Triton Inference Server. Она добавляет поверх движков инференса (vLLM, SGLang и других) распределенный слой с маршрутизацией запросов, управлением KV‑кэшем, планированием и автомасштабированием — превращая кластер GPU в единую скоординированную multi‑node систему.
1. Router (Маршрутизатор)
Его задача — определить:
-
на какой GPU отправить запрос;
-
где уже находится нужный KV‑кэш;
-
как минимизировать передачу данных.
2. Prefill worker и Decode worker
О них мы говорили выше: prefill worker создает начальный KV‑кэш, когда приходит запрос, а decode worker готовит ответ токен за токеном. Decode‑фаза имеет другой профиль нагрузки: много последовательных шагов и меньше вычислений на каждый шаг, поэтому Dynamo может запускать её на других GPU.
3. Disaggregated Serving (Разделенное обслуживание)
Основная идея Dynamo заключается в разделении процесса инференса на специализированные этапы. Вместо того чтобы один GPU выполнял и prefill, и decode, Dynamo может распределить эти этапы между разными устройствами. Один GPU занимается построением контекста и KV‑кэша, а другой — генерацией токенов на его основе. Такое разделение позволяет эффективнее загружать оборудование, повышать пропускную способность кластера и уменьшать простои GPU, что особенно важно при обслуживании больших языковых моделей в масштабе дата‑центра.
4. NIXL (ускоренная передача KV)
NIXL (NVIDIA Inference Xfer Library) — это высокопроизводительный транспортный слой, который перемещает KV‑блоки между воркерами и уровнями памяти по NVLink и InfiniBand, используя RDMA.
5. Memory Hierarchy (Иерархия памяти)
Dynamo может хранить кэш не только в памяти GPU. По мере необходимости данные могут лежать в:
-
Блок — локальный диск/NVMe, доступ на уровне блоков.
-
Локальный файл — локальный SSD.
-
Удаленный файл / Объект — объектное хранилище.
-
Облако — облачное объектное хранилище.
На больших кластерах Dynamo позволяет:
-
обслуживать больше запросов одновременно;
-
эффективнее использовать дорогие GPU;
-
уменьшать задержки;
-
масштабировать инференс крупных моделей (Qwen, DeepSeek и других) на множество узлов.
По сути, Dynamo превращает набор отдельных GPU в единую распределенную систему инференса, где разные этапы генерации выполняются там, где это наиболее выгодно.
Агентный подход поддерживается на трех уровнях:
-
интерфейсный API
-
маршрутизатор
-
управление KV‑кэшем
Поверх этих трёх уровней работает сквозной механизм подсказок Agent Hints: он позволяет агенту передавать инфраструктуре информацию о своих намерениях, чтобы действия на уровнях были согласованы.
Архитектура агентного инференса в Dynamo
Основная цель оптимизации агентного инференса — максимальное использование кэша всеми воркерами и поддержание блоков KV в активном состоянии для обеспечения маршрутизации.
Рассмотрим сценарий для coding‑агента с большим системным промптом и набором инструментов, который порождает 4 субагента (поиск по коду, прогон тестов, чтение файлов, ответ разработчику).
-
KV‑маршрутизатор направляет каждый шаг на тот воркер, где уже лежит максимум общего префикса, чтобы не пересчитывать системный промпт и определения инструментов.
-
KVBM рассматривает общий префикс как разделяемый ресурс кластера: его считают один раз, а субагенты на других воркерах подтягивают готовые блоки через NIXL.
-
Agent Hints позволяют агенту заранее сказать инфраструктуре, какой запрос важнее и какой шаг будет следующим.
Дальше разберём каждый из этих компонентов по отдельности.
Frontend — единая точка входа для агентов
Dynamo Frontend — это шлюз API для обслуживания запросов инференса LLM. Он предоставляет HTTP‑интерфейсы, совместимые с OpenAI, и gRPC‑интерфейсы KServe, обеспечивая предварительную обработку запросов, их маршрутизацию и преобразование ответов в требуемый формат. Помимо чатовых запросов, Frontend поддерживает также эндпоинты для генерации изображений и видео.
Ещё один важный для агентов момент: фронтенд Dynamo понимает не один формат запросов. Кроме привычного OpenAI‑совместимого API, он умеет работать с форматами запросов, используемыми харнессами (harness), такими как Claude Code и Codex CLI. Их можно подключить к собственному серверу инференса, указав его адрес. Менять логику работы агента не потребуется — Dynamo выступает промежуточным слоем между агентной средой и кластером GPU.
KV Router — маршрутизация по содержимому кэша
Dynamo решает проблему задержек и сброса кэша с помощью KV‑маршрутизатора. Он распределяет запросы, оценивая затраты на их выполнение на разных воркерах. При этом учитываются как затраты на decode, так и затраты на prefill. От качества работы KV‑маршрутизатора напрямую зависят пропускная способность и задержка распределенной системы инференса.
Воркеры регистрируются с помощью API register_llm, после чего KV‑маршрутизатор автоматически:
-
отслеживает состояние всех зарегистрированных воркеров
-
принимает решения о маршрутизации на основе перекрытия KV‑кэша
-
распределяет нагрузку между доступными воркерами
KV‑маршрутизатор отслеживает две ключевые метрики для каждого воркера:
-
Потенциальные активные блоки: количество блоков, которые будут использоваться для декодирования, если запрос будет направлен на воркер. Сюда входят как существующие активные блоки, так и новые блоки из входящего запроса.
-
Потенциальные новые prefill блоки: количество токенов, которые необходимо вычислить заново на воркере.
Поведение KV‑маршрутизатора можно настроить с помощью нескольких параметров. Например, можно изменить размер блоков KV‑кэша, от их размера зависят накладные расходы на память и точность определения совпадения префиксов. Также есть параметр, влияющий на случайность выбора воркера (всегда выбирается лучший воркер или нагрузка распределяется равномерно). Кроме того, можно задать баланс между prefill и decode (настраивается в зависимости от задачи: длинные промпты с короткими ответами или наоборот, короткие промпты и длинные ответы).
KV cache management
Если KV Router отвечает на вопрос «где находится нужный контекст?», то KV Cache Management отвечает на вопрос «как этот контекст хранить, перемещать и не потерять во время работы агента».
Мы уже выяснили, что агентные нагрузки предъявляют к KV‑кэшу совершенно другие требования, чем классический чатовый инференс. Контекст нужно не просто сохранить между вызовами модели, но и сделать доступным для разных воркеров, защитить от преждевременного вытеснения и научиться переиспользовать в рамках всего кластера. Эти задачи в Dynamo решает компонент KV Cache Management.
Особенность Dynamo заключается в том, что KV‑кэш перестает быть локальным ресурсом отдельного GPU. Исторически KV‑кэш существовал только в памяти того GPU, который обрабатывал запрос.
В Dynamo эту проблему решает KVBM (KV Block Manager). Он организует четырехуровневую иерархию памяти, благодаря которой KV‑блоки могут совместно использоваться разными воркерами.
После вычисления префикса KV‑блоки автоматически копируются из памяти GPU в следующий уровень хранения. Каждый блок получает хеш по содержимому и регистрируется в глобальном каталоге. Благодаря этому одинаковые блоки не дублируются, а после регистрации становятся неизменяемыми и могут использоваться любым воркером, имеющим доступ к соответствующему уровню хранения.
Предположим, ведущий агент уже вычислил системный промпт и определения инструментов. Эти KV‑блоки сохраняются в общем хранилище, когда один из субагентов запускается на другом воркере, KV Router определяет, что нужные блоки уже существуют. Вместо повторного выполнения prefill новый воркер загружает готовые данные через NIXL. В результате несколько независимых вычисления превращаются в одно вычисление и передачу готовых KV‑блоков
Однако само по себе многоуровневое хранилище не устраняет все задержки. KV‑блоки попадают в память GPU только после того, как запрос уже поступил на выбранный воркер.
Предполагается, что вместе с API управления хранилищем это позволит закреплять важные блоки в памяти, назначать им приоритеты при вытеснении и заранее загружать KV‑блоки в память GPU до того, как они понадобятся следующему запросу.
Agent Hints
Одной из интересных возможностей NVIDIA Dynamo является механизм Agent Hints — расширение OpenAI‑совместимого API, позволяющий харнессам передавать инфраструктуре информацию о своих намерениях. Вместо того чтобы рассматривать каждый запрос как независимый вызов LLM, Dynamo получает дополнительные сигналы о том, как агент планирует использовать результат, и может оптимизировать маршрутизацию, планирование и управление KV‑кэшем. Идея заключается в том, что агент знает о своём будущем поведении гораздо больше, чем инференс‑сервер. Например:
-
какой запрос важен
-
какой агент скоро вернётся после вызова инструмента
-
какой контекст стоит удерживать в кэше
-
какой шаг будет следующим
Agent Hints представляет собой набор дополнительных полей внутри секции nvext, расширяющей стандартный OpenAI API
{ "model": "my-model", "messages": [ { "role": "user", "content": "Continue the report." } ], "nvext": { "agent_hints": { "priority": 5, "strict_priority": 1, "osl": 1024, "speculative_prefill": true } }}
-
priority указывает важность запроса, чем выше значение, тем раньше запрос попадет в обработку и тем ниже вероятность вытеснения его блоков из KV‑кэш.
-
strict_priority — механизм жесткой приоритизации запросов на уровне маршрутизатора Dynamo. Запросы с более высоким значением всегда обслуживаются раньше запросов с более низким значением, независимо от их положения в очереди.
-
osl (Output Sequence Length) — предполагаемая длина ответа в токенах. Dynamo использует это значение для более точного планирования нагрузки и оценки времени занятости воркеров. Система может со временем научиться определять это значение, отслеживая среднюю длину выходных последовательностей для каждого типа вызова инструмента.
-
speculative_prefill — после завершения текущего ответа Dynamo может заранее прогреть KV‑кэш для предполагаемого следующего запроса. Во время ожидания ответа от инструмента инфраструктура уже может начать подготовку следующего префикса контекста. Это снижает задержки при возобновлении агентной сессии.
Фронтенд анализирует nvext.agent_hints, маршрутизатор использует подсказки для организации очередей и выбора воркеров, а поддерживаемые воркеры используют переадресованные подсказки для планирования на уровне движка и политики кэширования.
Agent Hints можно рассматривать как попытку сформировать новый слой протокола для агентных систем. Если MCP стандартизирует взаимодействие агента с инструментами, а A2A — взаимодействие между агентами, то nvext.agent_hints пытается стандартизировать взаимодействие между агентным оркестратором и инференс‑инфраструктурой.
Практические сценарии использования Dynamo
Если инференс выполняется на одной GPU и запросы обрабатываются последовательно, то Dynamo не дает заметного прироста производительности. Его преимущества проявляются при масштабировании на несколько GPU, в агентных системах и при работе с длинными контекстами.
-
Self‑hosting открытых моделей под coding‑агентов. Если вы поднимаете собственный инференс для локальной модели с открытым harness вроде OpenCode, то Dynamo помогает эффективнее переиспользовать KV‑кэш и уменьшить объем повторных вычислений. Это хороший вариант, когда важно использовать собственную инфраструктуру вместо внешнего API.
-
Мультиагентные системы. Когда один агент запускает несколько субагентов, они обычно используют одинаковый системный промпт и одни и те же описания инструментов. Без общего KV‑кэша каждый субагент пересчитывает этот префикс заново. Dynamo же сохраняет его один раз и позволяет другим воркерам загрузить уже готовые блоки, сокращая объем вычислений.
-
Агенты с большим контекстом. Deep Research, анализ крупных кодовых баз, работа с документацией или юридическими документами могут приводить к контексту в десятки тысяч токенов. В таких случаях с помощью Dynamo можно отправить запрос туда, где уже находится нужная часть KV‑кэша.
Проверяем Dynamo на практике: даёт ли KV‑роутинг прирост в домашних условиях
В сети ходит много статей и постов, о том как Dynamo ускорил инференс, например, 2x инференс KV‑маршрутизатором. Мне стало интересно попробовать Dynamo не в production условиях, а на более простом железе и с меньшей нагрузкой, поэтому я решила провести небольшой эксперимент: взять в аренду пару видеокарт, поднять модель под Dynamo и замерить, есть ли прирост от KV‑маршрутизатора по сравнению с обычной маршрутизацией.
Что и зачем меряем
Проверим идею Dynamo для агентных сценариев — KV‑aware маршрутизация. Агент в цикле ReAct снова и снова обращается к модели с одним и тем же большим общим префиксом: системный промпт и описания инструментов, которые не меняются от шага к шагу. Если запрос попадет на воркер, где этот префикс уже посчитан и лежит в KV‑кэше, его не нужно пересчитывать — ответ приходит быстрее. При обычной маршрутизации запросы распределяются вслепую и регулярно промахиваются мимо нужного кэша. KV‑маршрутизатор Dynamo, наоборот, старается направить запрос туда, где префикс уже есть.
Гипотеза: под параллельной нагрузкой KV‑маршрутизатор должен снижать время до первого токена (TTFT), потому что реже заставляет модель пересчитывать общий префикс заново.
Модель и железо
В качестве GPU использовались 2×RTX 4090 (24 ГБ) для разворачивания двух реплик модели. Тестировать KV‑маршрутизатор на одной видеокарте бессмысленно. У vLLM уже есть собственный prefix caching в пределах одного GPU — префикс переиспользуется внутри карты сам по себе, без Dynamo.
Модель была выбрана Qwen3-14B‑FP8, чтобы свободно помещалась в 24 ГБ и оставалось место под кэш. Она подходит для проверки вызова инструментов и агентных сценариев.
Как поднять модель под Dynamo
Dynamo распространяется готовым Docker‑образом с бэкендом vLLM. Внутри контейнера сервис состоит из двух частей: frontend (единая точка входа, OpenAI‑совместимый API) и воркеры (движки vLLM с моделью).
Скачивание образа:
docker pull nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.1
Для baseline‑конфигурации поднимаем frontend без роутера и два воркера — по одному на каждую карту:
python3 -m dynamo.frontend --http-port 8000 --discovery-backend file & CUDA_VISIBLE_DEVICES=0 python3 -m dynamo.vllm \ --model Qwen/Qwen3-14B-FP8 --served-model-name qwen3 \ --max-model-len 8192 --gpu-memory-utilization 0.90 \ --enable-prefix-caching --dyn-tool-call-parser hermes \ --reasoning-parser qwen3 --trust-remote-code \ --discovery-backend file &
Для конфигурации с KV‑маршрутизатором нужно поменять в двух местах. Frontend поднимается с флагом ‑router‑mode kv, а воркеры начинают публиковать события о состоянии своего KV‑кэша (enable_kv_cache_events). Кроме того, KV‑роутер требует шину сообщений NATS (в отличие от round‑robin, которому хватало файлового discovery) — её нужно поднять заранее.
Нагрузка: агентный трейс
Для замеров был собран детерминированный трейс coding‑агента и использован через AIPerf (нагрузочный инструмент NVIDIA). Каждая сессия — общий префикс (~6000 токенов: системный промпт и описания четырёх инструментов), а также несколько шагов ReAct с паузами между ними, имитирующими работу инструмента. Общий префикс одинаков во всех сессиях — именно он должен переиспользоваться через кэш.
Прогоны содержали три уровня параллелизма — 1, 20 и 40 сессий — в обеих конфигурациях, по несколько повторов каждый.
Результаты
|
Параллельные сессии |
Без маршрутизатора (round‑robin), TTFT p90 (мс) |
KV‑маршрутизатор, TTFT p90 (мс) |
Снижение TTFT |
|
1 |
89 |
95 |
≈ нет |
|
20 |
269 ± 12 |
225 ± 24 |
~16% |
|
40 |
492 ± 15 |
326 ± 62 |
~34% |
Для одной сессии выигрыша нет и в целом значения получились похожие, это ожидаемо, так как маршрутизировать нечего. На 20 сессиях KV‑роутер снижает TTFT примерно на 16%, на 40 — уже на 34%. Приходим к результату, который ожидали, что чем больше параллельных сессий конкурируют за две карты с ограниченным KV‑кэшем, тем чаще round‑robin отправляет запрос не на нужную карту и вынуждает пересчитывать общий префикс заново. KV‑маршрутизатор направляет запрос туда, где префикс уже лежит. Этот механизм действительно работает, так как метрика hit rate роутера на нагруженных прогонах держалась около единицы, то есть маршрутизатор почти всегда попадал в нужный воркер.
Отметим ограничения эксперимента:
-
Масштаб эксперимента несопоставим с официальными бенчмарками NVIDIA, в которых речь про кластеры из 16 карт H200 с NVLink. Там выигрыш KV‑маршрутизатора гораздо заметнее.
-
На 24 ГБ остаётсямало места под KV‑кэш, что ограничивает число одновременных сессий, которые помещаются в кэш без вытеснения. С одной стороны, это усиливает эффект маршрутизатора, с другой — на карте с большим объёмом и при выборе модели с большим контекстом результаты будут другими.
-
Не проверялся disaggregated serving — важная и интересная часть Dynamo, из‑за отсутствия NVLink на 4090. Это осталось за рамками эксперимента.
Использованные источники
-
NVIDIA Dynamo — документация: https://docs.nvidia.com/dynamo/
-
NVIDIA Technical Blog — Full‑Stack Optimizations for Agentic Inference: https://developer.nvidia.com/blog/full‑stack‑optimizations‑for‑agentic‑inference‑with‑nvidia‑dynamo/
Выводы
Dynamo появился как ответ на новую нагрузку, которую создают агентные системы. Если для классического чат‑инференса было достаточно эффективно обслуживать отдельные запросы, то теперь важнее научиться сохранять и переиспользовать контекст между шагами агента и разными воркерами.
Если вы запускаете или планируете запускать открытые модели на собственных GPU для агентных и мультиагентных систем, то Dynamo поможет с пересчетом KV‑кэша, холодным стартом субагентов и медленными ответами.
Часть агентных возможностей (предзагрузка блоков, новые подсказки agent hints) пока активно дорабатывается и помечена как экспериментальная. Для молодой технологии это нормально — будем ждать новых возможностей и дальнейшего развития Dynamo.
ссылка на оригинал статьи https://habr.com/ru/articles/1056460/