Skip to main content

Time-aware semantic LLM cache — automatically invalidates stale AI answers

Project description

temporal-cache

Time-aware semantic caching for LLM responses

Python 3.9+ License: MIT Tests

Cache LLM responses by semantic meaning AND freshness. Stop serving stale answers.


Table of Contents


What is temporal-cache?

temporal-cache is a semantic cache for LLM API responses that understands when an answer was relevant, not just what it says.

Traditional semantic caches store responses and return them when a similar query arrives. But they don't know if that response is still correct. A cached answer about "current US president" from 2024 is semantically relevant in 2026 — but wrong.

temporal-cache solves this with a StalenessClass classifier that evaluates how time-sensitive a query is, and an optional LLM-based semantic classifier that detects when cached content has drifted from current facts.

Use cases:

  • Knowledge bases with evolving information
  • Customer support bots with changing policies
  • Financial/news Q&A systems
  • Any LLM application where answers expire

The Problem

┌─────────────────────────────────────────────────────────────────┐
│  Traditional Semantic Cache                                      │
│                                                                  │
│  Query: "What is the capital of France?"                         │
│  Cache hit → "Paris" ✓                                           │
│                                                                  │
│  Query: "What's the current CEO of Tesla?"                       │
│  Cache hit → "Elon Musk" (cached 2024)                           │
│  Reality: CEO changed in 2025 ✗                                   │
│                                                                  │
│  Problem: Cache doesn't know the answer is stale                 │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│  temporal-cache                                                  │
│                                                                  │
│  Query: "What's the current CEO of Tesla?"                       │
│  StalenessClass: DYNAMIC (changes frequently)                    │
│  Action: Revalidate → check if cache is still valid              │
│  Result: Fresh answer or cache with metadata about freshness     │
└─────────────────────────────────────────────────────────────────┘

How It Works

Cache Flow

                          ┌──────────────┐
                          │   Incoming   │
                          │    Query     │
                          └──────┬───────┘
                                 │
                                 ▼
                    ┌────────────────────────┐
                    │  StalenessClass        │
                    │  Classifier            │
                    │                        │
                    │  STATIC │ EVOLVING │   │
                    │  SEMI-  │ DYNAMIC  │   │
                    │  STATIC │          │   │
                    └────────┬───────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
         ┌─────────┐   ┌─────────┐   ┌─────────┐
         │ STATIC  │   │ SEMI-   │   │ DYNAMIC │
         │         │   │ STATIC  │   │         │
         │ Cache   │   │ Cache   │   │ Reval-  │
         │ Forever │   │ + TTL   │   │ idate   │
         └─────────┘   └─────────┘   └─────────┘
              │              │              │
              │              │              │
              ▼              ▼              ▼
         ┌─────────────────────────────────────────┐
         │           Semantic Similarity           │
         │              (embedding)                │
         └──────────────────┬──────────────────────┘
                            │
              ┌─────────────┴─────────────┐
              │                           │
              ▼                           ▼
         Hit (≥ threshold)          Miss
              │                           │
              ▼                           ▼
         ┌──────────┐              ┌──────────────┐
         │ Return   │              │ Call LLM     │
         │ Cached   │              │ Store with   │
         │ Response │              │ metadata     │
         └──────────┘              └──────────────┘

Staleness Classification

Each query is classified into one of four staleness classes:

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  Query Analysis                                                  │
│  ═══════════════                                                 │
│                                                                  │
│  "What is 2+2?"                    → STATIC                     │
│  "What is Python?"                 → STATIC                     │
│  "Explain quantum computing"       → SEMI_STATIC                │
│  "What are Python best practices?" → SEMI_STATIC                │
│  "Who is the current US president?"→ DYNAMIC                    │
│  "Tesla stock price today"         → DYNAMIC                    │
│  "Latest news about OpenAI"        → EVOLVING                   │
│  "What changed in Python 3.12?"    → EVOLVING                   │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Installation

pip install temporal-cache

From source:

git clone https://github.com/yourusername/temporal-cache.git
cd temporal-cache
pip install -e .

With Redis support:

pip install temporal-cache[redis]

