skills/llm-response-caching-layer/SKILL.md
Implement semantic and exact-match caching for LLM responses to reduce cost 40-60% and latency. Activate on: LLM caching, semantic cache, reduce API costs, cache AI responses. NOT for: general web caching (caching-strategies), CDN config (cloudflare-worker-dev).
npx skillsauth add curiositech/windags-skills llm-response-caching-layerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Implement semantic and exact-match caching for LLM API responses to reduce costs 40-60% and cut P50 latency from seconds to milliseconds.
Activate on: "cache LLM responses", "semantic cache", "reduce OpenAI costs", "LLM API caching", "cache embeddings", "deduplicate LLM calls", "response memoization for AI"
NOT for: General HTTP/CDN caching (caching-strategies), browser cache headers (caching-strategies), or database query caching (ORM-specific)
| Domain | Technologies | Notes | |--------|-------------|-------| | Exact-Match Cache | Redis, DynamoDB, Memcached | Hash(prompt + model + temperature + params) as key | | Semantic Cache | GPTCache, Qdrant, Pinecone, pgvector | Embed query, find similar cached responses | | Similarity Threshold | Cosine similarity >= 0.95 typical | Tune per use case; lower = more hits, more risk | | Cache Invalidation | TTL-based, version-tagged, manual purge | LLM responses rarely need real-time freshness | | Observability | Cache hit/miss rates, cost savings, latency delta | Essential for ROI justification |
LLM Request
│
▼
[Exact Match Cache (Redis)] ──hit──→ Return cached response (< 5ms)
│ miss
▼
[Semantic Cache (Vector DB)] ──hit (similarity > 0.95)──→ Return cached response (< 50ms)
│ miss
▼
[LLM API Call] ──→ response ──→ Store in both caches ──→ Return response
# Two-tier caching middleware
import hashlib, json, numpy as np
class LLMCacheMiddleware:
def __init__(self, redis_client, vector_db, embedder, threshold=0.95):
self.redis = redis_client
self.vdb = vector_db
self.embedder = embedder
self.threshold = threshold
def cache_key(self, prompt: str, model: str, **params) -> str:
blob = json.dumps({"prompt": prompt, "model": model, **params}, sort_keys=True)
return f"llm:{hashlib.sha256(blob.encode()).hexdigest()}"
async def query(self, prompt: str, model: str, **params) -> str:
# Tier 1: Exact match
key = self.cache_key(prompt, model, **params)
cached = await self.redis.get(key)
if cached:
return json.loads(cached)["response"] # < 5ms
# Tier 2: Semantic match
query_emb = self.embedder.embed(prompt)
results = self.vdb.search(query_emb, top_k=1)
if results and results[0].score >= self.threshold:
return results[0].payload["response"] # < 50ms
# Cache miss: call LLM
response = await llm_call(prompt, model, **params)
# Store in both tiers
await self.redis.setex(key, 86400, json.dumps({"response": response}))
self.vdb.upsert(query_emb, {"prompt": prompt, "response": response})
return response
Incoming Request
│
▼
[Classify Cacheability]
├── temperature == 0 AND structured output → HIGHLY CACHEABLE (TTL: 7 days)
├── temperature == 0 AND free-form → CACHEABLE (TTL: 24 hours)
├── temperature > 0 AND repeated pattern → SEMANTIC CACHE ONLY (TTL: 1 hour)
└── temperature > 0 AND unique/creative → DO NOT CACHE
Cache Key = hash(prompt + model_version + system_prompt_version + params)
Model upgrade (gpt-4o-2026-01 → gpt-4o-2026-03):
→ All cache keys change automatically (model_version in hash)
→ Old cache entries expire via TTL
→ No manual invalidation needed
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.