中文翻译暂不可用,显示俄语原文。
Реализовать semantic cache для LLM
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать semantic cache для LLM
1. Цель задачи
Реализовать семантический кэш для LLM‑запросов на основе Qdrant и косинусного порога (threshold similarity). Кэш позволяет повторно использовать ответы на семантически похожие запросы, снижая затраты на API и latency. Ключевой результат функционирующий semantic cache с cache hit rate 30–50% на репрезентативном наборе запросов.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Qdrant (векторное хранилище) | Docker-образ qdrant/qdrant |
| Набор тестовых запросов (100–500 штук) | Синтезировать на основе FAQ, датасетов (например, Natural Questions) или выгрузить из логов реального чата |
| Embedding модель | sentence-transformers/all-MiniLM-L6-v2 (или аналог) |
| LLM API (OpenAI или любой совместимый) | Аккаунт OpenAI / мок-сервер (например, FastAPI, возвращающий фиксированный ответ) |
| Python 3.10+ | Установленный интерпретатор |
| Библиотеки | qdrant-client, sentence-transformers, openai, numpy, pandas, matplotlib |
Если нет реального инструмента — симулируем:
- Нет датасета запросов — сгенерируйте 200 вариаций для 10 сущностей (например, «Какой сегодня курс доллара?», «курс USD сейчас», «доллар к рублю сегодня»), чтобы естественно покрыть различные paraphrase.
- Нет LLM API — запустите мок-сервер на FastAPI, который принимает prompt и возвращает заранее заготовленную строку, эмулируя задержку 0.5–1 сек.
- Нет Qdrant — используйте Qdrant в Docker:
docker run -p 6333:6333 qdrant/qdrant.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Векторное хранилище | Qdrant (Docker) | Хранение эмбеддингов запросов и ответов, поиск по косинусной мере |
| Embedding | sentence-transformers/all-MiniLM-L6-v2 | Получение плотных векторных представлений запросов |
| LLM (для заполнения кэша) | OpenAI API / мок-сервер | Генерация ответа при промахе кэша |
| Оркестрация | Python, asyncio | Кэш-клиент (проверка + вставка) |
| Профилирование | time, matplotlib, pandas | Оценка hit rate, latency, экономии |
4. Этапы выполнения
Этап 1: Подготовка инфраструктуры и данных (1 час)
Действия
- Развернуть Qdrant в Docker:
docker pull qdrant/qdrant docker run -d --name qdrant -p 6333:6333 qdrant/qdrant - Установить Python-зависимости:
qdrant-client,sentence-transformers,openai,numpy,pandas,matplotlib. - Создать коллекцию
llm_cacheс параметрами:vectors_config: размерность 384 (all-MiniLM-L6-v2), distance = Cosineoptimizers_config: default values
- Сгенерировать тестовый датасет запросов (CSV-файл с колонками
original_query,variant_query,expected_answer). Варианты должны иметь косинусную схожесть > 0.7 с оригиналом. - Написать функцию
get_embedding(text)для превращения текста в вектор.
Ожидаемый результат этапа Работающий Qdrant, коллекция с векторами размерности 384, тестовый датасет в data/test_queries.csv.
Этап 2: Реализация ядра semantic cache (2–3 часа)
Действия
- Разработать класс
SemanticCache:class SemanticCache: def __init__(self, host="localhost", port=6333, threshold=0.8, ttl_seconds=86400): # инициализация клиента Qdrant, эмбеддера # создание коллекции, если не существует pass def get_cached_response(self, query): # получить эмбеддинг запроса # search в Qdrant с limit=1, score_threshold=threshold # если результат найден и score >= threshold → возвращаем сохранённый ответ # иначе → None pass def store_cache(self, query, response): # получить эмбеддинг запроса # upsert: точка с payload={“query”: query, “response”: response, “timestamp”: time} pass - Добавить поддержку TTL (удалять записи старше N секунд через background task или при вставке).
- Реализовать асинхронную версию методов для production-нагрузки (опционально — на async-клиенте Qdrant).
Ожидаемый результат этапа Модуль semantic_cache.py, который корректно возвращает None при промахе и ответ из кэша при попадании.
Этап 3: Интеграция с LLM и тест-драйв (1.5 часа)
Действия
- Написать функцию
get_llm_response(prompt)— вызов OpenAI API (или мока). - Реализовать функцию
cached_llm(prompt, cache):def cached_llm(prompt, cache): cached = cache.get_cached_response(prompt) if cached: return cached, "cache_hit" else: response = get_llm_response(prompt) cache.store_cache(prompt, response) return response, "cache_miss" - Провести прогон на 100 запросах (50 оригинальных + 50 paraphrase), замерить:
- число cache hit / miss
- время ответа (latency) для hit и miss
- корректность: сравнить ответы из кэша с «эталонными» (для paraphrase – с ответом на оригинал, считается OK, если content схож >80% по BLEU или LLM-as-judge)
Ожидаемый результат этапа Запуск на тестовых данных; видно, сколько запросов сэкономлено.
Этап 4: Оценка метрик и тюнинг threshold (1.5 часа)
Действия
- Прогнать весь тестовый датасет с разными значениями
threshold: 0.7, 0.75, 0.8, 0.85, 0.9. - Для каждого порога вычислить:
- Построить график зависимости hit rate от threshold.
- Выбрать порог, который даёт hit rate 30–50% при accuracy > 95%.
Ожидаемый результат этапа Таблица метрик, график, выбранный threshold.
Этап 5: Документация и отчёт (1 час)
Действия
- Написать краткую документацию к модулю (README или docstring) – как запустить, параметры, пример.
- Сформировать отчёт с метриками:
Отчёт: Semantic Cache Evaluation - Threshold: 0.82 - Cache hit rate: 38% - Miss latency: 1200 ms - Hit latency: 10 ms (включая поиск в Qdrant) - Estimated cost savings: 38% (при цене $0.01/запрос экономия ~$0.0038/test_run) - Включить графики в отчёт (PNG или встроенные).
Ожидаемый результат этапа Пакет semantic_cache/ с кодом, требованиями, примером запуска и отчётом (Jupyter notebook или PDF).
5. Критерии приемки (Definition of Done)
- Qdrant поднимается одной командой
docker compose up(или docker run). -
SemanticCacheкорректно сохраняет и находит запросы по косинусной близости. - При наличии семантически похожего запроса (≥ threshold) возвращается ответ из кэша.
- Cache hit rate на синтезированном датасете составляет 30–50% при threshold, обеспечивающем accuracy ≥ 95%.
- Latency при cache hit ≤ 50 мс (на локальной машине).
- Реализован автоматический TTL (устаревшие записи не возвращаются).
- Код покрыт докстрингами и содержит пример использования (
examples/demo.py). - Отчёт содержит таблицу метрик для 3–5 значений threshold и график hit rate vs accuracy.
6. Ожидаемый результат
Основной артефакт Папка semantic-cache/ с:
semantic_cache.py— классSemanticCacherequirements.txtdata/test_queries.csvexamples/demo.py— скрипт для тестового прогонаreport.ipynb— Jupyter notebook с вычислением метрик и графиками
Дополнительно
docker-compose.yml(опционально, для единого подъёма Qdrant)- README.md с инструкцией по запуску и описание параметров (threshold, TTL)
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Qdrant не отвечает на localhost | Проверить, что контейнер запущен (docker ps); порт 6333 проброшен; использовать client.http=True |
| Embedding модель медленно загружается | Загружать модель один раз при старте (Singleton); использовать GPU, если доступен |
| Слишком низкий hit rate — запросы не похожи | Уменьшить threshold (но не ниже 0.7); улучшить качество paraphrase в датасете |
| Слишком высокий hit rate — кэш выдаёт нерелевантные ответы | Увеличить threshold до 0.85–0.9; добавить проверку на payload-фильтр (например, категорию запроса) |
| Нарушение TTL | Реализовать recreate_index или фильтр при search по полю timestamp |
| Параллельные запросы: гонка данных | Использовать опцию wait=True при upsert; рассмотреть блокировку на уровне in-memory, если нужна строгая консистентность |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| 1. Подготовка | 1 час |
| 2. Реализация ядра | 2–3 часа |
| 3. Интеграция и тест-драйв | 1.5 часа |
| 4. Оценка метрик и тюнинг | 1.5 часа |
| 5. Документация и отчёт | 1 час |
| Итого | 7–8 часов |
Примечание для первого раза добавьте 2 часа на настройку окружения (Docker, зависимости) и отладку threshold.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 42 | Стратегии кэширования для LLM |
| 67 | Векторные базы данных (Qdrant, Weaviate, Milvus) |
| 89 | Sentence embeddings и cosine similarity |
| 134 | Снижение latency в RAG-системах |
| 201 | Cost optimization для OpenAI API |
| 218 | TTL и eviction policy в кэшах |
| 307 | Оценка качества paraphrase |
| 411 | Интеграция Qdrant с Python |
| 522 | Batch-обработка эмбеддингов |
| 678 | A/B тестирование порогов similarity |
10. Чек-лист самопроверки
- Я развернул Qdrant и убедился, что клиент подключается (
client.get_collections()не падает). - Я выбрал threshold и проверил на 10 ручных парах запросов, что кэш работает ожидаемо.
- Я замерил hit rate на полном датасете — результат между 30% и 50%.
- Я проверил, что при cache hit latency не превышает 50 мс.
- Я добавил TTL и убедился, что старые записи не возвращаются (проверка через
time.sleepпосле вставки).