Requirements

  • Python 3.9+
  • sentence-transformers (for embeddings)
  • redis (optional, for Redis backend)

Quick Start

from temporal_cache import TemporalCache

# Initialize with default settings (in-memory backend)
cache = TemporalCache()

# Or with Redis backend
cache = TemporalCache(
    backend="redis",
    redis_url="redis://localhost:6379",
    embedding_model="all-MiniLM-L6-v2"
)

# Store a response
cache.set(
    query="What is the capital of France?",
    response="Paris is the capital of France.",
    metadata={"source": "wikipedia", "verified": True}
)

# Retrieve a response (semantic match)
result = cache.get("What's the capital of France?")

if result:
    print(f"Cache hit: {result.response}")
    print(f"Staleness: {result.staleness_class}")
    print(f"Freshness: {result.freshness_score}")
else:
    print("Cache miss - call your LLM here")

Python API Reference

TemporalCache

TemporalCache(
    backend: str = "memory",           # "memory" or "redis"
    redis_url: str = "redis://localhost:6379",
    embedding_model: str = "all-MiniLM-L6-v2",
    similarity_threshold: float = 0.85,
    ttl_config: dict = None,           # Custom TTL per staleness class
    llm_classifier: bool = False,      # Enable LLM-based revalidation
    classifier_model: str = None       # Model for LLM classifier
)

Methods

set(query, response, metadata=None, staleness_class=None)

Store a query-response pair in the cache.

Parameter Type Description
query str The input query
response str The LLM response to cache
metadata dict Optional metadata (source, timestamp, etc.)
staleness_class StalenessClass Override auto-detected class

get(query, force_refresh=False)

Retrieve a cached response by semantic similarity.

Parameter Type Description
query str The query to look up
force_refresh bool Bypass cache, always return None

Returns CacheResult or None.

invalidate(query=None, pattern=None)

Remove entries from cache.

# Invalidate specific query
cache.invalidate(query="What is the capital of France?")

# Invalidate by pattern
cache.invalidate(pattern="*stock*")

stats()

Return cache statistics.

stats = cache.stats()
# {
#     "total_entries": 1523,
#     "hits": 892,
#     "misses": 231,
#     "stale_rejections": 45,
#     "avg_freshness_score": 0.87
# }

CacheResult

@dataclass
class CacheResult:
    response: str
    similarity_score: float
    staleness_class: StalenessClass
    freshness_score: float          # 0.0 (stale) to 1.0 (fresh)
    cached_at: datetime
    metadata: dict

StalenessClass

class StalenessClass(Enum):
    STATIC = "static"           # Never changes
    SEMI_STATIC = "semi_static" # Changes rarely
    EVOLVING = "evolving"       # Changes periodically
    DYNAMIC = "dynamic"         # Changes frequently

Staleness Classes

Class Description TTL Revalidation Examples
STATIC Facts that don't change Never "What is π?", "2+2", "What is DNA?"
SEMI_STATIC Rarely changes 30 days On major events "Python docs", "Physics laws", "Best practices"
EVOLVING Changes periodically 24 hours On schedule "Python 3.12 features", "Company policies"
DYNAMIC Changes constantly 1 hour Every query "Stock price", "Current president", "Live news"

Custom TTL Configuration

cache = TemporalCache(
    ttl_config={
        "static": None,              # No expiration
        "semi_static": 86400 * 30,   # 30 days
        "evolving": 86400,           # 1 day
        "dynamic": 3600              # 1 hour
    }
)

Architecture

temporal_cache/
├── __init__.py
├── cache.py              # TemporalCache engine
├── classifiers/
│   ├── __init__.py
│   ├── staleness.py      # StalenessClass rule-based classifier
│   └── llm.py            # LLM-based semantic classifier
├── backends/
│   ├── __init__.py
│   ├── memory.py         # In-memory backend (dict)
│   └── redis.py          # Redis backend
├── embeddings.py         # Embedding generation
├── models.py             # CacheResult, CacheEntry dataclasses
├── config.py             # Configuration and defaults
└── utils.py              # Helpers

Data Flow

