Cache truyền thống (Redis, Memcached) dùng exact key match — user gõ "thủ đô VN?" và "Việt Nam có thủ đô gì?" → cache miss dù ý giống nhau. Semantic cache embed query, tìm query tương đồng trong cache, trả response đã cache nếu đủ giống.
Lợi ích: 20-40% hit rate cho customer support / FAQ / Q&A bot → giảm cost + latency tương ứng.
Implementation đơn giản (Python, dùng Qdrant làm vector store):
import hashlib
from openai import OpenAI
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
client = OpenAI()
qdrant = QdrantClient(":memory:") # prod: URL + auth
CACHE = "semantic_cache"
THRESHOLD = 0.92 # cosine similarity threshold
qdrant.recreate_collection(
collection_name=CACHE,
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
def embed(text: str) -> list[float]:
return client.embeddings.create(
model="text-embedding-3-small", input=text
).data[0].embedding
def cache_lookup(query: str) -> str | None:
q_vec = embed(query)
hits = qdrant.search(
collection_name=CACHE,
query_vector=q_vec,
limit=1,
)
if hits and hits[0].score >= THRESHOLD:
return hits[0].payload["response"]
return None
def cache_store(query: str, response: str):
q_vec = embed(query)
point_id = int(hashlib.md5(query.encode()).hexdigest()[:15], 16)
qdrant.upsert(
collection_name=CACHE,
points=[PointStruct(
id=point_id,
vector=q_vec,
payload={"query": query, "response": response},
)],
)
def cached_llm(query: str) -> tuple[str, bool]:
"""Returns (response, was_cached)."""
cached = cache_lookup(query)
if cached:
return cached, True
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": query}],
).choices[0].message.content
cache_store(query, response)
return response, False
# --- USAGE ---
print(cached_llm("Thủ đô Việt Nam là gì?"))
# → (Hà Nội, False)
print(cached_llm("Việt Nam có thủ đô gì?"))
# → (Hà Nội, True) # semantic matchNâng cấp production:
1. TTL (time-to-live) — lưu timestamp, expire sau N giờ/ngày. Quan trọng cho query theo time (giá, tỷ giá, weather).
from datetime import datetime, timedelta
payload["expires_at"] = (datetime.utcnow() + timedelta(hours=24)).isoformat()2. Context-aware keys — chỉ cache query không có user-specific context:
- User hỏi "số dư tài khoản tôi là bao nhiêu?" → KHÔNG cache (per-user).
- User hỏi "phí chuyển khoản là bao nhiêu?" → cache OK (general).
- Classify trước khi store.
3. Threshold tuning:
- 0.95+ → conservative, ít hit nhưng chính xác.
- 0.85-0.92 → aggressive, nhiều hit nhưng có risk false positive.
- Measure: cho 100 query, manual check cache hit có thực sự đúng không.
4. Cache invalidation — source data update → invalidate cache. Tag cache với source version.
5. Multi-tenancy — namespace per tenant; 1 tenant không thấy cache của tenant khác.
6. Partial cache — cache từng component (RAG retrieval result, embedding) riêng, không chỉ full response.
7. Monitoring:
- Hit rate overall và per endpoint.
- Cost saved ($/hour).
- False positive rate (response sai do cache match nhầm).
- Cache size, eviction rate.
Tool sẵn có:
- GPTCache (thư viện Python) — semantic cache layer có sẵn, support nhiều vector backend + LLM provider. Drop-in replacement cho OpenAI client:
from gptcache.adapter import openai
response = openai.ChatCompletion.create(...) # cache transparent- LangChain — có
CacheLLMvới semantic option. - Redis + RediSearch — vector search built-in.
- Portkey, Helicone — commercial gateway có semantic cache.
Limitation & caveat:
- Chat multi-turn khó cache: context phụ thuộc history → semantic match khó. Thường chỉ cache single-turn query.
- Personalized response không cache được.
- Creative task (viết email, story) cache → user nhận cùng output → bad UX.
- Cache stored trong DB phải encrypt / PII-scrub trước (compliance).
- Threshold quá thấp → false positive; quá cao → hit rate thấp.
Rule: bật semantic cache sau khi có baseline cost observability; đo hit rate thực → tune threshold. Không blind-apply.