Skip to main content
LLMs are expensive. When users ask questions that are semantically equivalent — “What’s your return policy?” and “How do I return an item?” — there is no reason to run two separate model calls. SemanticCache stores responses keyed on embedding similarity rather than exact string matching, so a new prompt that is close enough to a cached one returns the stored answer instantly without touching the model.

How it works

When you call cache.get(prompt), SemanticCache embeds the prompt and queries the backing vector store for the nearest stored entry. If the top result’s cosine similarity exceeds the configured threshold (default 0.95) and the entry has not expired, it’s a cache hit and the stored response is returned. On a miss, your code calls the LLM as normal, then stores the response with cache.set() for future hits. The cache.wrap() convenience method handles the full get-or-produce flow in one call.

Setup

Constructor options

The default store is an in-process MemoryVectorStore. Use SqliteVectorStore or another persistent store to keep the cache across process restarts.

API

cache.get(prompt, opts?)

Looks up a prompt in the cache. Returns a CacheLookup object.
CacheLookup fields: The optional opts object accepts:

cache.set(prompt, value)

Stores a response string paired with the prompt’s embedding. Call this after a model response to prime future cache hits.

cache.wrap(prompt, produce, opts?)

The recommended entry point. Checks the cache, calls produce() on a miss, stores the new response, and returns a result object.
The return value has:

Integrating with an agent

Wrap the model call inside defineAgent with cache.wrap() to cache agent responses by their user query:

Tuning the threshold

The right threshold depends on how similar “equivalent” prompts need to be for your use case.
Using a HashEmbedder in production limits cache effectiveness because it tracks vocabulary overlap, not semantic meaning. Use a semantic provider embedder (OpenAI text-embedding-3-small, Gemini text-embedding-004) for accurate similarity scoring.

Observability

When you pass a trace handle to cache.get() or cache.wrap(), Anvil records a cache span that includes:
  • hit — whether the lookup was a cache hit
  • score — the cosine similarity of the nearest entry
  • threshold — the configured threshold
These spans appear in the Anvil dashboard timeline so you can track cache hit rates alongside latency and cost.