The confusion most teams hit is that "caching" describes two different savings. Provider prefix caching, also called prompt caching or context caching, stores the key-value attention states the model already computed for a prompt prefix and reuses them when a later request begins with exactly the same token sequence. The model still runs, it still decodes output tokens, and you still pay for the completion, but the repeated prefix is billed at a reduced read rate and prefill is skipped. Modular's inference handbook describes this clearly: the model finds the longest cached token sequence matching from the beginning, loads those states, and runs prefill only for the remainder.
A local response cache is a different animal. You hash the full request (messages, model, parameters, and sometimes the API key), look it up in your own store, and if there is an exact match you return the stored response without calling the provider at all. OpenRouter's implementation makes the economics plain: a hit returns immediately with all billable usage counters reported as zero, and lookup averages about 4 milliseconds, while an uncached call to a comparable model can take seconds. The OpenRouter response caching docs and the announcement post both stress that response caching is separate from prompt caching: prompt caching discounts the prompt portion, response caching skips the provider entirely.
So the two layers save different things. Prefix caching saves input tokens and time-to-first-token. Response caching saves input tokens, output tokens, and the full round trip. That is why stacking them can make sense, and why stacking them can also be pure overhead.



