Prompt caching

Prompt caching makes a repeated prompt start cheaper. A multi-turn chat or an agent loop gets the saving with no setup.

Many prompts start the same way: a system prompt, tool definitions or a long document. A provider can store that start, called the prefix. A later request with the same prefix reads it from the cache, and the provider charges a fraction of the input rate for those tokens. The exchange makes a cache plan for each job and sends it to the winning provider.

To store a whole answer at the exchange and skip the provider, see Response caching.

What a cache costs

The first request that sends a prefix pays for a write. Each later request that reuses the prefix pays for a read. The lifetime of a write is its time-to-live (TTL). After the TTL ends, the next request writes again.

Example: input at USD 3.00 for each million tokens, a read at 0.1 times, a five-minute write at 1.25 times, and a 10,000-token prefix. The rates are an illustration.

Request Without a cache With a cache
1 (write) USD 0.0300 USD 0.0375
2 (read) USD 0.0300 USD 0.0030
3 (read) USD 0.0300 USD 0.0030
Total for three USD 0.0900 USD 0.0435

The write pays back at the first read. If no later request reads the prefix, the write is a loss, so auto does not cache a one-off request.

You pay the rates of the winning offer. The order book shows the cache-read and cache-write rates of each offer. A provider that quotes no cache-read rate gets no cache saving in the ranking.

Check what a job saved

Each response has an exchange block. Its charge object has three cache fields:

cache_usd and uncached_usd are present only when some input used a cache, and no money moves on them. A job that hit its price cap has no cache_usd. If uncached_usd is smaller than total_usd, a write was never read.

The price cap includes cache writes up to the last breakpoint. It does not include an assumed saving, and a write cannot charge more than the cap.

The usage block reports cached input separately from fresh input:

API Cache read Cache write
Chat Completions cached_tokens cache_write_tokens
Messages cache_read_input_tokens cache_creation_input_tokens

On Chat Completions both are inside prompt_tokens_details, and prompt_tokens counts them. On Messages, input_tokens excludes them: add the three for the total input.

The receipt of the job shows the cache tokens and the charge. If an offer quotes no write rate, the exchange bills written tokens as uncached input.

If the second request shows no read

Check these causes:

Choose how to cache

Set exchange.cache.mode in the request body to choose who places the breakpoints. A breakpoint is a point in the prompt. The provider caches everything before it.

Value Who places the breakpoints
auto (default) Your cache_control markers, or the exchange when you sent none.
buyer Only your own cache_control markers.
off No one. The exchange sends no breakpoints and no cache key.

Let the exchange cache (auto)

If the request declares tools or continues a conversation, the exchange places breakpoints after the tool definitions, after the system prompt, after the previous request, and after the last message. The next request reads the last one.

It places breakpoints only if the estimated prompt is 512 tokens or more, the smallest minimum of the Anthropic models. It does not cache a one-off request. Its breakpoints always use the five-minute TTL. Use your own markers to ask for one hour.

Place your own breakpoints (auto or buyer)

Add cache_control to the last block of the prefix to cache. Under auto, a request with any marker keeps your markers and gets none from the exchange. Under buyer, the exchange never places its own.

Marker TTL Meter
{"type": "ephemeral"} 5 minutes cache_write_short
{"type": "ephemeral", "ttl": "1h"} 1 hour cache_write_long

Any ttl other than "1h" is five minutes. Use the short write for requests within five minutes of each other, such as one agent loop. Use the long write when requests are further apart. A long write pays back only if the prefix is read after the short TTL would have ended.

Messages API (Anthropic format). Mark a block of system, a tool, or a block inside a turn:

import os
from anthropic import Anthropic

client = Anthropic(
    base_url="https://router.inference.ai.exchange",
    api_key=os.environ["LIQUID_API_KEY"],
)

response = client.messages.create(
    model="liquid.auto",
    max_tokens=1024,
    system=[
        {"type": "text", "text": "You are terse."},
        {
            "type": "text",
            "text": long_reference_document,
            "cache_control": {"type": "ephemeral", "ttl": "1h"},  # long write
        },
    ],
    messages=[{"role": "user", "content": "What changed in section 4?"}],
)
print(response.usage)