┌─────────────────────────────────────────────────────────────────────┐
│                                                                     │
│  User Query                                                         │
│       │                                                             │
│       ▼                                                             │
│  ┌─────────────┐     ┌──────────────────┐                           │
│  │ Staleness   │────▶│ Embedding        │                           │
│  │ Classifier  │     │ Generator        │                           │
│  └──────┬──────┘     └────────┬─────────┘                           │
│         │                     │                                     │
│         ▼                     ▼                                     │
│  ┌─────────────┐     ┌──────────────────┐                           │
│  │ TTL         │     │ Backend          │                           │
│  │ Manager     │     │ (Memory/Redis)   │                           │
│  └──────┬──────┘     └────────┬─────────┘                           │
│         │                     │                                     │
│         └──────────┬──────────┘                                     │
│                    │                                                │
│                    ▼                                                │
│         ┌──────────────────────┐                                    │
│         │ Response Validator   │                                    │
│         │                      │                                    │
│         │ - Check similarity   │                                    │
│         │ - Check freshness    │                                    │
│         │ - LLM revalidation   │                                    │
│         └──────────┬───────────┘                                    │
│                    │                                                │
│         ┌──────────┴──────────┐                                     │
│         │                     │                                     │
│         ▼                     ▼                                     │
│    Cache Hit              Cache Miss                                │
│    (return)               (call LLM, store)                         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Configuration

Environment Variables

TEMPORAL_CACHE_BACKEND=redis
TEMPORAL_CACHE_REDIS_URL=redis://localhost:6379
TEMPORAL_CACHE_SIMILARITY_THRESHOLD=0.85
TEMPORAL_CACHE_DEFAULT_TTL=3600

Configuration File

# temporal_cache.yaml
backend: redis
redis_url: redis://localhost:6379
embedding_model: all-MiniLM-L6-v2
similarity_threshold: 0.85
llm_classifier:
  enabled: true
  model: gpt-4
  temperature: 0.0
ttl:
  static: null
  semi_static: 2592000
  evolving: 86400
  dynamic: 3600

Testing

Run the test suite:

# All tests
pytest

# With coverage
pytest --cov=temporal_cache --cov-report=html

# Verbose output
pytest -v

The test suite includes 16 tests covering:

  • Cache storage and retrieval
  • Semantic similarity matching
  • Staleness classification accuracy
  • TTL expiration behavior
  • Redis backend integration
  • LLM classifier revalidation
  • Edge cases and error handling

Contributing

Contributions are welcome! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run the tests (pytest)
  5. Submit a pull request

Development Setup

git clone https://github.com/yourusername/temporal-cache.git
cd temporal-cache
pip install -e ".[dev]"
pre-commit install

Code Style

  • Follow PEP 8
  • Use type hints
  • Write docstrings for public APIs
  • Add tests for new features

Roadmap

  • v0.2.0 - Async support (async/await)
  • v0.2.0 - PostgreSQL backend
  • v0.3.0 - Bloom filter pre-check for fast misses
  • v0.3.0 - Distributed cache invalidation
  • v0.4.0 - Embedding cache (reuse embeddings across queries)
  • v0.4.0 - Web dashboard for cache analytics
  • v1.0.0 - Production-ready release

License

MIT License. See LICENSE for details.


Built with care for the LLM community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

temporal_cache_llm-0.1.0.tar.gz (28.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

temporal_cache_llm-0.1.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file temporal_cache_llm-0.1.0.tar.gz.

File metadata

  • Download URL: temporal_cache_llm-0.1.0.tar.gz
  • Upload date:
  • Size: 28.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for temporal_cache_llm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0d20a969f9de520d8044c44e47f5863615ccf8032f09d102c3195a2f8382c96d
MD5 ad73745568f77acf43ac72faa681f85c
BLAKE2b-256 a362af6f162e362adc53a0a6c77f9d6f391d89af7dc9cbba2174b501c2b81a93

See more details on using hashes here.

File details

Details for the file temporal_cache_llm-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for temporal_cache_llm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 150d5bdf448c5875fe2e81693732c8154a702a1630e7b6c0d6cd1da7b5372b7e
MD5 b8acfc51961e065a32535086fdda3958
BLAKE2b-256 992e3cb201818157e6ba99039b4a783aecc8b40ba3fa025ac402509517a3493f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page