Реализовать prefix caching для system prompt
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать prefix caching для system prompt
1. Цель задачи
Освоить механизм prefix caching для сокращения времени до первого токена (TTFT) в LLM-серверах, когда запросы многократно используют один и тот же system prompt. Вы научитесь настраивать кеширование начальной части контекста (prefix) на сервере инференса, замерять TTFT до и после внедрения, и добиться целевого сокращения времени.
Ключевой результат TTFT для запросов с общим system prompt снижен на 50% (или более) относительно baseline без кеширования, при корректной работе с разными длинами user-части и неизменном качестве ответов.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| LLM-сервер с поддержкой prefix caching (vLLM, TGI, TensorRT-LLM) | Локальная установка vLLM (pip install vllm) или Docker-образ |
| Хранилище для кеша (опционально) | RAM / Redis (по умолчанию встроенный в vLLM) |
| Инструмент для измерения TTFT | Python-клиент + time.perf_counter() или специализированное ПО (locust, hey) |
| Эталонный system prompt | Сформулировать самостоятельно (100–500 токенов) |
| Набор тестовых запросов | Сгенерировать через скрипт (5–10 различных user-prompt, каждый повторяется 3+ раз) |
| Мониторинг использования памяти | nvidia-smi, vllm stats endpoint, Prometheus (опционально) |
Если нет реального LLM-сервера — симулируем:
- Установите
vllm==0.6.0и скачайте маленькую модельQwen2.5-0.5B-Instructилиfacebook/opt-125m - Запустите сервер с флагами:
python -m vllm.entrypoints.openai.api_server --model facebook/opt-125m --enable-prefix-caching - Напишите скрипт, который отправляет запросы с одинаковым system prompt, замеряя
time_to_first_token - Повторите замеры с выключенным кешированием (флаг
--no-enable-prefix-caching)
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| LLM-сервер | vLLM (0.6.0+) / TGI / TensorRT-LLM | Инференс модели с поддержкой prefix caching |
| Клиент запросов | Python (openai, requests) + asyncio | Отправка запросов и замер времени |
| Модель | OPT-125M / Qwen2.5-0.5B (или любая малая) | Объект инференса |
| Измерение TTFT | time.perf_counter() / curl + -w "%{time_starttransfer}" | Фиксация времени первого токена |
| Кеш-storage | Встроенный в vLLM (RAM, hash-based) / отдельный Redis | Хранение кешированных KV-кэшей префиксов |
| Мониторинг | vllm stats endpoint + nvidia-smi | Контроль занятой памяти и cache hit rate |
| Версионирование | Git | Хранение скриптов и результатов |
4. Этапы выполнения
Этап 1: Настройка окружения и замер baseline (30–45 минут)
Действия
-
Установите vLLM и выбранную модель:
pip install vllm==0.7.1 python -m vllm.entrypoints.openai.api_server --model facebook/opt-125mУбедитесь, что сервер отвечает на
http://localhost:8000/v1/chat/completions. -
Создайте тестовые данные
- Один фиксированный system prompt:
"Ты — полезный ассистент. Отвечай кратко, по делу, на русском языке." - 5 разнообразных user-запросов (каждый не длиннее 50 токенов), например:
"Что такое квантовая запутанность?""Напиши функцию на Python для сортировки списка.""Переведи 'Hello world' на итальянский.""Какая столица Австралии?""Расскажи анекдот про программиста."
- Один фиксированный system prompt:
-
Напишите скрипт замера TTFT (baseline — без кеширования):
import time, openai, statistics client = openai.OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123") system_prompt = {"role": "system", "content": "Ты — полезный ассистент. Отвечай кратко, по делу, на русском языке."} user_messages = {...} # список user-промптов results = [] for msg in user_messages: for _ in range(5): # 5 повторений каждого запроса start = time.perf_counter() stream = client.chat.completions.create( model="facebook/opt-125m", messages=[system_prompt, {"role": "user", "content": msg}], stream=True, max_tokens=1 ) for chunk in stream: if chunk.choices[0].delta.content: ttft = time.perf_counter() - start results.append(ttft) break avg_ttft = statistics.mean(results) print(f"Baseline TTFT: {avg_ttft*1000:.2f} ms")Зафиксируйте средний TTFT.
-
Запустите скрипт и запишите baseline.
Ожидаемый результат этапа Значение среднего TTFT (в мс) для пяти повторений каждого запроса. Baseline зафиксирован в baseline.txt или в переменной.
Этап 2: Активация prefix caching и первичная проверка (30 минут)
Действия
-
Перезапустите vLLM с включённым prefix caching:
python -m vllm.entrypoints.openai.api_server --model facebook/opt-125m --enable-prefix-caching --max-model-len 2048Флаг
--enable-prefix-cachingзадействует встроенный механизм hash-based caching в vLLM. -
Запустите тот же скрипт замера (обратите внимание, что в vLLM prefix caching работает автоматически — при совпадении начала последовательности токенов KV-кэш переиспользуется). Однако первый запрос с new system prompt не будет закеширован. Чтобы получить выгоду, нужно повторять запросы с тем же system prompt.
-
Измерьте TTFT для первых запросов (каждый user-prompt — первый раз) и повторных запросов (с тем же system prompt и разными user-prompt, или теми же user-prompt).
Ожидаемый результат этапа TTFT для повторных запросов упал на 40–60% относительно baseline. Зафиксированы данные.
Этап 3: Оптимизация и настройка параметров кеширования (1 час)
Действия
-
Изучите конфигурацию prefix caching в vLLM:
--block-size(размер блоков KV-кэша, по умолчанию 16)--enable-prefix-caching(включает/выключает)--max-model-len(длина контекста)--max-num-batched-tokensи--max-num-seqs
-
Добавьте в тестовый сценарий разные длины system prompt (100, 300, 500 токенов) через скрипт:
import tokenizers tokenizer = tokenizers.Tokenizer.from_pretrained("facebook/opt-125m") long_system = "Ты — полезный ассистент. " * 50 # ~1000 символов, ~200 токенов system_prompt_content = tokenizer.decode(tokenizer.encode(long_system).ids[:200]) system_prompt = {"role": "system", "content": system_prompt_content} -
Измерьте TTFT для каждой длины system prompt с кешированием и без. Постройте график зависимости TTFT от длины prefix.
-
Попробуйте изменить
--block-size(например, 8, 32) и повторите замеры для одной длины.- Более мелкие блоки: выше гибкость кеширования, но больше метаданных.
- Крупные блоки: меньше оверхеда, но кеш работает только при точном совпадении целых блоков.
-
Проверьте cache hit rate (vLLM предоставляет эндпоинт
/statsили через аргумент--enable-cache-stats). Запишитеprefix_cache_hit_rateдля каждого запуска.
Ожидаемый результат этапа Таблица с TTFT для разных длин system prompt и значений block-size. Выбран оптимальный block-size (по умолчанию 16 — обычно хорош).
Этап 4: Проверка корректности и edge cases (45 минут)
Действия
-
Проверьте кеширование при частичном совпадении prefix:
-
Проверьте, что кеш не используется, если system prompt изменился полностью:
-
Проверьте стабильность при высокой нагрузке
- Напишите скрипт параллельных запросов (5–10 concurrent) с разными system prompt. Убедитесь, что TTFT для повторных запросов остаётся низким, а память не растёт неконтролируемо (watch nvidia-smi).
-
Проверьте корректность ответов
- Сравните текст ответа для запросов с кешированием и без. Они должны быть идентичны (генерируются одни и те же токены). Можно использовать хеширование ответов.
Ожидаемый результат этапа Подтверждение, что prefix caching работает корректно: ускорение только для совпадающего prefix, ответы не отличаются, система стабильна.
Этап 5: Анализ и документирование (30 минут)
Действия
-
Сведите все замеры в единый отчёт:
-
Сформулируйте рекомендации
-
Создайте файл README.md с инструкцией по включению prefix caching в продуктивном окружении.
Ожидаемый результат этапа Файл report.md с данными, графиками и выводами.
5. Критерии приемки (Definition of Done)
- Baseline TTFT измерен и задокументирован.
- vLLM запущен с
--enable-prefix-caching. - Скрипт замера корректно разделяет cold start и повторные запросы.
- TTFT для повторных запросов с тем же system prompt снижен на ≥50% относительно baseline.
- Проведены тесты с разной длиной system prompt (100, 300, 500 токенов).
- Проверена корректность ответов (хеши совпадают с baseline).
- Подтверждено отсутствие утечки памяти (nvidia-smi стабилен).
- Edge cases (частичное совпадение, полное изменение) отработаны без ошибок.
- Подготовлен отчёт с таблицами и графиками.
- README с рекомендациями по внедрению в production.
6. Ожидаемый результат
Основной результат Рабочая конфигурация LLM-сервера с включённым prefix caching и скрипт для воспроизводимых замеров TTFT.
Артефакты
baseline.txt— значение baseline TTFT.measure.py— скрипт для запуска тестов.results.csv— сырые замеры (время, тип запроса).report.md— итоговый отчёт, включая:README.md— инструкция по настройке prefix caching.
Опционально Jupyter notebook с визуализациями, Dockerfile для воспроизводимого окружения.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| vLLM не поддерживает prefix caching для текущей модели | Проверьте список supported models; используйте OPT, LLaMA, Mistral, или другие transformer-based модели. Для BLOOM может не работать. |
| TTFT не падает или падает незначительно | Убедитесь, что system prompt достаточно длинный (>100 токенов). Проверьте, что повторные запросы действительно используют тот же prefix – кеш работает на уровне токенов, а не текста. Включите логгирование cache hit (--enable-cache-stats). |
| Резкий рост памяти GPU | Prefix caching хранит KV-кеш для каждого уникального prefix. Ограничьте количество префиксов через --max-num-seqs или используйте LRU-стратегию (в vLLM встроена). Увеличьте --max-model-len, если кеш вытесняется. |
| Ответы отличаются при включенном кешировании | Проверьте, что --temperature=0 и --seed=42 для воспроизводимости. Различия могут быть из-за изменения порядка в batch processing – используйте max_tokens=1 и сравнивайте лог-вероятности. |
| Не удаётся запустить сервер на малом GPU | Используйте CPU-режим vLLM (--device cpu) или очень маленькую модель (GPT-2). Замеры будут медленнее, но относительное улучшение сохранится. |
CURL не показывает time_starttransfer | Используйте Python или hey (HTTP-нагрузочный инструмент). |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Настройка и baseline | 45 мин |
| Этап 2: Активация prefix caching | 30 мин |
| Этап 3: Оптимизация параметров | 60 мин |
| Этап 4: Edge cases и корректность | 45 мин |
| Этап 5: Анализ и документирование | 30 мин |
| Итого | 3.5 часа |
Примечание: Для первого выполнения с нуля может потребоваться до 5 часов, включая развёртывание vLLM и отладку несовместимостей.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 45 | LLM inference optimization: KV-cache |
| 112 | Time-to-first-token (TTFT) metrics |
| 203 | System prompt design and engineering |
| 304 | vLLM deployment and tuning |
| 401 | Caching strategies for LLM APIs |
| 512 | Sequence parallelism and caching |
| 618 | Batch inference and latency trade-offs |
| 722 | Memory management in transformer models |
| 815 | Prompt compression techniques |
| 901 | Benchmarking LLM serving systems |
10. Чек-лист самопроверки
- Я развернул LLM-сервер и проверил, что он отвечает на /v1/chat/completions.
- Я измерил TTFT без prefix caching (baseline) для каждого тестового запроса в 5 повторениях.
- Я включил
--enable-prefix-cachingи перезапустил сервер. - Я написал скрипт, который разделяет cold start и повторные запросы.
- Я получил снижение TTFT не менее чем на 50% для повторных запросов с тем же system prompt.
- Я проверил корректность ответов (сравнил вывод с baseline).
- Я провёл тесты с разными длинами system prompt и зафиксировал зависимость.
- Я проверил edge cases (частичное совпадение, смена prompt) и отсутствие ошибок.
- Я подготовил итоговый отчёт в
report.mdиREADME.md. - Я могу объяснить, почему TTFT снизился, и в каких сценариях этот подход неэффективен.