Chat Completions. Mark a content part or a tool. A marker needs the array form of content:

response = client.chat.completions.create(
    model="liquid.auto",
    messages=[
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": long_reference_document,
                    "cache_control": {"type": "ephemeral"},  # short write
                }
            ],
        },
        {"role": "user", "content": "What changed in section 4?"},
    ],
)

Rules for markers:

Switch off the cache (off)

off drops your own markers and the cache key. It cannot stop an upstream that caches long prompts itself.

response = client.chat.completions.create(
    model="liquid.auto",
    messages=[{"role": "user", "content": "hello"}],
    extra_body={"exchange": {"cache": {"mode": "off"}}},
)

Keep a conversation on one cache

Name the conversation

Send session_id in the request body, or the x-session-id header, with the same value on each turn. The body field wins. The value can have 256 characters at most.

The exchange picks the cache key in this order: session_id, prompt_cache_key, then a digest of the first block of the prompt. Some providers, such as OpenAI, route by this key. The exchange salts the key for each buyer, so it never joins the requests of two buyers. With exchange.cache.mode: "off", the exchange ignores session_id.

response = client.chat.completions.create(
    model="liquid.auto",
    messages=messages,
    extra_body={"session_id": "support-chat-4821"},
)

Which provider serves the next turn

A cache lives at one provider. The exchange remembers which provider served the last turn of a session, for as long as the longest cache that the turn wrote. Each new turn renews the record.

For that provider, the ranking estimate assumes a cache read for part of the prompt, but only if the provider publishes a cache-read rate.

When the cache saves anything, the exchange also ranks that provider 5% below its own estimate. So the provider that served the last turn wins unless another offer is cheaper by more than the cache saving plus that margin. The price cap does not include the assumed saving. Under Auto, a session can also stay on the previous deployment. See Auto Router.

A new conversation can also find a warm cache. The exchange remembers, for each buyer, which provider served each prefix, for the same time as a session. This works without a session_id, and the exchange can lose a record early.

Keep a session on one deployment

Set exchange.session.sticky: true in the exchange block or in a preset. The deployment that served the previous turn then ranks first while it is eligible: it passes your rules and its price cap fits the cap of the call. Otherwise the exchange ranks as usual. A fallback to the next offer happens only before any output.

response = client.chat.completions.create(
    model="liquid.auto",
    messages=messages,
    extra_body={"session_id": "support-chat-4821", "exchange": {"session": {"sticky": True}}},
)

exchange.session.sticky is not the Auto session pin of Auto versions 5 and 6. Set exchange.session.pin: "off" to turn the pin off, or exchange.session.margin to change the score points that a rival must add. See Session pin.

Privacy between buyers

Only you can read your cached prompts. The exchange puts a code that is unique to your account before your system prompt and messages in each cacheable prompt, so a shared upstream account never shares a prefix between buyers. One exception: some upstreams cache the tool definitions before the system prompt, so buyers can share the cache for an identical list of tools.

Reference

The meters

The exchange meters the input of a job in four parts and the output as a fifth. Each part has its own rate on the offer.

Meter What it counts Typical rate
uncached_input Input that the cache did not read or write. The input rate.
cache_read Input that the provider read from its cache. 0.1 to 0.5 times the input rate.
cache_write_short Input stored in the cache for five minutes. 1 to 1.25 times the input rate.
cache_write_long Input stored in the cache for one hour. About 2 times the input rate.
generation Output tokens. Caching has no effect. The output rate.

The public offers in Market data carry the rates in the cache_read, cache_write_short and cache_write_long lines of pricing. A line is absent when the offer quotes no such price.

What each upstream caches

The exchange sends the same cache plan to each provider, in the form that its upstream reads. The upstream decides what it caches and what it charges. The multipliers below are list prices of the upstream, and an offer can quote other rates. A prompt shorter than the minimum of the upstream is never cached and is billed as uncached input.

Anthropic

OpenAI

Other upstreams

Groq, Grok, Moonshot AI, DeepSeek, Z.AI, Google Gemini and others cache a repeated prefix by themselves. The exchange sends the same body as for OpenAI, and the upstream can ignore the key.

These rules are a guide. The usage block shows what the provider reported, and the receipt shows what you paid.

Next steps