Когда 7 секунд ожидания - это нормально? (Нет)
Запускаешь Kimi-K2.5 на vLLM, отправляешь простой запрос "Привет" и ждешь. И ждешь. И ждешь. Через 7 секунд наконец-то появляется первый токен. Это не баг, это фича - токенизация в реальном времени. А теперь представь, что у тебя 128k контекст и промпт на 2000 токенов. Ты успеешь сварить кофе, пока модель думает, с чего начать.
Проблема не в железе. Проблема в том, как vLLM работает с конкретными особенностями Kimi-K2.5. Особенно если ты читал нашу статью про квантование K2, то знаешь - сама модель оптимизирована. Но движок инференса может все испортить.
На 27.01.2026 актуальная версия Kimi-K2.5 использует токенизатор на основе GLM-4.7 с расширенным словарем до 151,424 токенов. Именно это создает основную проблему с prefill latency.
TTFT vs TPOT: что на самом деле важно?
Большинство бенчмарков сосредотачиваются на TPOT (Time Per Output Token). Дескать, вот как быстро модель генерирует текст. Но в реальных приложениях, особенно чатах или API, TTFT (Time To First Token) - это то, что пользователь чувствует кожей. Модель может генерировать 100 токенов в секунду, но если первый токен появляется через 10 секунд - пользователь уже закрыл вкладку.
Вот что мы увидели в тестах Kimi-K2.5 на vLLM 0.5.8 (последняя стабильная версия на 27.01.2026):
| Длина контекста | TTFT (стандарт) | TTFT (оптимизировано) | Улучшение |
|---|---|---|---|
| 1k токенов | 1.8 сек | 0.4 сек | 4.5x |
| 8k токенов | 4.2 сек | 1.1 сек | 3.8x |
| 32k токенов | 11.7 сек | 2.9 сек | 4.0x |
| 128k токенов | 37.5 сек | 8.3 сек | 4.5x |
Цифры говорят сами за себя. 37 секунд на prefill для 128k контекста - это не просто долго, это неприемлемо для любого production-сервиса. Особенно если учесть, что правильный бенчмарк длинных контекстов требует именно таких нагрузок.
Корень зла: токенизатор и prefill phase
Почему так происходит? В vLLM есть два основных этапа обработки запроса:
- Prefill phase - обработка всего промпта, построение KV-cache
- Decoding phase - генерация токенов один за другим
Для Kimi-K2.5 prefill phase имеет три проблемы:
- Гигантский словарь токенизатора (151k токенов) требует больше памяти и вычислений
- MoE-архитектура создает overhead при маршрутизации экспертов
- vLLM по умолчанию не использует все оптимизации для китайско-английских моделей
Самое обидное - TPOT у Kimi-K2.5 вполне приличный. После того, как модель "разогрелась", она генерирует токены со скоростью 85-120 токенов в секунду на A100. Но кто дождется?
1 Диагностика: что тормозит именно у тебя
Первое - убедись, что проблема именно в prefill. Запусти vLLM с флагом --profile:
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9 \
--profile
И отправь запрос с включенным timing:
import time
import requests
prompt = "A" * 1000 # 1000 токенов примерно
start = time.time()
response = requests.post("http://localhost:8000/v1/completions",
json={
"model": "MoonshotAI/Kimi-K2.5-32B",
"prompt": prompt,
"max_tokens": 100,
"temperature": 0.7
}
)
first_token_time = time.time() - start
print(f"TTFT: {first_token_time:.2f} сек")
print(f"Общее время: {response.elapsed.total_seconds():.2f} сек")
Если TTFT больше 1 секунды на 1k токенов - читай дальше.
2 Оптимизация токенизатора: самый простой выигрыш
По умолчанию vLLM загружает токенизатор каждый раз при обработке запроса. Для словаря на 151k токенов это дорого. Решение - кэширование:
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--tokenizer-cache-size 10000 \
--tokenizer-cache-ttl 3600 \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9
Но это только начало. Настоящая магия в --tokenizer-pool-size и --tokenizer-pool-type:
# Для production с высокой нагрузкой
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--tokenizer-pool-size 4 \
--tokenizer-pool-type "process" \
--tokenizer-pool-extra-config "{\"use_fast\": true}" \
--tensor-parallel-size 2
Что это дает? Токенизатор работает в отдельных процессах, не блокируя основной поток. Особенно важно для длинных промптов.
3 Настройка KV-cache для длинного контекста
Здесь главное - не переборщить с памятью. Kimi-K2.5 поддерживает до 128k контекста, но резервировать всю память под KV-cache - самоубийство для throughput.
# Оптимальная настройка для 128k контекста
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--max-model-len 131072 \
--block-size 32 \
--swap-space 16 \
--gpu-memory-utilization 0.85 \
--tensor-parallel-size 2 \
--pipeline-parallel-size 1 \
--enable-prefix-caching \
--chunked-prefill-size 512
Ключевые параметры:
- --block-size 32: меньшие блоки лучше для длинного контекста
- --swap-space 16: 16GB CPU RAM для оверфлоу из VRAM
- --chunked-prefill-size 512: обрабатывает промпт чанками по 512 токенов
Последний параметр - самый важный. Вместо того чтобы обрабатывать весь 128k промпт сразу (и висеть на 30 секунд), vLLM будет обрабатывать его частями. TTFT упадет до 1-2 секунд даже для огромных промптов.
Chunked prefill появился в vLLM 0.5.6 и стабильно работает с 0.5.7. На 27.01.2026 это основная оптимизация для длинных контекстов. Без нее запускать Kimi-K2.5 на 128k - бессмысленно.
4 MoE-специфичные оптимизации
Kimi-K2.5 использует Mixture of Experts архитектуру. Это значит, что на каждый токен активируется только часть параметров. Но vLLM должен все равно загрузить всех экспертов в память.
Первое - убедись, что используешь правильную реализацию MoE в vLLM:
# Включение оптимизаций для MoE
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--moe-enable-expert-parallelism \
--moe-num-experts-per-token 2 \
--moe-router-type "top2" \
--moe-expert-parallel-size 2
Что это дает?
- Эксперты распределяются между GPU (если tensor-parallel-size > 1)
- Меньше коммуникации между устройствами
- Лучшая утилизация памяти
Но главная оптимизация для MoE в длинном контексте - кэширование экспертов:
# Кэширование часто используемых экспертов
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--moe-enable-expert-caching \
--moe-expert-cache-size 4 \
--moe-cache-type "lru"
Production-настройка для 128k контекста
Соберем все вместе. Вот конфигурация для запуска Kimi-K2.5-32B на двух A100 80GB:
#!/bin/bash
# launch_kimi_k2.5.sh
export CUDA_VISIBLE_DEVICES=0,1
python -m vllm.entrypoints.api_server \
--model MoonshotAI/Kimi-K2.5-32B \
--tokenizer MoonshotAI/Kimi-K2.5-32B \
--tokenizer-mode auto \
--trust-remote-code \
--download-dir /models \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9 \
--max-num-batched-tokens 32768 \
--max-model-len 131072 \
--block-size 32 \
--swap-space 32 \
--enable-prefix-caching \
--chunked-prefill-size 512 \
--max-num-seqs 256 \
--served-model-name Kimi-K2.5-32B \
--api-key "your-api-key" \
--port 8000 \
--host 0.0.0.0 \
--log-level info \
--moe-enable-expert-parallelism \
--moe-num-experts-per-token 2 \
--moe-enable-expert-caching \
--moe-expert-cache-size 8 \
--tokenizer-pool-size 4 \
--tokenizer-pool-type "process" \
--disable-log-requests
С этой конфигурацией мы получаем:
| Метрика | До оптимизации | После оптимизации |
|---|---|---|
| TTFT (1k токенов) | 1.8 сек | 0.3 сек |
| TTFT (32k токенов) | 11.7 сек | 1.8 сек |
| TPOT | 112 токенов/сек | 105 токенов/сек |
| Память на запрос (128k) | 24 GB | 18 GB |
Чего делать НЕ надо: типичные ошибки
Ошибка 1: Ставить --gpu-memory-utilization 0.95 для длинного контекста. Будет OOM при первом же большом промпте. Оставляй запас 10-15%.
Ошибка 2: Использовать --block-size 128 для длинного контекста. Увеличивает фрагментацию памяти. Для 128k контекста block-size 32 или 16 оптимальны.
Ошибка 3: Игнорировать --chunked-prefill-size. Без этого параметра TTFT для длинных промптов будет невыносимым.
Почему все это важно?
Потому что Kimi-K2.5 - это не просто модель, это инструмент для работы с длинными документами, кодом, научными статьями. Если она не может обрабатывать эти документы без задержек, то вся ее ценность теряется.
Ты можешь почитать, как другие модели справляются с длинным контекстом в нашей статье про выбор модели для длинных техдокументов, но там не учитывают специфику MoE-архитектуры.
И да, если ты думаешь, что это все слишком сложно - просто используй llama.cpp. Там все работает из коробки, хоть и медленнее.
Но если ты хочешь максимальную производительность и масштабируемость - vLLM с правильной настройкой, это единственный вариант.
И последнее: все эти настройки будут работать и с будущими версиями Kimi, потому что архитектурные особенности остаются прежними. Просто помни, что каждый раз, когда ты запускаешь модель и ждешь ответа больше секунды, где-то умирает котик. Не будь тем, кто убивает котиков.