LLM-запити дорогі та повільні. Особливо коли 30–40% з них дублюються або семантично схожі. Кешування LLM — найдешевший спосіб знизити обидва показники. Наша компанія має 10+ років досвіду в AI/ML та понад 50 реалізованих проєктів із впровадження exact та semantic кешування LLM під ключ: від простого exact match до семантичного пошуку за ембеддингами. Exact cache дає hit rate до 35%, Semantic cache — ще 28%, і разом вони закривають 63% запитів без виклику LLM. При типовому навантаженні 5000 запитів/день це значна економія коштів — до $10,000 на місяць на GPT-4o або $15,000 на Claude. Оцінимо ваш проєкт за 1 день — просто зв'яжіться з нами.
Головний біль — кожен повторний запит до GPT-4o або Claude летить в API та оплачується. При типовому навантаженні 5000 запитів/день 30% — дублікати. Exact cache на Redis повертає відповідь за 5–15 мс замість 2–5 секунд — це в 100 разів швидше. Semantic cache додає ще 20–28% збігів за змістом, навіть якщо формулювання інше. Провали контексту при частих однотипних питаннях також усуваються — кеш гарантує стабільну відповідь без галюцинацій. Exact та Semantic cache — два основні види кешування LLM, які ми комбінуємо для максимальної ефективності.
Як влаштований Exact Cache?
Просто: хешуємо промпт (messages, model, temperature) та зберігаємо відповідь у Redis. При повторному запиті з тим же хешем — повертаємо без виклику LLM. Підходить для FAQ, форм, шаблонних запитів. Exact cache обробляє запит у 100 разів швидше, ніж Semantic cache (5–15 мс проти 50–100 мс).
Реалізація Exact Cache
import hashlib
import json
import redis
from typing import Optional
from functools import wraps
class ExactLLMCache:
def __init__(self, redis_url: str = "redis://localhost:6379", ttl: int = 3600):
self.redis = redis.from_url(redis_url)
self.ttl = ttl
def _make_key(self, messages: list[dict], model: str, temperature: float) -> str:
"""Створює ключ кешу з параметрів запиту"""
cache_input = {
"messages": messages,
"model": model,
"temperature": temperature,
}
content = json.dumps(cache_input, sort_keys=True, ensure_ascii=False)
return f"llm:exact:{hashlib.sha256(content.encode()).hexdigest()}"
def get(self, messages: list[dict], model: str, temperature: float = 0) -> Optional[str]:
key = self._make_key(messages, model, temperature)
cached = self.redis.get(key)
if cached:
return cached.decode()
return None
def set(self, messages: list[dict], model: str, temperature: float, response: str):
key = self._make_key(messages, model, temperature)
self.redis.setex(key, self.ttl, response.encode())
def cached_complete(self, complete_fn):
"""Декоратор для кешування функцій"""
@wraps(complete_fn)
def wrapper(messages, model="gpt-4o", temperature=0, **kwargs):
cached = self.get(messages, model, temperature)
if cached:
return cached
result = complete_fn(messages, model=model, temperature=temperature, **kwargs)
self.set(messages, model, temperature, result)
return result
return wrapper
Навіщо потрібен Semantic Cache?
Exact кеш ловить лише однакові запити, але користувачі часто переформульовують питання. Semantic Cache вирішує цю проблему: перетворюємо питання на ембеддинг, шукаємо у векторній БД схожі, і при косинусній схожості >0.92 повертаємо відповідь. Ефективно для чатів, де формулювання відрізняються. Семантичний кеш хоч і повільніший за точний (50–100 мс vs 5–15 мс), але краще справляється з варіаціями питань.
Реалізація Semantic Cache
from openai import OpenAI
import numpy as np
from dataclasses import dataclass
@dataclass
class CachedEntry:
query_embedding: list[float]
question: str
answer: str
model: str
created_at: float
class SemanticLLMCache:
"""Кеш на основі векторної схожості питань"""
def __init__(
self,
similarity_threshold: float = 0.92,
max_entries: int = 10000,
):
self.openai = OpenAI()
self.threshold = similarity_threshold
self.entries: list[CachedEntry] = []
def _get_embedding(self, text: str) -> list[float]:
response = self.openai.embeddings.create(
model="text-embedding-3-small",
input=text,
)
return response.data[0].embedding
def _cosine_similarity(self, a: list[float], b: list[float]) -> float:
a_arr = np.array(a)
b_arr = np.array(b)
return np.dot(a_arr, b_arr) / (np.linalg.norm(a_arr) * np.linalg.norm(b_arr))
def get(self, question: str, model: str = None) -> Optional[str]:
"""Шукає схоже питання в кеші"""
if not self.entries:
return None
query_embedding = self._get_embedding(question)
best_similarity = 0
best_answer = None
for entry in self.entries:
if model and entry.model != model:
continue
similarity = self._cosine_similarity(query_embedding, entry.query_embedding)
if similarity > best_similarity:
best_similarity = similarity
best_answer = entry.answer
if best_similarity >= self.threshold:
return best_answer
return None
def set(self, question: str, answer: str, model: str):
"""Додає запис до кешу"""
import time
embedding = self._get_embedding(question)
entry = CachedEntry(
query_embedding=embedding,
question=question,
answer=answer,
model=model,
created_at=time.time(),
)
self.entries.append(entry)
# Обмежуємо розмір кешу
if len(self.entries) > 10000:
self.entries = sorted(self.entries, key=lambda e: e.created_at)[-10000:]
Порівняння Exact та Semantic Cache
| Характеристика | Exact Cache | Semantic Cache |
|---|---|---|
| Принцип | Хеш промпту | Векторна схожість |
| Сховище | Redis | ChromaDB / Qdrant |
| Latency (p95) | 5–15 мс | 50–100 мс |
| Hit rate | до 35% | до 28% |
| Використання | Часто повторювані запити | Семантично схожі питання |
| Складність реалізації | Низька | Середня |
Exact та Semantic cache – два основні види кешування LLM, які ми комбінуємо для досягнення максимального hit rate.
Комбінований кеш: Redis + векторне сховище
У production ми об'єднуємо обидва підходи: спочатку перевіряємо exact cache (Redis), потім semantic (ChromaDB). Це дає мінімальну latency та максимальний hit rate. Така комбінація exact та semantic кешування LLM дозволяє досягти 63% попадань.
Production реалізація
import chromadb
import time
class ProductionSemanticCache:
"""Production-ready кеш: Redis для exact, Chroma для semantic"""
def __init__(self):
self.redis = redis.from_url("redis://localhost:6379")
self.chroma = chromadb.HttpClient(host="localhost", port=8000)
self.collection = self.chroma.get_or_create_collection("llm_cache")
self.openai = OpenAI()
self.similarity_threshold = 0.93
self.exact_ttl = 3600
self.semantic_ttl = 86400 # 24 години
def get(self, question: str, model: str) -> Optional[dict]:
# 1. Exact match спочатку (швидко)
exact_key = f"llm:exact:{hashlib.md5(f'{question}:{model}'.encode()).hexdigest()}"
exact_hit = self.redis.get(exact_key)
if exact_hit:
return {"answer": exact_hit.decode(), "cache_type": "exact"}
# 2. Semantic match
embedding = self.openai.embeddings.create(
model="text-embedding-3-small",
input=question,
).data[0].embedding
results = self.collection.query(
query_embeddings=[embedding],
n_results=1,
where={"model": model},
)
if results["distances"] and results["distances"][0]:
distance = results["distances"][0][0]
similarity = 1 - distance # Chroma використовує косинусну відстань
if similarity >= self.similarity_threshold:
answer = results["documents"][0][0]
return {"answer": answer, "cache_type": "semantic", "similarity": similarity}
return None
def set(self, question: str, answer: str, model: str):
# Exact cache у Redis
exact_key = f"llm:exact:{hashlib.md5(f'{question}:{model}'.encode()).hexdigest()}"
self.redis.setex(exact_key, self.exact_ttl, answer.encode())
# Semantic cache у Chroma
embedding = self.openai.embeddings.create(
model="text-embedding-3-small",
input=question,
).data[0].embedding
self.collection.add(
ids=[f"{int(time.time())}_{hash(question)}"],
embeddings=[embedding],
documents=[answer],
metadatas=[{"model": model, "question": question, "created_at": time.time()}],
)
Як виміряти ефективність кешу?
Для оцінки впроваджуємо метрики: hit rate, latency p95, cost per request. Типові показники: exact hit 35%, semantic hit 28%, середня latency знижується з 2.3 с до 0.4 с. Для моніторингу використовуємо дашборди з алертами при падінні hit rate нижче порогу. Поріг косинусної схожості 0.92 обраний емпірично — він мінімізує false positives, зберігаючи до 95% релевантних збігів. При порозі 0.95 hit rate падає на 12%, при 0.90 — зростає кількість невірних відповідей.
Кейс нашого клієнта: FAQ-бот на 5000 запитів/день
Ми впровадили для клієнта (сервіс технічної підтримки) комбінований exact та semantic кеш LLM. До впровадження всі запити йшли напряму в GPT-4o. Наша команда (10+ років досвіду, понад 50 проєктів) налаштувала рішення. Результати:
| Метрика | До кешу | Після кешу |
|---|---|---|
| Витрати на LLM | 100% | 37% |
| Економія | — | $8,000/міс |
| Середня latency | 2.3 сек | 0.4 сек |
| Exact hit rate | 0% | 35% |
| Semantic hit rate | 0% | 28% |
Економія 63% (до $8,000 на місяць) — лише за рахунок кешування, без зміни моделі. Отримайте консультацію інженера — розрахуємо потенційну економію для вашого проєкту.
Що входить у нашу роботу
- Аналітика — аудит ваших запитів, виявлення патернів, розрахунок потенційного hit rate.
- Архітектура — вибір стеку (Redis / Chroma / Qdrant), проектування схеми кешу.
- Реалізація — написання production-коду (Python, інтеграція з вашим LLM-провайдером).
- Тестування — A/B тест із заміром latency та cost на ваших даних.
- Моніторинг — дашборд hit rate, dashboard latency, алерти при падінні ефективності.
- Документація та навчання — передача коду, інструкції, навчання команди.
Терміни орієнтовно
• Exact cache (Redis): 0.5–1 день • Semantic cache (Chroma + embeddings): 2–3 дні • Повне production-рішення з моніторингом: 1 тиждень
Гарантуємо стабільну роботу кешу, підтримку після впровадження та прозору звітність. Замовте аудит вашого проєкту — оцінимо hit rate та економію за 1 день.







